RubyConf India 2012Pune                      Crafting Beautiful               Command Line Applications                   ...
Shishir Das@shishirdasThoughtWorks
Nikhil Mungel@hyfatherThoughtWorks
Why the command line?
Why the command line?
eyheroku              knife                            puppet  pg_ctl    mysql      rails                               git
bash       zsh        powershell           eyheroku              knife                            puppet  pg_ctl    mysql ...
eyheroku                knife                              puppet  pg_ctl    mysql        rails                           ...
Lightweight
Lightweight
Scriptable
Consistent UX
Consistent UX    *
What makes a CLI app       good?
The Luxury of  Ignorance
~ > rails
~ > railsUsage: rails COMMAND [ARGS]The most common rails commands are: generate    Generate new code (short-cut alias: "g...
~ > rails generate
~ > rails generateUsage: rails generate GENERATOR [args] [options]Please choose a generator below.Rails:  assets  controll...
~ > ssh
~ > sshusage: ssh [-1246AaCfgKkMNnqsTtVvXxYy] [-b bind_address] [-ccipher_spec]           [-D [bind_address:]port] [-F con...
Least Astonishment
~ > bundle
~ > bundleFetching source index for https://rubygems.org/Using rake (0.9.2.2)Installing i18n (0.6.0)Installing multi_json ...
Reversibility
~ > git commit -am "Added a new framework"
~ > git commit -am "Added a new framework"[master b4a2130] Added a new framework  2 files changed, 1012 insertions(+), 529...
~ > git commit -am "Added a new framework"[master b4a2130] Added a new framework  2 files changed, 1012 insertions(+), 529...
~ > git commit -am "Added a new framework"[master b4a2130] Added a new framework  2 files changed, 1012 insertions(+), 529...
Config Files
~ > knife cookbook upload apache2 -o /User/foo/cookbooks --server-url http://chef-server:4000 --key /etc/chef/my.key --col...
~ > knife cookbook upload apache2 -o /User/foo/cookbooks --server-url http://chef-server:4000 --key /etc/chef/my.key --col...
~ > knife cookbook upload apache2 -o /User/foo/cookbooks --server-url http://chef-server:4000 --key /etc/chef/my.key --col...
Graceful Failure
~ > git pull
~ > git pullYou asked me to pull without telling me which branch youwant to merge with, and branch.master.merge inyour con...
No hidden states
Confirmations should   be scriptable
~ > gem uninstall rspec
~ > gem uninstall rspecYou have requested to uninstall the gem:	 rspec-2.8.0cucumber-1.1.4 depends on [rspec (>= 2.7.0)]If...
~ > gem uninstall rspecYou have requested to uninstall the gem:	 rspec-2.8.0cucumber-1.1.4 depends on [rspec (>= 2.7.0)]If...
~ > gem uninstall rspecYou have requested to uninstall the gem:	 rspec-2.8.0cucumber-1.1.4 depends on [rspec (>= 2.7.0)]If...
Honor Piping
IO#tty?
Why Ruby?
Scripting Language
Easy textmanipulation
Good Abstractions
Plethora of gems to     help you
Examples to learn      from
Structure of CLI      apps
Input   Execution   Output
Input   Execution   Output STDIO = UI/UX
Input
Input        STDIN
Input        ARGV/ENV          STDIN
Input        ARGV/ENV          STDIN
Input        ARGV/ENV          STDIN
Input        OptionParser        ARGV/ENV          STDIN
Input        OptionParser        ARGV/ENV          STDIN
Input   Libraries        OptionParser        ARGV/ENV          STDIN
options = {}OptionParser.new do |opts|  opts.banner = "Usage: example.rb [options]"  opts.on("-v", "--[no-]verbose", "Run ...
options = {}OptionParser.new do |opts|  opts.banner = "Usage: example.rb [options]"  opts.on("-v", "--[no-]verbose", "Run ...
options = {}OptionParser.new do |opts|  opts.banner = "Usage: example.rb [options]"  opts.on("-v", "--[no-]verbose", "Run ...
options = {}OptionParser.new do |opts|  opts.banner = "Usage: example.rb [options]"  opts.on("-v", "--[no-]verbose", "Run ...
options = {}OptionParser.new do |opts|  opts.banner = "Usage: example.rb [options]"  opts.on("-v", "--[no-]verbose", "Run ...
The Mixlib Suite
class MyCLIApp  include Mixlib::CLI  option :config_file,    :short => "-c CONFIG",    :description => "Configuration file...
class MyCLIApp  include Mixlib::CLI  option :config_file,    :short => "-c CONFIG",    :description => "Configuration file...
class MyCLIApp  include Mixlib::CLI  option :config_file,    :short => "-c CONFIG",    :description => "Configuration file...
config.rbserver_url “http://server.remote”username   “elvis”password   “hotdog”
config.rbserver_url “http://server.remote”username   “elvis”password   “hotdog”class MyConfig  extend(Mixlib::Config)  ser...
config.rbserver_url “http://server.remote”username   “elvis”password   “hotdog”class MyConfig  extend(Mixlib::Config)  ser...
Thor
class Test < Thor  desc " FILE", "an example task"  method_option :delete,                :aliases => "-d",               ...
class Test < Thor  desc " FILE", "an example task"  method_option :delete,                :aliases => "-d",               ...
class Test < Thor  desc " FILE", "an example task"  method_option :delete,                :aliases => "-d",               ...
class Test < Thor  desc " FILE", "an example task"  method_option :delete,                :aliases => "-d",               ...
class Test < Thor  desc " FILE", "an example task"  method_option :delete,                :aliases => "-d",               ...
class Test < Thor  desc " FILE", "an example task"  method_option :delete,                :aliases => "-d",               ...
class Test < Thor  desc " FILE", "an example task"  method_option :delete,                :aliases => "-d",               ...
class Test < Thor  desc " FILE", "an example task"  method_option :delete,                :aliases => "-d",               ...
Testing
Input   Execution   Output
Input   Execution   Output
Input   Execution   OutputMostly third party libraries
Input   Execution   OutputTest::Unit, rspec etc.
Input   Execution   Output         System
SystemFile System    Network   Process
Isolated       Environments                              ContainerUser               Application           File           ...
Streams & Signals
STDOUTSTDIN        App              STDERR
STDOUTSTDIN        App              STDERR
STDOUTSTDIN        App                STDERR                  STDOUT & STDERR        STDIN                 App
Mixlib::Shellout> ls = Mixlib::ShellOut.new("ls")> ls.run_command> ls.stdout“init.elnREADME.mdn”
Mixlib::Shellout> ls = Mixlib::ShellOut.new("ls")> ls.run_command> ls.stdout“init.elnREADME.mdn”
Plugin Architecture
Hooks
Logging
GNU CLI standards‘--version’ and ‘--help’Input/Output Files --  -O for Output Files
“CLI apps could bethe first consumers                 ” of your services.
“CLI apps could bethe first consumers                 ” of your services.
“CLI apps could bethe first consumers                               ” of your services.      Testing    Development      C...
Ideas    CLI app for a REST API: Github    SCM Plugins for Knife    Transform Rake scripts into first    class CLI appsShi...
Questions              Comments         SuggestionsShishir                      Nikhil@shishirdas               @hyfather
Crafting Beautiful CLI Applications in Ruby
Crafting Beautiful CLI Applications in Ruby
Crafting Beautiful CLI Applications in Ruby
Crafting Beautiful CLI Applications in Ruby
Crafting Beautiful CLI Applications in Ruby
Crafting Beautiful CLI Applications in Ruby
Crafting Beautiful CLI Applications in Ruby
Crafting Beautiful CLI Applications in Ruby
Crafting Beautiful CLI Applications in Ruby
Crafting Beautiful CLI Applications in Ruby
Crafting Beautiful CLI Applications in Ruby
Crafting Beautiful CLI Applications in Ruby
Crafting Beautiful CLI Applications in Ruby
Crafting Beautiful CLI Applications in Ruby
Upcoming SlideShare
Loading in...5
×

Crafting Beautiful CLI Applications in Ruby

9,653

Published on

Shishir Das (@shishirdas) and Nikhil Mungel (@hyfather) presented this at RubyConf India 2012.

Published in: Technology
0 Comments
20 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
9,653
On Slideshare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
0
Comments
0
Likes
20
Embeds 0
No embeds

No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • task oriented v/s feature oriented\n(ssh is feature / rails is tasks)\n\nOther Examples -- knife &amp; cucumber\nTODO: SSH\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • bundle is a bad example\n\nrails/git/knife are good examples\n\n
  • \n
  • \n
  • all commands should be reversible, those that are not should be called out.\n\nSometimes irreversibility is unavoidable &gt;&gt; rm -rf --no-preserve-root /\n\n
  • make an example for rails generate /destroy\n
  • make an example for rails generate /destroy\n
  • make an example for rails generate /destroy\n
  • make an example for rails generate /destroy\n
  • Assume defaults wherever you can.\nIn case of risky operations don&amp;#x2019;t assume anything.\n\nE. g. -- package managers assume latest version\n
  • \n
  • \n
  • \n
  • git add\n&gt; did you mean `git add .&amp;#x2019; ?\n
  • \n
  • \n
  • vi modes\nbehavior should not depend on hidden state\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • git is a very mature cli. no piping or redirection normally used. but it honors everything.\nwrite errors to stderr\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • knife, rails, gem, bundle\n
  • \n
  • Input - command line -&gt; Option Parsing\n\nOutput - status code, stdout, stderr\n
  • Input - command line -&gt; Option Parsing\n\nOutput - status code, stdout, stderr\n
  • Input - command line -&gt; Option Parsing\n\nOutput - status code, stdout, stderr\n
  • Input - command line -&gt; Option Parsing\n\nOutput - status code, stdout, stderr\n
  • Input - command line -&gt; Option Parsing\n\nOutput - status code, stdout, stderr\n
  • Input - command line -&gt; Option Parsing\n\nOutput - status code, stdout, stderr\n
  • Input - command line -&gt; Option Parsing\n\nOutput - status code, stdout, stderr\n
  • Input - command line -&gt; Option Parsing\n\nOutput - status code, stdout, stderr\n
  • Input - command line -&gt; Option Parsing\n\nOutput - status code, stdout, stderr\n
  • Input - command line -&gt; Option Parsing\n\nOutput - status code, stdout, stderr\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Enforces OO\nAutomatic rake style tasks\n
  • Enforces OO\nAutomatic rake style tasks\n
  • Enforces OO\nAutomatic rake style tasks\n
  • Convention -- \nfirst arg to the description becomes the input \nsecond arg is the banner\n
  • Convention -- \nfirst arg to the description becomes the input \nsecond arg is the banner\n
  • Convention -- \nfirst arg to the description becomes the input \nsecond arg is the banner\n
  • Option Parsing\nInbuilt support for help and banners\nSupports standard invocations of help on the shell\n
  • Option Parsing\nInbuilt support for help and banners\nSupports standard invocations of help on the shell\n
  • \n
  • \n
  • \n
  • \n
  • Input - mostly handled by the third party library.\nTesting that would be testing the gem. Not a good idea.\n\n
  • Input - mostly handled by the third party library.\nTesting that would be testing the gem. Not a good idea.\n\n
  • Standard Ruby classes. Libraries like test/unit, rspec.\nMocking and proxy layers for 3rd party services etc.\nLike any other app.\n\n
  • \n
  • Mocking\n&amp;#xA0; mocha works out well.&amp;#xA0;\n&amp;#xA0; For filesystem, MockFS lets you mock the entire file system.&amp;#xA0;\n\nTesting CLI apps that manipulate filesystem. Mocking is good. But if we mock every call to FileUtils, test becomes very tightly coupled. So even if behaviour doesn&apos;t change but the command changes the test breaks.\n&amp;#xA0;- one use FakeFS\n\n
  • Isolate environment of its own.\nIf its is cheap and scriptable to spin up the environment. Then we can have behaviour testing&amp;#xA0;\n&amp;#xA0; - powerful machines.\n&amp;#xA0; - strong virtualizations (inbuilt)\nvagrant, lxc, openvz\n
  • 2 distinct sections -- your and subprocesses\n\nbackticks and system ruby calls not versatile. Doesn&amp;#x2019;t give you full control over the Input/Output/Error stream\nMixLib::Shellout and POpen3 are better alternatives.\nRespect exit status 0 -for success, rest all failures while writing your CLI.\nYour CLI should write error to stderr and not stdout. ruby provides $stdout, $stdin, $stderr\n\n
  • \n
  • \n
  • \n
  • Compatible with windows.\nUses the select(2) system call. \nGives abstractions over umask, cwd etc.\n
  • Compatible with windows.\nUses the select(2) system call. \nGives abstractions over umask, cwd etc.\n
  • Drop in plugins eg. vagrant, knife\nPick up all .rb files from a predetermined location.\n\nYour CLI app can then be easily extended\nWhen writing an app, you don&amp;#x2019;t know all the possible use cases\n\n
  • Provide hooks where arbitrary code can be run on failure and success of steps.\nEnsure that you support all executable files and not only .rb files.\n\nCan be filename based (git) or configurable.\n
  • STDOUT could be the default. But should be configurable to a file. \n\nLog at correct level. Apply to all apps but worth mentioning.\n\nyou may want to support -v and -vv for falling back to :info or :debug and -q falls back fatal.\n
  • Give URL in sliduments\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Transcript of "Crafting Beautiful CLI Applications in Ruby"

    1. 1. RubyConf India 2012Pune Crafting Beautiful Command Line Applications using Ruby Shishir Nikhil @shishirdas @hyfather
    2. 2. Shishir Das@shishirdasThoughtWorks
    3. 3. Nikhil Mungel@hyfatherThoughtWorks
    4. 4. Why the command line?
    5. 5. Why the command line?
    6. 6. eyheroku knife puppet pg_ctl mysql rails git
    7. 7. bash zsh powershell eyheroku knife puppet pg_ctl mysql rails git
    8. 8. eyheroku knife puppet pg_ctl mysql rails git Developers and QAs
    9. 9. Lightweight
    10. 10. Lightweight
    11. 11. Scriptable
    12. 12. Consistent UX
    13. 13. Consistent UX *
    14. 14. What makes a CLI app good?
    15. 15. The Luxury of Ignorance
    16. 16. ~ > rails
    17. 17. ~ > railsUsage: rails COMMAND [ARGS]The most common rails commands are: generate Generate new code (short-cut alias: "g") console Start the Rails console (short-cut alias: "c") server Start the Rails server (short-cut alias: "s")~ >
    18. 18. ~ > rails generate
    19. 19. ~ > rails generateUsage: rails generate GENERATOR [args] [options]Please choose a generator below.Rails: assets controller generator helper integration_test mailer migration model observer performance_test plugin~ >
    20. 20. ~ > ssh
    21. 21. ~ > sshusage: ssh [-1246AaCfgKkMNnqsTtVvXxYy] [-b bind_address] [-ccipher_spec] [-D [bind_address:]port] [-F configfile] [-I pkcs11] [-i identity_file] [-L [bind_address:]port:host:hostport] [-l login_name] [-O ctl_cmd] [-o option] [-p port] [-R [bind_address:]port:host:hostport] [-S ctl_path] [-W host:port] [-w local_tun[:remote_tun]] [user@]hostname [command]~ >
    22. 22. Least Astonishment
    23. 23. ~ > bundle
    24. 24. ~ > bundleFetching source index for https://rubygems.org/Using rake (0.9.2.2)Installing i18n (0.6.0)Installing multi_json (1.0.4)Installing activesupport (3.2.1)Installing builder (3.0.0)Installing activemodel (3.2.1)Installing erubis (2.7.0)~ >
    25. 25. Reversibility
    26. 26. ~ > git commit -am "Added a new framework"
    27. 27. ~ > git commit -am "Added a new framework"[master b4a2130] Added a new framework 2 files changed, 1012 insertions(+), 529 deletions(-)~ >
    28. 28. ~ > git commit -am "Added a new framework"[master b4a2130] Added a new framework 2 files changed, 1012 insertions(+), 529 deletions(-)~ > git reset HEAD^
    29. 29. ~ > git commit -am "Added a new framework"[master b4a2130] Added a new framework 2 files changed, 1012 insertions(+), 529 deletions(-)~ > git reset HEAD^Unstaged changes after reset:M javascript/framework.jsM javascripts/support.js~ >
    30. 30. Config Files
    31. 31. ~ > knife cookbook upload apache2 -o /User/foo/cookbooks --server-url http://chef-server:4000 --key /etc/chef/my.key --color~ >
    32. 32. ~ > knife cookbook upload apache2 -o /User/foo/cookbooks --server-url http://chef-server:4000 --key /etc/chef/my.key --color~ >~ > cat knife.rb log_level                :infolog_location             STDOUTnode_name                blitzclient_key               /Users/shishir/.chef/blitz.pemvalidation_client_name   chef-validatorvalidation_key           /etc/chef/validation.pemchef_server_url          http://10.10.100.202:4000cache_type               BasicFilecache_options( :path => /Users/shishir/.chef/checksums )~ >
    33. 33. ~ > knife cookbook upload apache2 -o /User/foo/cookbooks --server-url http://chef-server:4000 --key /etc/chef/my.key --color~ >~ > cat knife.rb log_level                :infolog_location             STDOUTnode_name                blitzclient_key               /Users/shishir/.chef/blitz.pemvalidation_client_name   chef-validatorvalidation_key           /etc/chef/validation.pemchef_server_url          http://10.10.100.202:4000cache_type               BasicFilecache_options( :path => /Users/shishir/.chef/checksums )~ >~ > knife cookbook upload apache2
    34. 34. Graceful Failure
    35. 35. ~ > git pull
    36. 36. ~ > git pullYou asked me to pull without telling me which branch youwant to merge with, and branch.master.merge inyour configuration file does not tell me, either. Pleasespecify which branch you want to use on the command line andtry again (e.g. git pull <repository> <refspec>).See git-pull(1) for details.If you often merge with the same branch, you may want touse something like the following in your configuration file: [branch "master"] remote = <nickname> merge = <remote-ref> [remote "<nickname>"] url = <url> fetch = <refspec>See git-config(1) for details.
    37. 37. No hidden states
    38. 38. Confirmations should be scriptable
    39. 39. ~ > gem uninstall rspec
    40. 40. ~ > gem uninstall rspecYou have requested to uninstall the gem: rspec-2.8.0cucumber-1.1.4 depends on [rspec (>= 2.7.0)]If you remove this gems, one or more dependencies will not be met.Continue with Uninstall? [Yn] n
    41. 41. ~ > gem uninstall rspecYou have requested to uninstall the gem: rspec-2.8.0cucumber-1.1.4 depends on [rspec (>= 2.7.0)]If you remove this gems, one or more dependencies will not be met.Continue with Uninstall? [Yn] n~ > gem uninstall -I rspec
    42. 42. ~ > gem uninstall rspecYou have requested to uninstall the gem: rspec-2.8.0cucumber-1.1.4 depends on [rspec (>= 2.7.0)]If you remove this gems, one or more dependencies will not be met.Continue with Uninstall? [Yn] n~ > gem uninstall -I rspecSuccessfully uninstalled rspec-2.8.0
    43. 43. Honor Piping
    44. 44. IO#tty?
    45. 45. Why Ruby?
    46. 46. Scripting Language
    47. 47. Easy textmanipulation
    48. 48. Good Abstractions
    49. 49. Plethora of gems to help you
    50. 50. Examples to learn from
    51. 51. Structure of CLI apps
    52. 52. Input Execution Output
    53. 53. Input Execution Output STDIO = UI/UX
    54. 54. Input
    55. 55. Input STDIN
    56. 56. Input ARGV/ENV STDIN
    57. 57. Input ARGV/ENV STDIN
    58. 58. Input ARGV/ENV STDIN
    59. 59. Input OptionParser ARGV/ENV STDIN
    60. 60. Input OptionParser ARGV/ENV STDIN
    61. 61. Input Libraries OptionParser ARGV/ENV STDIN
    62. 62. options = {}OptionParser.new do |opts| opts.banner = "Usage: example.rb [options]" opts.on("-v", "--[no-]verbose", "Run verbosely") do |v| options[:verbose] = v endend.parse!
    63. 63. options = {}OptionParser.new do |opts| opts.banner = "Usage: example.rb [options]" opts.on("-v", "--[no-]verbose", "Run verbosely") do |v| options[:verbose] = v endend.parse!~ > ./opt.rb --helpUsage: example.rb [options]   -v, --[no-]verbose               Run verbosely
    64. 64. options = {}OptionParser.new do |opts| opts.banner = "Usage: example.rb [options]" opts.on("-v", "--[no-]verbose", "Run verbosely") do |v| options[:verbose] = v endend.parse!~ > ./opt.rb --helpUsage: example.rb [options]   -v, --[no-]verbose               Run verbosely
    65. 65. options = {}OptionParser.new do |opts| opts.banner = "Usage: example.rb [options]" opts.on("-v", "--[no-]verbose", "Run verbosely") do |v| options[:verbose] = v endend.parse!~ > ./opt.rb --helpUsage: example.rb [options]   -v, --[no-]verbose               Run verbosely
    66. 66. options = {}OptionParser.new do |opts| opts.banner = "Usage: example.rb [options]" opts.on("-v", "--[no-]verbose", "Run verbosely") do |v| options[:verbose] = v endend.parse!~ > ./opt.rb --helpUsage: example.rb [options]   -v, --[no-]verbose               Run verbosely
    67. 67. The Mixlib Suite
    68. 68. class MyCLIApp include Mixlib::CLI option :config_file, :short => "-c CONFIG", :description => "Configuration file", :required => trueend~ > ./mycliapp.rb --helpUsage: ./mix.rb (options) -c, --config CONFIG Configuration file (required) -h, --help Show this message
    69. 69. class MyCLIApp include Mixlib::CLI option :config_file, :short => "-c CONFIG", :description => "Configuration file", :required => trueend~ > ./mycliapp.rb --helpUsage: ./mix.rb (options) -c, --config CONFIG Configuration file (required) -h, --help Show this message
    70. 70. class MyCLIApp include Mixlib::CLI option :config_file, :short => "-c CONFIG", :description => "Configuration file", :required => trueend~ > ./mycliapp.rb --helpUsage: ./mix.rb (options) -c, --config CONFIG Configuration file (required) -h, --help Show this message
    71. 71. config.rbserver_url “http://server.remote”username “elvis”password “hotdog”
    72. 72. config.rbserver_url “http://server.remote”username “elvis”password “hotdog”class MyConfig extend(Mixlib::Config) server_url http://server.local username king password burgerendMyConfig.from_file(‘config.rb’)irb> MyConfig.server_url# ‘http://server.remote’
    73. 73. config.rbserver_url “http://server.remote”username “elvis”password “hotdog”class MyConfig extend(Mixlib::Config) server_url http://server.local username king password burgerendMyConfig.from_file(‘config.rb’)irb> MyConfig.server_url# ‘http://server.remote’
    74. 74. Thor
    75. 75. class Test < Thor desc " FILE", "an example task" method_option :delete, :aliases => "-d", :desc => "Delete the file" def example(file) endend
    76. 76. class Test < Thor desc " FILE", "an example task" method_option :delete, :aliases => "-d", :desc => "Delete the file" def example(file) endend~ > myapp help test:exampleUsage: thor test:example FILEOptions: -d, [--delete=DELETE] # Delete the file after parsing itan example task
    77. 77. class Test < Thor desc " FILE", "an example task" method_option :delete, :aliases => "-d", :desc => "Delete the file" def example(file) endend~ > myapp help test:exampleUsage: thor test:example FILEOptions: -d, [--delete=DELETE] # Delete the file after parsing itan example task
    78. 78. class Test < Thor desc " FILE", "an example task" method_option :delete, :aliases => "-d", :desc => "Delete the file" def example(file) endend~ > myapp help test:exampleUsage: thor test:example FILEOptions: -d, [--delete=DELETE] # Delete the file after parsing itan example task
    79. 79. class Test < Thor desc " FILE", "an example task" method_option :delete, :aliases => "-d", :desc => "Delete the file" def example(file) endend~ > myapp help test:exampleUsage: thor test:example FILEOptions: -d, [--delete=DELETE] # Delete the file after parsing itan example task
    80. 80. class Test < Thor desc " FILE", "an example task" method_option :delete, :aliases => "-d", :desc => "Delete the file" def example(file) endend~ > myapp help test:exampleUsage: thor test:example FILEOptions: -d, [--delete=DELETE] # Delete the file after parsing itan example task
    81. 81. class Test < Thor desc " FILE", "an example task" method_option :delete, :aliases => "-d", :desc => "Delete the file" def example(file) endend~ > myapp help test:exampleUsage: thor test:example FILEOptions: -d, [--delete=DELETE] # Delete the file after parsing itan example task
    82. 82. class Test < Thor desc " FILE", "an example task" method_option :delete, :aliases => "-d", :desc => "Delete the file" def example(file) endend~ > myapp help test:exampleUsage: thor test:example FILEOptions: -d, [--delete=DELETE] # Delete the file after parsing itan example task
    83. 83. Testing
    84. 84. Input Execution Output
    85. 85. Input Execution Output
    86. 86. Input Execution OutputMostly third party libraries
    87. 87. Input Execution OutputTest::Unit, rspec etc.
    88. 88. Input Execution Output System
    89. 89. SystemFile System Network Process
    90. 90. Isolated Environments ContainerUser Application File Memory Processes System
    91. 91. Streams & Signals
    92. 92. STDOUTSTDIN App STDERR
    93. 93. STDOUTSTDIN App STDERR
    94. 94. STDOUTSTDIN App STDERR STDOUT & STDERR STDIN App
    95. 95. Mixlib::Shellout> ls = Mixlib::ShellOut.new("ls")> ls.run_command> ls.stdout“init.elnREADME.mdn”
    96. 96. Mixlib::Shellout> ls = Mixlib::ShellOut.new("ls")> ls.run_command> ls.stdout“init.elnREADME.mdn”
    97. 97. Plugin Architecture
    98. 98. Hooks
    99. 99. Logging
    100. 100. GNU CLI standards‘--version’ and ‘--help’Input/Output Files -- -O for Output Files
    101. 101. “CLI apps could bethe first consumers ” of your services.
    102. 102. “CLI apps could bethe first consumers ” of your services.
    103. 103. “CLI apps could bethe first consumers ” of your services. Testing Development Cheap No rich UI, functional Fast tests
    104. 104. Ideas CLI app for a REST API: Github SCM Plugins for Knife Transform Rake scripts into first class CLI appsShishir Nikhil@shishirdas @hyfather
    105. 105. Questions Comments SuggestionsShishir Nikhil@shishirdas @hyfather

    ×