Introducing Command Line Applications with Ruby

3,491 views
3,400 views

Published on

Published in: Technology, Design
0 Comments
4 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
3,491
On SlideShare
0
From Embeds
0
Number of Embeds
1,665
Actions
Shares
0
Downloads
3
Comments
0
Likes
4
Embeds 0
No embeds

No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Input - command line -> Option Parsing\n\nOutput - status code, stdout, stderr\n
  • Input - command line -> Option Parsing\n\nOutput - status code, stdout, stderr\n
  • Input - command line -> Option Parsing\n\nOutput - status code, stdout, stderr\n
  • Input - command line -> Option Parsing\n\nOutput - status code, stdout, stderr\n
  • Input - command line -> Option Parsing\n\nOutput - status code, stdout, stderr\n
  • Input - command line -> Option Parsing\n\nOutput - status code, stdout, stderr\n
  • Input - command line -> Option Parsing\n\nOutput - status code, stdout, stderr\n
  • Input - command line -> Option Parsing\n\nOutput - status code, stdout, stderr\n
  • Input - command line -> Option Parsing\n\nOutput - status code, stdout, stderr\n
  • Input - command line -> Option Parsing\n\nOutput - status code, stdout, stderr\n
  • Input - command line -> 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  mocha works out well. \n  For filesystem, MockFS lets you mock the entire file system. \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't change but the command changes the test breaks.\n - one use FakeFS\n\n
  • Mocking\n  mocha works out well. \n  For filesystem, MockFS lets you mock the entire file system. \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't change but the command changes the test breaks.\n - 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 \n  - powerful machines.\n  - strong virtualizations (inbuilt)\nvagrant, lxc, openvz\n
  • Isolate environment of its own.\nIf its is cheap and scriptable to spin up the environment. Then we can have behaviour testing \n  - powerful machines.\n  - strong virtualizations (inbuilt)\nvagrant, lxc, openvz\n
  • Isolate environment of its own.\nIf its is cheap and scriptable to spin up the environment. Then we can have behaviour testing \n  - powerful machines.\n  - strong virtualizations (inbuilt)\nvagrant, lxc, openvz\n
  • Isolate environment of its own.\nIf its is cheap and scriptable to spin up the environment. Then we can have behaviour testing \n  - powerful machines.\n  - strong virtualizations (inbuilt)\nvagrant, lxc, openvz\n
  • Isolate environment of its own.\nIf its is cheap and scriptable to spin up the environment. Then we can have behaviour testing \n  - powerful machines.\n  - strong virtualizations (inbuilt)\nvagrant, lxc, openvz\n
  • 2 distinct sections -- your and subprocesses\n\nbackticks and system ruby calls not versatile. Doesn’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
  • backticks and system ruby calls not versatile. Doesn’t give you full control over the Input/Output/Error stream\nMixLib::Shellout and POpen3 are better alternatives.\n\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
  • backticks and system ruby calls not versatile. Doesn’t give you full control over the Input/Output/Error stream\nMixLib::Shellout and POpen3 are better alternatives.\n\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
  • 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
  • \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
  • \n
  • Introducing Command Line Applications with Ruby

    1. 1. Ruby on Rails In PracticeApartment List and ThoughtbotSan Francisco, September 2012 Getting started with Command Line Applications
    2. 2. Ruby on Rails In PracticeApartment List and ThoughtbotSan Francisco, September 2012 Getting started with Command Line Applications Nikhil Mungel @hyfather
    3. 3. Why CLI ?
    4. 4. CLI
    5. 5. ScriptableCLI Lightweight Consistent UX
    6. 6. Why Ruby?
    7. 7. • Textual Manipulation• OO & FP Abstractions• Plethora of CLI gems• Examples to learn from
    8. 8. The Structure
    9. 9. Input Execution Output
    10. 10. Input Execution Output STDIO = UI/UX
    11. 11. Input STDIN
    12. 12. Input ARGV/ENV STDIN
    13. 13. Input ARGV/ENV STDIN
    14. 14. Input ARGV/ENV STDIN
    15. 15. Input OptionParser ARGV/ENV STDIN
    16. 16. Input OptionParser ARGV/ENV STDIN
    17. 17. Input Libraries OptionParser ARGV/ENV STDIN
    18. 18. Input Libraries OptionParser ARGV/ENV STDIN
    19. 19. Input Libraries OptionParser ARGV/ENV STDIN
    20. 20. 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!
    21. 21. 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
    22. 22. 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
    23. 23. 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
    24. 24. 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
    25. 25. The Mixlib Suite
    26. 26. 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
    27. 27. 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
    28. 28. 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
    29. 29. config.rbserver_url “http://server.remote”username “elvis”password “hotdog”
    30. 30. 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’
    31. 31. 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’
    32. 32. Thor
    33. 33. class Test < Thor desc " FILE", "an example task" method_option :delete, :aliases => "-d", :desc => "Delete the file" def example(file) endend
    34. 34. 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
    35. 35. 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
    36. 36. 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
    37. 37. 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
    38. 38. 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
    39. 39. 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
    40. 40. 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
    41. 41. Testing!
    42. 42. Input Execution Output
    43. 43. Input Execution Output
    44. 44. Input Execution OutputMostly third party libraries
    45. 45. Input Execution OutputTest::Unit, rspec etc.
    46. 46. Input Execution Output System
    47. 47. System
    48. 48. SystemFile System Network Process
    49. 49. Isolated EnvironmentsFile System Network Process
    50. 50. Isolated EnvironmentsUser Container Application File System Network Process
    51. 51. Streams & Signals
    52. 52. STDO UT/S TDER R CLIUser App STDIN
    53. 53. STDO UT/S TDER R CLIUser App STDIN STDOUT & STDERR STDIN Another App
    54. 54. STDO UT/S TDER R CLIUser App STDIN STDOUT & STDERR STDIN Another App
    55. 55. Mixlib::Shellout> ls = Mixlib::ShellOut.new("ls")> ls.run_command> ls.stdout“init.elnREADME.mdn” Nikhil Mungel www.hyfather.com @hyfather
    56. 56. Mixlib::Shellout> ls = Mixlib::ShellOut.new("ls")> ls.run_command> ls.stdout“init.elnREADME.mdn” Nikhil Mungel www.hyfather.com @hyfather
    57. 57. Nikhil Mungelwww.hyfather.com @hyfather
    58. 58. IO#tty? Nikhil Mungelwww.hyfather.com @hyfather
    59. 59. Output$stdout TRACE DEBUG INFO$stderr WARN ERROR FATAL Nikhil Mungelwww.hyfather.com @hyfather
    60. 60. Thanks!I am currently a Grad Student at San Jose StateFormerly at ThoughtWorks Studios slidesha.re/rubycli Nikhil Mungel www.hyfather.com @hyfather

    ×