SlideShare a Scribd company logo
RubyConf India 2012
Pune




                      Crafting Beautiful
               Command Line Applications
                              using Ruby



  Shishir                          Nikhil
  @shishirdas                   @hyfather
Shishir Das


@shishirdas
ThoughtWorks
Nikhil Mungel


@hyfather
ThoughtWorks
Why the command line?
Why the command line?
ey
heroku              knife
                            puppet
  pg_ctl    mysql      rails
                               git
bash       zsh        powershell

           ey
heroku              knife
                            puppet
  pg_ctl    mysql      rails
                               git
ey
heroku                knife
                              puppet

  pg_ctl    mysql        rails
                                 git




         Developers
                and

                QAs
Lightweight
Lightweight
Scriptable
Consistent UX
Consistent UX

    *
What makes a CLI app
       good?
The Luxury of
  Ignorance
~ > rails
~ > rails
Usage: 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")
~ >
~ > rails generate
~ > rails generate
Usage: rails generate GENERATOR [args] [options]

Please choose a generator below.

Rails:
  assets
  controller
  generator
  helper
  integration_test
  mailer
  migration
  model
  observer
  performance_test
  plugin
~ >
~ > ssh
~ > ssh
usage: ssh [-1246AaCfgKkMNnqsTtVvXxYy] [-b bind_address] [-c
cipher_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]
~ >
Least Astonishment
~ > bundle
~ > bundle
Fetching 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)
~ >
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 deletions(-)
~ >
~ > git commit -am "Added a new framework"
[master b4a2130] Added a new framework
  2 files changed, 1012 insertions(+), 529 deletions(-)
~ > git reset HEAD^
~ > 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.js
M	 javascripts/support.js
~ >
Config Files
~ > knife cookbook upload apache2 -o /User/foo/cookbooks --
server-url http://chef-server:4000 --key /etc/chef/my.key --color
~ >
~ > 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                :info
log_location             STDOUT
node_name                'blitz'
client_key               '/Users/shishir/.chef/blitz.pem'
validation_client_name   'chef-validator'
validation_key           '/etc/chef/validation.pem'
chef_server_url          'http://10.10.100.202:4000'
cache_type               'BasicFile'
cache_options( :path => '/Users/shishir/.chef/checksums' )
~ >
~ > 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                :info
log_location             STDOUT
node_name                'blitz'
client_key               '/Users/shishir/.chef/blitz.pem'
validation_client_name   'chef-validator'
validation_key           '/etc/chef/validation.pem'
chef_server_url          'http://10.10.100.202:4000'
cache_type               'BasicFile'
cache_options( :path => '/Users/shishir/.chef/checksums' )
~ >
~ > knife cookbook upload apache2
Graceful Failure
~ > git pull
~ > git pull
You asked me to pull without telling me which branch you
want to merge with, and 'branch.master.merge' in
your configuration file does not tell me, either. Please
specify which branch you want to use on the command line and
try again (e.g. 'git pull <repository> <refspec>').
See git-pull(1) for details.

If you often merge with the same branch, you may want to
use 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.
No hidden states
Confirmations should
   be scriptable
~ > gem uninstall rspec
~ > gem uninstall rspec

You have requested to uninstall the gem:
	 rspec-2.8.0
cucumber-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 rspec

You have requested to uninstall the gem:
	 rspec-2.8.0
cucumber-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
~ > gem uninstall rspec

You have requested to uninstall the gem:
	 rspec-2.8.0
cucumber-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
Successfully uninstalled rspec-2.8.0
Honor Piping
IO#tty?
Why Ruby?
Scripting Language
Easy text
manipulation
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 verbosely") do |v|
    options[:verbose] = v
  end
end.parse!
options = {}
OptionParser.new do |opts|
  opts.banner = "Usage: example.rb [options]"

  opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
    options[:verbose] = v
  end
end.parse!




~ > ./opt.rb --help
Usage: example.rb [options]
   -v, --[no-]verbose               Run verbosely
options = {}
OptionParser.new do |opts|
  opts.banner = "Usage: example.rb [options]"

  opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
    options[:verbose] = v
  end
end.parse!




~ > ./opt.rb --help
Usage: example.rb [options]
   -v, --[no-]verbose               Run verbosely
options = {}
OptionParser.new do |opts|
  opts.banner = "Usage: example.rb [options]"

  opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
    options[:verbose] = v
  end
end.parse!




~ > ./opt.rb --help
Usage: example.rb [options]
   -v, --[no-]verbose               Run verbosely
options = {}
OptionParser.new do |opts|
  opts.banner = "Usage: example.rb [options]"

  opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
    options[:verbose] = v
  end
end.parse!




~ > ./opt.rb --help
Usage: example.rb [options]
   -v, --[no-]verbose               Run verbosely
The Mixlib Suite
class MyCLIApp
  include Mixlib::CLI

  option :config_file,
    :short => "-c CONFIG",
    :description => "Configuration file",
    :required => true
end




~ > ./mycliapp.rb --help
Usage: ./mix.rb (options)
    -c, --config CONFIG      Configuration file (required)
    -h, --help               Show this message
class MyCLIApp
  include Mixlib::CLI

  option :config_file,
    :short => "-c CONFIG",
    :description => "Configuration file",
    :required => true
end




~ > ./mycliapp.rb --help
Usage: ./mix.rb (options)
    -c, --config CONFIG      Configuration file (required)
    -h, --help               Show this message
class MyCLIApp
  include Mixlib::CLI

  option :config_file,
    :short => "-c CONFIG",
    :description => "Configuration file",
    :required => true
end




~ > ./mycliapp.rb --help
Usage: ./mix.rb (options)
    -c, --config CONFIG      Configuration file (required)
    -h, --help               Show this message
config.rb
server_url “http://server.remote”
username   “elvis”
password   “hotdog”
config.rb
server_url “http://server.remote”
username   “elvis”
password   “hotdog”



class MyConfig
  extend(Mixlib::Config)

  server_url 'http://server.local'
  username   'king'
  password   'burger'
end
MyConfig.from_file(‘config.rb’)



irb> MyConfig.server_url
# ‘http://server.remote’
config.rb
server_url “http://server.remote”
username   “elvis”
password   “hotdog”



class MyConfig
  extend(Mixlib::Config)

  server_url 'http://server.local'
  username   'king'
  password   'burger'
end
MyConfig.from_file(‘config.rb’)



irb> MyConfig.server_url
# ‘http://server.remote’
Thor
class Test < Thor
  desc " FILE", "an example task"
  method_option :delete,
                :aliases => "-d",
                :desc => "Delete the file"
  def example(file)
  end
end
class Test < Thor
  desc " FILE", "an example task"
  method_option :delete,
                :aliases => "-d",
                :desc => "Delete the file"
  def example(file)
  end
end




~ > myapp help test:example
Usage:
  thor test:example FILE

Options:
  -d, [--delete=DELETE]   # Delete the file after parsing it

an example task
class Test < Thor
  desc " FILE", "an example task"
  method_option :delete,
                :aliases => "-d",
                :desc => "Delete the file"
  def example(file)
  end
end




~ > myapp help test:example
Usage:
  thor test:example FILE

Options:
  -d, [--delete=DELETE]   # Delete the file after parsing it

an example task
class Test < Thor
  desc " FILE", "an example task"
  method_option :delete,
                :aliases => "-d",
                :desc => "Delete the file"
  def example(file)
  end
end




~ > myapp help test:example
Usage:
  thor test:example FILE

Options:
  -d, [--delete=DELETE]   # Delete the file after parsing it

an example task
class Test < Thor
  desc " FILE", "an example task"
  method_option :delete,
                :aliases => "-d",
                :desc => "Delete the file"
  def example(file)
  end
end




~ > myapp help test:example
Usage:
  thor test:example FILE

Options:
  -d, [--delete=DELETE]   # Delete the file after parsing it

an example task
class Test < Thor
  desc " FILE", "an example task"
  method_option :delete,
                :aliases => "-d",
                :desc => "Delete the file"
  def example(file)
  end
end




~ > myapp help test:example
Usage:
  thor test:example FILE

Options:
  -d, [--delete=DELETE]   # Delete the file after parsing it

an example task
class Test < Thor
  desc " FILE", "an example task"
  method_option :delete,
                :aliases => "-d",
                :desc => "Delete the file"
  def example(file)
  end
end




~ > myapp help test:example
Usage:
  thor test:example FILE

Options:
  -d, [--delete=DELETE]   # Delete the file after parsing it

an example task
class Test < Thor
  desc " FILE", "an example task"
  method_option :delete,
                :aliases => "-d",
                :desc => "Delete the file"
  def example(file)
  end
end




~ > myapp help test:example
Usage:
  thor test:example FILE

Options:
  -d, [--delete=DELETE]   # Delete the file after parsing it

an example task
Testing
Input   Execution   Output
Input   Execution   Output
Input   Execution   Output




Mostly third party libraries
Input   Execution   Output




Test::Unit, rspec etc.
Input   Execution   Output

         System
System


File System    Network   Process
Isolated
       Environments
                              Container


User               Application




           File
                     Memory      Processes
          System
Streams & Signals
STDOUT
STDIN
        App
              STDERR
STDOUT
STDIN
        App
              STDERR
STDOUT
STDIN
        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 be
the first consumers



                 ”
 of your services.
“CLI apps could be
the first consumers



                 ”
 of your services.
“CLI apps could be
the first consumers



                               ”
 of your services.

      Testing    Development


      Cheap
                 No rich UI,
    functional
                    Fast
      tests
Ideas

    CLI app for a REST API: Github

    SCM Plugins for Knife

    Transform Rake scripts into first
    class CLI apps




Shishir                           Nikhil
@shishirdas                    @hyfather
Questions
              Comments
         Suggestions


Shishir                      Nikhil
@shishirdas               @hyfather

More Related Content

What's hot

Running Ruby on Solaris (RubyKaigi 2015, 12/Dec/2015)
Running Ruby on Solaris (RubyKaigi 2015, 12/Dec/2015)Running Ruby on Solaris (RubyKaigi 2015, 12/Dec/2015)
Running Ruby on Solaris (RubyKaigi 2015, 12/Dec/2015)
ngotogenome
 
Puppet Continuous Integration with PE and GitLab
Puppet Continuous Integration with PE and GitLabPuppet Continuous Integration with PE and GitLab
Puppet Continuous Integration with PE and GitLab
Alessandro Franceschi
 
What you need to remember when you upload to CPAN
What you need to remember when you upload to CPANWhat you need to remember when you upload to CPAN
What you need to remember when you upload to CPAN
charsbar
 
Rest, sockets em golang
Rest, sockets em golangRest, sockets em golang
Rest, sockets em golang
jefferson Otoni Lima
 
Composer - Package Management for PHP. Silver Bullet?
Composer - Package Management for PHP. Silver Bullet?Composer - Package Management for PHP. Silver Bullet?
Composer - Package Management for PHP. Silver Bullet?
Kirill Chebunin
 
Laravel 4 package development
Laravel 4 package developmentLaravel 4 package development
Laravel 4 package development
Tihomir Opačić
 
用 Go 語言打造多台機器 Scale 架構
用 Go 語言打造多台機器 Scale 架構用 Go 語言打造多台機器 Scale 架構
用 Go 語言打造多台機器 Scale 架構
Bo-Yi Wu
 
ZFConf 2012: Dependency Management в PHP и Zend Framework 2 (Кирилл Чебунин)
ZFConf 2012: Dependency Management в PHP и Zend Framework 2 (Кирилл Чебунин)ZFConf 2012: Dependency Management в PHP и Zend Framework 2 (Кирилл Чебунин)
ZFConf 2012: Dependency Management в PHP и Zend Framework 2 (Кирилл Чебунин)
ZFConf Conference
 
Drone CI/CD Platform
Drone CI/CD PlatformDrone CI/CD Platform
Drone CI/CD Platform
Bo-Yi Wu
 
Vagrant move over, here is Docker
Vagrant move over, here is DockerVagrant move over, here is Docker
Vagrant move over, here is Docker
Nick Belhomme
 
Asynchronous Systems with Fn Flow
Asynchronous Systems with Fn FlowAsynchronous Systems with Fn Flow
Asynchronous Systems with Fn Flow
José Paumard
 
Git introduction
Git introductionGit introduction
Git introduction
Kornel Lugosi
 
Construire son JDK en 10 étapes
Construire son JDK en 10 étapesConstruire son JDK en 10 étapes
Construire son JDK en 10 étapes
José Paumard
 
Orchestrated Functional Testing with Puppet-spec and Mspectator - PuppetConf ...
Orchestrated Functional Testing with Puppet-spec and Mspectator - PuppetConf ...Orchestrated Functional Testing with Puppet-spec and Mspectator - PuppetConf ...
Orchestrated Functional Testing with Puppet-spec and Mspectator - PuppetConf ...
Puppet
 
Shared Object images in Docker: What you need is what you want.
Shared Object images in Docker: What you need is what you want.Shared Object images in Docker: What you need is what you want.
Shared Object images in Docker: What you need is what you want.
Workhorse Computing
 
Test Driven Development with Puppet - PuppetConf 2014
Test Driven Development with Puppet - PuppetConf 2014Test Driven Development with Puppet - PuppetConf 2014
Test Driven Development with Puppet - PuppetConf 2014
Puppet
 
Drone 1.0 Feature
Drone 1.0 FeatureDrone 1.0 Feature
Drone 1.0 Feature
Bo-Yi Wu
 
Composer: putting dependencies on the score
Composer: putting dependencies on the scoreComposer: putting dependencies on the score
Composer: putting dependencies on the score
Rafael Dohms
 
Getting Started With Aura
Getting Started With AuraGetting Started With Aura
Getting Started With Aura
Chris Tankersley
 
Test driven infrastructure
Test driven infrastructureTest driven infrastructure
Test driven infrastructure
XPeppers
 

What's hot (20)

Running Ruby on Solaris (RubyKaigi 2015, 12/Dec/2015)
Running Ruby on Solaris (RubyKaigi 2015, 12/Dec/2015)Running Ruby on Solaris (RubyKaigi 2015, 12/Dec/2015)
Running Ruby on Solaris (RubyKaigi 2015, 12/Dec/2015)
 
Puppet Continuous Integration with PE and GitLab
Puppet Continuous Integration with PE and GitLabPuppet Continuous Integration with PE and GitLab
Puppet Continuous Integration with PE and GitLab
 
What you need to remember when you upload to CPAN
What you need to remember when you upload to CPANWhat you need to remember when you upload to CPAN
What you need to remember when you upload to CPAN
 
Rest, sockets em golang
Rest, sockets em golangRest, sockets em golang
Rest, sockets em golang
 
Composer - Package Management for PHP. Silver Bullet?
Composer - Package Management for PHP. Silver Bullet?Composer - Package Management for PHP. Silver Bullet?
Composer - Package Management for PHP. Silver Bullet?
 
Laravel 4 package development
Laravel 4 package developmentLaravel 4 package development
Laravel 4 package development
 
用 Go 語言打造多台機器 Scale 架構
用 Go 語言打造多台機器 Scale 架構用 Go 語言打造多台機器 Scale 架構
用 Go 語言打造多台機器 Scale 架構
 
ZFConf 2012: Dependency Management в PHP и Zend Framework 2 (Кирилл Чебунин)
ZFConf 2012: Dependency Management в PHP и Zend Framework 2 (Кирилл Чебунин)ZFConf 2012: Dependency Management в PHP и Zend Framework 2 (Кирилл Чебунин)
ZFConf 2012: Dependency Management в PHP и Zend Framework 2 (Кирилл Чебунин)
 
Drone CI/CD Platform
Drone CI/CD PlatformDrone CI/CD Platform
Drone CI/CD Platform
 
Vagrant move over, here is Docker
Vagrant move over, here is DockerVagrant move over, here is Docker
Vagrant move over, here is Docker
 
Asynchronous Systems with Fn Flow
Asynchronous Systems with Fn FlowAsynchronous Systems with Fn Flow
Asynchronous Systems with Fn Flow
 
Git introduction
Git introductionGit introduction
Git introduction
 
Construire son JDK en 10 étapes
Construire son JDK en 10 étapesConstruire son JDK en 10 étapes
Construire son JDK en 10 étapes
 
Orchestrated Functional Testing with Puppet-spec and Mspectator - PuppetConf ...
Orchestrated Functional Testing with Puppet-spec and Mspectator - PuppetConf ...Orchestrated Functional Testing with Puppet-spec and Mspectator - PuppetConf ...
Orchestrated Functional Testing with Puppet-spec and Mspectator - PuppetConf ...
 
Shared Object images in Docker: What you need is what you want.
Shared Object images in Docker: What you need is what you want.Shared Object images in Docker: What you need is what you want.
Shared Object images in Docker: What you need is what you want.
 
Test Driven Development with Puppet - PuppetConf 2014
Test Driven Development with Puppet - PuppetConf 2014Test Driven Development with Puppet - PuppetConf 2014
Test Driven Development with Puppet - PuppetConf 2014
 
Drone 1.0 Feature
Drone 1.0 FeatureDrone 1.0 Feature
Drone 1.0 Feature
 
Composer: putting dependencies on the score
Composer: putting dependencies on the scoreComposer: putting dependencies on the score
Composer: putting dependencies on the score
 
Getting Started With Aura
Getting Started With AuraGetting Started With Aura
Getting Started With Aura
 
Test driven infrastructure
Test driven infrastructureTest driven infrastructure
Test driven infrastructure
 

Similar to Crafting Beautiful CLI Applications in Ruby

Toolbox of a Ruby Team
Toolbox of a Ruby TeamToolbox of a Ruby Team
Toolbox of a Ruby Team
Arto Artnik
 
Generators
GeneratorsGenerators
Generators
Allan Davis
 
Intro django
Intro djangoIntro django
Intro django
Alexander Lyabah
 
Rails Engine | Modular application
Rails Engine | Modular applicationRails Engine | Modular application
Rails Engine | Modular application
mirrec
 
How I Learned to Stop Worrying and Love the Cloud - Wesley Beary, Engine Yard
How I Learned to Stop Worrying and Love the Cloud - Wesley Beary, Engine YardHow I Learned to Stop Worrying and Love the Cloud - Wesley Beary, Engine Yard
How I Learned to Stop Worrying and Love the Cloud - Wesley Beary, Engine Yard
SV Ruby on Rails Meetup
 
Chef 0.10 Overview
Chef 0.10 OverviewChef 0.10 Overview
Chef 0.10 Overview
Matt Ray
 
Cooking with Chef
Cooking with ChefCooking with Chef
Cooking with Chef
Ken Robertson
 
Migrating Legacy Rails Apps to Rails 3
Migrating Legacy Rails Apps to Rails 3Migrating Legacy Rails Apps to Rails 3
Migrating Legacy Rails Apps to Rails 3
Clinton Dreisbach
 
TIAD 2016 : Migrating 100% of your production services to containers
TIAD 2016 : Migrating 100% of your production services to containersTIAD 2016 : Migrating 100% of your production services to containers
TIAD 2016 : Migrating 100% of your production services to containers
The Incredible Automation Day
 
SaltConf14 - Ben Cane - Using SaltStack in High Availability Environments
SaltConf14 - Ben Cane - Using SaltStack in High Availability EnvironmentsSaltConf14 - Ben Cane - Using SaltStack in High Availability Environments
SaltConf14 - Ben Cane - Using SaltStack in High Availability Environments
SaltStack
 
Practical Chef and Capistrano for Your Rails App
Practical Chef and Capistrano for Your Rails AppPractical Chef and Capistrano for Your Rails App
Practical Chef and Capistrano for Your Rails App
SmartLogic
 
Railsconf2011 deployment tips_for_slideshare
Railsconf2011 deployment tips_for_slideshareRailsconf2011 deployment tips_for_slideshare
Railsconf2011 deployment tips_for_slideshare
tomcopeland
 
Deploying Symfony | symfony.cat
Deploying Symfony | symfony.catDeploying Symfony | symfony.cat
Deploying Symfony | symfony.cat
Pablo Godel
 
Go Web Development
Go Web DevelopmentGo Web Development
Go Web Development
Cheng-Yi Yu
 
Mojolicious - A new hope
Mojolicious - A new hopeMojolicious - A new hope
Mojolicious - A new hope
Marcus Ramberg
 
DevOps(4) : Ansible(2) - (MOSG)
DevOps(4) : Ansible(2) - (MOSG)DevOps(4) : Ansible(2) - (MOSG)
DevOps(4) : Ansible(2) - (MOSG)
Soshi Nemoto
 
fog or: How I Learned to Stop Worrying and Love the Cloud
fog or: How I Learned to Stop Worrying and Love the Cloudfog or: How I Learned to Stop Worrying and Love the Cloud
fog or: How I Learned to Stop Worrying and Love the Cloud
Wesley Beary
 
May The Nodejs Be With You
May The Nodejs Be With YouMay The Nodejs Be With You
May The Nodejs Be With You
Dalibor Gogic
 
Web2py Code Lab
Web2py Code LabWeb2py Code Lab
Web2py Code Lab
Colin Su
 
Catalyst MVC
Catalyst MVCCatalyst MVC
Catalyst MVC
Sheeju Alex
 

Similar to Crafting Beautiful CLI Applications in Ruby (20)

Toolbox of a Ruby Team
Toolbox of a Ruby TeamToolbox of a Ruby Team
Toolbox of a Ruby Team
 
Generators
GeneratorsGenerators
Generators
 
Intro django
Intro djangoIntro django
Intro django
 
Rails Engine | Modular application
Rails Engine | Modular applicationRails Engine | Modular application
Rails Engine | Modular application
 
How I Learned to Stop Worrying and Love the Cloud - Wesley Beary, Engine Yard
How I Learned to Stop Worrying and Love the Cloud - Wesley Beary, Engine YardHow I Learned to Stop Worrying and Love the Cloud - Wesley Beary, Engine Yard
How I Learned to Stop Worrying and Love the Cloud - Wesley Beary, Engine Yard
 
Chef 0.10 Overview
Chef 0.10 OverviewChef 0.10 Overview
Chef 0.10 Overview
 
Cooking with Chef
Cooking with ChefCooking with Chef
Cooking with Chef
 
Migrating Legacy Rails Apps to Rails 3
Migrating Legacy Rails Apps to Rails 3Migrating Legacy Rails Apps to Rails 3
Migrating Legacy Rails Apps to Rails 3
 
TIAD 2016 : Migrating 100% of your production services to containers
TIAD 2016 : Migrating 100% of your production services to containersTIAD 2016 : Migrating 100% of your production services to containers
TIAD 2016 : Migrating 100% of your production services to containers
 
SaltConf14 - Ben Cane - Using SaltStack in High Availability Environments
SaltConf14 - Ben Cane - Using SaltStack in High Availability EnvironmentsSaltConf14 - Ben Cane - Using SaltStack in High Availability Environments
SaltConf14 - Ben Cane - Using SaltStack in High Availability Environments
 
Practical Chef and Capistrano for Your Rails App
Practical Chef and Capistrano for Your Rails AppPractical Chef and Capistrano for Your Rails App
Practical Chef and Capistrano for Your Rails App
 
Railsconf2011 deployment tips_for_slideshare
Railsconf2011 deployment tips_for_slideshareRailsconf2011 deployment tips_for_slideshare
Railsconf2011 deployment tips_for_slideshare
 
Deploying Symfony | symfony.cat
Deploying Symfony | symfony.catDeploying Symfony | symfony.cat
Deploying Symfony | symfony.cat
 
Go Web Development
Go Web DevelopmentGo Web Development
Go Web Development
 
Mojolicious - A new hope
Mojolicious - A new hopeMojolicious - A new hope
Mojolicious - A new hope
 
DevOps(4) : Ansible(2) - (MOSG)
DevOps(4) : Ansible(2) - (MOSG)DevOps(4) : Ansible(2) - (MOSG)
DevOps(4) : Ansible(2) - (MOSG)
 
fog or: How I Learned to Stop Worrying and Love the Cloud
fog or: How I Learned to Stop Worrying and Love the Cloudfog or: How I Learned to Stop Worrying and Love the Cloud
fog or: How I Learned to Stop Worrying and Love the Cloud
 
May The Nodejs Be With You
May The Nodejs Be With YouMay The Nodejs Be With You
May The Nodejs Be With You
 
Web2py Code Lab
Web2py Code LabWeb2py Code Lab
Web2py Code Lab
 
Catalyst MVC
Catalyst MVCCatalyst MVC
Catalyst MVC
 

Recently uploaded

Cosa hanno in comune un mattoncino Lego e la backdoor XZ?
Cosa hanno in comune un mattoncino Lego e la backdoor XZ?Cosa hanno in comune un mattoncino Lego e la backdoor XZ?
Cosa hanno in comune un mattoncino Lego e la backdoor XZ?
Speck&Tech
 
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdfUnlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Malak Abu Hammad
 
Generating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and MilvusGenerating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and Milvus
Zilliz
 
Mariano G Tinti - Decoding SpaceX
Mariano G Tinti - Decoding SpaceXMariano G Tinti - Decoding SpaceX
Mariano G Tinti - Decoding SpaceX
Mariano Tinti
 
“Building and Scaling AI Applications with the Nx AI Manager,” a Presentation...
“Building and Scaling AI Applications with the Nx AI Manager,” a Presentation...“Building and Scaling AI Applications with the Nx AI Manager,” a Presentation...
“Building and Scaling AI Applications with the Nx AI Manager,” a Presentation...
Edge AI and Vision Alliance
 
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
名前 です男
 
UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6
DianaGray10
 
Let's Integrate MuleSoft RPA, COMPOSER, APM with AWS IDP along with Slack
Let's Integrate MuleSoft RPA, COMPOSER, APM with AWS IDP along with SlackLet's Integrate MuleSoft RPA, COMPOSER, APM with AWS IDP along with Slack
Let's Integrate MuleSoft RPA, COMPOSER, APM with AWS IDP along with Slack
shyamraj55
 
Programming Foundation Models with DSPy - Meetup Slides
Programming Foundation Models with DSPy - Meetup SlidesProgramming Foundation Models with DSPy - Meetup Slides
Programming Foundation Models with DSPy - Meetup Slides
Zilliz
 
National Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practicesNational Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practices
Quotidiano Piemontese
 
Presentation of the OECD Artificial Intelligence Review of Germany
Presentation of the OECD Artificial Intelligence Review of GermanyPresentation of the OECD Artificial Intelligence Review of Germany
Presentation of the OECD Artificial Intelligence Review of Germany
innovationoecd
 
Mind map of terminologies used in context of Generative AI
Mind map of terminologies used in context of Generative AIMind map of terminologies used in context of Generative AI
Mind map of terminologies used in context of Generative AI
Kumud Singh
 
Uni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdfUni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems S.M.S.A.
 
Fueling AI with Great Data with Airbyte Webinar
Fueling AI with Great Data with Airbyte WebinarFueling AI with Great Data with Airbyte Webinar
Fueling AI with Great Data with Airbyte Webinar
Zilliz
 
20240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 202420240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 2024
Matthew Sinclair
 
Ocean lotus Threat actors project by John Sitima 2024 (1).pptx
Ocean lotus Threat actors project by John Sitima 2024 (1).pptxOcean lotus Threat actors project by John Sitima 2024 (1).pptx
Ocean lotus Threat actors project by John Sitima 2024 (1).pptx
SitimaJohn
 
How to use Firebase Data Connect For Flutter
How to use Firebase Data Connect For FlutterHow to use Firebase Data Connect For Flutter
How to use Firebase Data Connect For Flutter
Daiki Mogmet Ito
 
Removing Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software FuzzingRemoving Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software Fuzzing
Aftab Hussain
 
20240605 QFM017 Machine Intelligence Reading List May 2024
20240605 QFM017 Machine Intelligence Reading List May 202420240605 QFM017 Machine Intelligence Reading List May 2024
20240605 QFM017 Machine Intelligence Reading List May 2024
Matthew Sinclair
 
Columbus Data & Analytics Wednesdays - June 2024
Columbus Data & Analytics Wednesdays - June 2024Columbus Data & Analytics Wednesdays - June 2024
Columbus Data & Analytics Wednesdays - June 2024
Jason Packer
 

Recently uploaded (20)

Cosa hanno in comune un mattoncino Lego e la backdoor XZ?
Cosa hanno in comune un mattoncino Lego e la backdoor XZ?Cosa hanno in comune un mattoncino Lego e la backdoor XZ?
Cosa hanno in comune un mattoncino Lego e la backdoor XZ?
 
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdfUnlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
 
Generating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and MilvusGenerating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and Milvus
 
Mariano G Tinti - Decoding SpaceX
Mariano G Tinti - Decoding SpaceXMariano G Tinti - Decoding SpaceX
Mariano G Tinti - Decoding SpaceX
 
“Building and Scaling AI Applications with the Nx AI Manager,” a Presentation...
“Building and Scaling AI Applications with the Nx AI Manager,” a Presentation...“Building and Scaling AI Applications with the Nx AI Manager,” a Presentation...
“Building and Scaling AI Applications with the Nx AI Manager,” a Presentation...
 
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
 
UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6
 
Let's Integrate MuleSoft RPA, COMPOSER, APM with AWS IDP along with Slack
Let's Integrate MuleSoft RPA, COMPOSER, APM with AWS IDP along with SlackLet's Integrate MuleSoft RPA, COMPOSER, APM with AWS IDP along with Slack
Let's Integrate MuleSoft RPA, COMPOSER, APM with AWS IDP along with Slack
 
Programming Foundation Models with DSPy - Meetup Slides
Programming Foundation Models with DSPy - Meetup SlidesProgramming Foundation Models with DSPy - Meetup Slides
Programming Foundation Models with DSPy - Meetup Slides
 
National Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practicesNational Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practices
 
Presentation of the OECD Artificial Intelligence Review of Germany
Presentation of the OECD Artificial Intelligence Review of GermanyPresentation of the OECD Artificial Intelligence Review of Germany
Presentation of the OECD Artificial Intelligence Review of Germany
 
Mind map of terminologies used in context of Generative AI
Mind map of terminologies used in context of Generative AIMind map of terminologies used in context of Generative AI
Mind map of terminologies used in context of Generative AI
 
Uni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdfUni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdf
 
Fueling AI with Great Data with Airbyte Webinar
Fueling AI with Great Data with Airbyte WebinarFueling AI with Great Data with Airbyte Webinar
Fueling AI with Great Data with Airbyte Webinar
 
20240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 202420240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 2024
 
Ocean lotus Threat actors project by John Sitima 2024 (1).pptx
Ocean lotus Threat actors project by John Sitima 2024 (1).pptxOcean lotus Threat actors project by John Sitima 2024 (1).pptx
Ocean lotus Threat actors project by John Sitima 2024 (1).pptx
 
How to use Firebase Data Connect For Flutter
How to use Firebase Data Connect For FlutterHow to use Firebase Data Connect For Flutter
How to use Firebase Data Connect For Flutter
 
Removing Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software FuzzingRemoving Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software Fuzzing
 
20240605 QFM017 Machine Intelligence Reading List May 2024
20240605 QFM017 Machine Intelligence Reading List May 202420240605 QFM017 Machine Intelligence Reading List May 2024
20240605 QFM017 Machine Intelligence Reading List May 2024
 
Columbus Data & Analytics Wednesdays - June 2024
Columbus Data & Analytics Wednesdays - June 2024Columbus Data & Analytics Wednesdays - June 2024
Columbus Data & Analytics Wednesdays - June 2024
 

Crafting Beautiful CLI Applications in Ruby

  • 1. RubyConf India 2012 Pune Crafting Beautiful Command Line Applications using Ruby Shishir Nikhil @shishirdas @hyfather
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14. ey heroku knife puppet pg_ctl mysql rails git
  • 15. bash zsh powershell ey heroku knife puppet pg_ctl mysql rails git
  • 16. ey heroku knife puppet pg_ctl mysql rails git Developers and QAs
  • 22. What makes a CLI app good?
  • 23. The Luxury of Ignorance
  • 25. ~ > rails Usage: 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") ~ >
  • 26. ~ > rails generate
  • 27. ~ > rails generate Usage: rails generate GENERATOR [args] [options] Please choose a generator below. Rails: assets controller generator helper integration_test mailer migration model observer performance_test plugin ~ >
  • 29. ~ > ssh usage: ssh [-1246AaCfgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_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] ~ >
  • 32. ~ > bundle Fetching 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) ~ >
  • 34. ~ > git commit -am "Added a new framework"
  • 35. ~ > git commit -am "Added a new framework" [master b4a2130] Added a new framework 2 files changed, 1012 insertions(+), 529 deletions(-) ~ >
  • 36. ~ > git commit -am "Added a new framework" [master b4a2130] Added a new framework 2 files changed, 1012 insertions(+), 529 deletions(-) ~ > git reset HEAD^
  • 37. ~ > 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.js M javascripts/support.js ~ >
  • 39. ~ > knife cookbook upload apache2 -o /User/foo/cookbooks -- server-url http://chef-server:4000 --key /etc/chef/my.key --color ~ >
  • 40. ~ > 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                :info log_location             STDOUT node_name                'blitz' client_key               '/Users/shishir/.chef/blitz.pem' validation_client_name   'chef-validator' validation_key           '/etc/chef/validation.pem' chef_server_url          'http://10.10.100.202:4000' cache_type               'BasicFile' cache_options( :path => '/Users/shishir/.chef/checksums' ) ~ >
  • 41. ~ > 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                :info log_location             STDOUT node_name                'blitz' client_key               '/Users/shishir/.chef/blitz.pem' validation_client_name   'chef-validator' validation_key           '/etc/chef/validation.pem' chef_server_url          'http://10.10.100.202:4000' cache_type               'BasicFile' cache_options( :path => '/Users/shishir/.chef/checksums' ) ~ > ~ > knife cookbook upload apache2
  • 43. ~ > git pull
  • 44. ~ > git pull You asked me to pull without telling me which branch you want to merge with, and 'branch.master.merge' in your configuration file does not tell me, either. Please specify which branch you want to use on the command line and try again (e.g. 'git pull <repository> <refspec>'). See git-pull(1) for details. If you often merge with the same branch, you may want to use 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.
  • 46.
  • 47.
  • 48. Confirmations should be scriptable
  • 49. ~ > gem uninstall rspec
  • 50. ~ > gem uninstall rspec You have requested to uninstall the gem: rspec-2.8.0 cucumber-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
  • 51. ~ > gem uninstall rspec You have requested to uninstall the gem: rspec-2.8.0 cucumber-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
  • 52. ~ > gem uninstall rspec You have requested to uninstall the gem: rspec-2.8.0 cucumber-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 Successfully uninstalled rspec-2.8.0
  • 54.
  • 55.
  • 61. Plethora of gems to help you
  • 64.
  • 65. Input Execution Output
  • 66. Input Execution Output STDIO = UI/UX
  • 67. Input
  • 68. Input STDIN
  • 69. Input ARGV/ENV STDIN
  • 70. Input ARGV/ENV STDIN
  • 71. Input ARGV/ENV STDIN
  • 72. Input OptionParser ARGV/ENV STDIN
  • 73. Input OptionParser ARGV/ENV STDIN
  • 74. Input Libraries OptionParser ARGV/ENV STDIN
  • 75. options = {} OptionParser.new do |opts| opts.banner = "Usage: example.rb [options]" opts.on("-v", "--[no-]verbose", "Run verbosely") do |v| options[:verbose] = v end end.parse!
  • 76. options = {} OptionParser.new do |opts| opts.banner = "Usage: example.rb [options]" opts.on("-v", "--[no-]verbose", "Run verbosely") do |v| options[:verbose] = v end end.parse! ~ > ./opt.rb --help Usage: example.rb [options]    -v, --[no-]verbose               Run verbosely
  • 77. options = {} OptionParser.new do |opts| opts.banner = "Usage: example.rb [options]" opts.on("-v", "--[no-]verbose", "Run verbosely") do |v| options[:verbose] = v end end.parse! ~ > ./opt.rb --help Usage: example.rb [options]    -v, --[no-]verbose               Run verbosely
  • 78. options = {} OptionParser.new do |opts| opts.banner = "Usage: example.rb [options]" opts.on("-v", "--[no-]verbose", "Run verbosely") do |v| options[:verbose] = v end end.parse! ~ > ./opt.rb --help Usage: example.rb [options]    -v, --[no-]verbose               Run verbosely
  • 79. options = {} OptionParser.new do |opts| opts.banner = "Usage: example.rb [options]" opts.on("-v", "--[no-]verbose", "Run verbosely") do |v| options[:verbose] = v end end.parse! ~ > ./opt.rb --help Usage: example.rb [options]    -v, --[no-]verbose               Run verbosely
  • 81. class MyCLIApp include Mixlib::CLI option :config_file, :short => "-c CONFIG", :description => "Configuration file", :required => true end ~ > ./mycliapp.rb --help Usage: ./mix.rb (options) -c, --config CONFIG Configuration file (required) -h, --help Show this message
  • 82. class MyCLIApp include Mixlib::CLI option :config_file, :short => "-c CONFIG", :description => "Configuration file", :required => true end ~ > ./mycliapp.rb --help Usage: ./mix.rb (options) -c, --config CONFIG Configuration file (required) -h, --help Show this message
  • 83. class MyCLIApp include Mixlib::CLI option :config_file, :short => "-c CONFIG", :description => "Configuration file", :required => true end ~ > ./mycliapp.rb --help Usage: ./mix.rb (options) -c, --config CONFIG Configuration file (required) -h, --help Show this message
  • 84. config.rb server_url “http://server.remote” username “elvis” password “hotdog”
  • 85. config.rb server_url “http://server.remote” username “elvis” password “hotdog” class MyConfig extend(Mixlib::Config) server_url 'http://server.local' username 'king' password 'burger' end MyConfig.from_file(‘config.rb’) irb> MyConfig.server_url # ‘http://server.remote’
  • 86. config.rb server_url “http://server.remote” username “elvis” password “hotdog” class MyConfig extend(Mixlib::Config) server_url 'http://server.local' username 'king' password 'burger' end MyConfig.from_file(‘config.rb’) irb> MyConfig.server_url # ‘http://server.remote’
  • 87. Thor
  • 88. class Test < Thor desc " FILE", "an example task" method_option :delete, :aliases => "-d", :desc => "Delete the file" def example(file) end end
  • 89. class Test < Thor desc " FILE", "an example task" method_option :delete, :aliases => "-d", :desc => "Delete the file" def example(file) end end ~ > myapp help test:example Usage: thor test:example FILE Options: -d, [--delete=DELETE] # Delete the file after parsing it an example task
  • 90. class Test < Thor desc " FILE", "an example task" method_option :delete, :aliases => "-d", :desc => "Delete the file" def example(file) end end ~ > myapp help test:example Usage: thor test:example FILE Options: -d, [--delete=DELETE] # Delete the file after parsing it an example task
  • 91. class Test < Thor desc " FILE", "an example task" method_option :delete, :aliases => "-d", :desc => "Delete the file" def example(file) end end ~ > myapp help test:example Usage: thor test:example FILE Options: -d, [--delete=DELETE] # Delete the file after parsing it an example task
  • 92. class Test < Thor desc " FILE", "an example task" method_option :delete, :aliases => "-d", :desc => "Delete the file" def example(file) end end ~ > myapp help test:example Usage: thor test:example FILE Options: -d, [--delete=DELETE] # Delete the file after parsing it an example task
  • 93. class Test < Thor desc " FILE", "an example task" method_option :delete, :aliases => "-d", :desc => "Delete the file" def example(file) end end ~ > myapp help test:example Usage: thor test:example FILE Options: -d, [--delete=DELETE] # Delete the file after parsing it an example task
  • 94. class Test < Thor desc " FILE", "an example task" method_option :delete, :aliases => "-d", :desc => "Delete the file" def example(file) end end ~ > myapp help test:example Usage: thor test:example FILE Options: -d, [--delete=DELETE] # Delete the file after parsing it an example task
  • 95. class Test < Thor desc " FILE", "an example task" method_option :delete, :aliases => "-d", :desc => "Delete the file" def example(file) end end ~ > myapp help test:example Usage: thor test:example FILE Options: -d, [--delete=DELETE] # Delete the file after parsing it an example task
  • 97.
  • 98. Input Execution Output
  • 99. Input Execution Output
  • 100. Input Execution Output Mostly third party libraries
  • 101. Input Execution Output Test::Unit, rspec etc.
  • 102. Input Execution Output System
  • 103. System File System Network Process
  • 104. Isolated Environments Container User Application File Memory Processes System
  • 106. STDOUT STDIN App STDERR
  • 107. STDOUT STDIN App STDERR
  • 108. STDOUT STDIN App STDERR STDOUT & STDERR STDIN App
  • 109. Mixlib::Shellout > ls = Mixlib::ShellOut.new("ls") > ls.run_command > ls.stdout “init.elnREADME.mdn”
  • 110. Mixlib::Shellout > ls = Mixlib::ShellOut.new("ls") > ls.run_command > ls.stdout “init.elnREADME.mdn”
  • 112. Hooks
  • 114. GNU CLI standards ‘--version’ and ‘--help’ Input/Output Files -- -O for Output Files
  • 115. “CLI apps could be the first consumers ” of your services.
  • 116. “CLI apps could be the first consumers ” of your services.
  • 117. “CLI apps could be the first consumers ” of your services. Testing Development Cheap No rich UI, functional Fast tests
  • 118. Ideas CLI app for a REST API: Github SCM Plugins for Knife Transform Rake scripts into first class CLI apps Shishir Nikhil @shishirdas @hyfather
  • 119. Questions Comments Suggestions Shishir Nikhil @shishirdas @hyfather

Editor's Notes

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. \n
  23. \n
  24. \n
  25. \n
  26. \n
  27. \n
  28. \n
  29. \n
  30. \n
  31. \n
  32. task oriented v/s feature oriented\n(ssh is feature / rails is tasks)\n\nOther Examples -- knife &amp; cucumber\nTODO: SSH\n
  33. \n
  34. \n
  35. \n
  36. \n
  37. \n
  38. \n
  39. bundle is a bad example\n\nrails/git/knife are good examples\n\n
  40. \n
  41. \n
  42. 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
  43. make an example for rails generate /destroy\n
  44. make an example for rails generate /destroy\n
  45. make an example for rails generate /destroy\n
  46. make an example for rails generate /destroy\n
  47. 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
  48. \n
  49. \n
  50. \n
  51. git add\n&gt; did you mean `git add .&amp;#x2019; ?\n
  52. \n
  53. \n
  54. vi modes\nbehavior should not depend on hidden state\n
  55. \n
  56. \n
  57. \n
  58. \n
  59. \n
  60. \n
  61. git is a very mature cli. no piping or redirection normally used. but it honors everything.\nwrite errors to stderr\n
  62. \n
  63. \n
  64. \n
  65. \n
  66. \n
  67. \n
  68. \n
  69. knife, rails, gem, bundle\n
  70. \n
  71. Input - command line -&gt; Option Parsing\n\nOutput - status code, stdout, stderr\n
  72. Input - command line -&gt; Option Parsing\n\nOutput - status code, stdout, stderr\n
  73. Input - command line -&gt; Option Parsing\n\nOutput - status code, stdout, stderr\n
  74. Input - command line -&gt; Option Parsing\n\nOutput - status code, stdout, stderr\n
  75. Input - command line -&gt; Option Parsing\n\nOutput - status code, stdout, stderr\n
  76. Input - command line -&gt; Option Parsing\n\nOutput - status code, stdout, stderr\n
  77. Input - command line -&gt; Option Parsing\n\nOutput - status code, stdout, stderr\n
  78. Input - command line -&gt; Option Parsing\n\nOutput - status code, stdout, stderr\n
  79. Input - command line -&gt; Option Parsing\n\nOutput - status code, stdout, stderr\n
  80. Input - command line -&gt; Option Parsing\n\nOutput - status code, stdout, stderr\n
  81. \n
  82. \n
  83. \n
  84. \n
  85. \n
  86. \n
  87. \n
  88. \n
  89. \n
  90. \n
  91. \n
  92. \n
  93. \n
  94. \n
  95. \n
  96. \n
  97. \n
  98. \n
  99. \n
  100. \n
  101. Enforces OO\nAutomatic rake style tasks\n
  102. Enforces OO\nAutomatic rake style tasks\n
  103. Enforces OO\nAutomatic rake style tasks\n
  104. Convention -- \nfirst arg to the description becomes the input \nsecond arg is the banner\n
  105. Convention -- \nfirst arg to the description becomes the input \nsecond arg is the banner\n
  106. Convention -- \nfirst arg to the description becomes the input \nsecond arg is the banner\n
  107. Option Parsing\nInbuilt support for help and banners\nSupports standard invocations of help on the shell\n
  108. Option Parsing\nInbuilt support for help and banners\nSupports standard invocations of help on the shell\n
  109. \n
  110. \n
  111. \n
  112. \n
  113. Input - mostly handled by the third party library.\nTesting that would be testing the gem. Not a good idea.\n\n
  114. Input - mostly handled by the third party library.\nTesting that would be testing the gem. Not a good idea.\n\n
  115. Standard Ruby classes. Libraries like test/unit, rspec.\nMocking and proxy layers for 3rd party services etc.\nLike any other app.\n\n
  116. \n
  117. 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
  118. 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
  119. 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
  120. \n
  121. \n
  122. \n
  123. Compatible with windows.\nUses the select(2) system call. \nGives abstractions over umask, cwd etc.\n
  124. Compatible with windows.\nUses the select(2) system call. \nGives abstractions over umask, cwd etc.\n
  125. 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
  126. 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
  127. 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
  128. Give URL in sliduments\n
  129. \n
  130. \n
  131. \n
  132. \n
  133. \n
  134. \n
  135. \n