Command Line Applications with Ruby
-
Upload
alexander-merkulov -
Category
Presentations & Public Speaking
-
view
91 -
download
0
Transcript of Command Line Applications with Ruby
COMMANDLINEAPPLICATIONS RUBY
AlexanderMerkulov
/
merqlove @merqlove
LOOKINGFORGEMS&
RakeOptionParserOptitronCommanderMain...manuallybuilditanywhereelse
BESTPRACTICES
BASEFEATURES&FACTSCOMPARISON
Feature OP Thor GLI
Numberofdownloads asRuby 63596500 898088
Authors Community Y.Katz D.Copeland
Noruntimedependencies Yes Yes Yes
Theargumentspecificationandthecode Yes Yes Yes
Outputanoptionsummary Yes Yes Yes
Optionalandmandatoryarguments Yes Yes Yes
Argumentscanbeautomaticallyconverted Yes Yes Yes
Argumentscanberestrictedtoacertainset Yes Yes Yes
ADVANCEDFEATURESCOMPARISONFeature OP Thor GLI
Descriptionhelper No Yes Yes
Longdescriptionhelper No Yes Yes
Actions No Yes Yes/No
Subcommands No Yes Yes
EasyChildclassloading No Yes No
Minimalisticapplicationcodebase No Yes Yes/No
Activelymaintains Yes/No Yes Yes
Fancycolors No Yes No
GIT-LIKEINTERFACECOMMANDLINEPARSER
Usefulifyouworkonmonolithbinary.Quitereadablecode.NoOOPrequired:)HasscaffoldgeneratorwithTDD/BDDapproach.Regularupdates.
GLI DAVETRON5000/GLI
$gliinitsomecommandversion├── Gemfile├── README.rdoc├── Rakefile├── bin│ └── some # our binary├── dist # tools for deploy├── features # if cucumber│ ├── some.feature│ ├── step_definitions│ │ └── some_steps.rb│ └── support│ └── env.rb├── lib│ ├── some│ │ └── version.rb│ └── some.rb├── some.gemspec└── test ├── default_test.rb └── test_helper.rb
ADDSOMECOMMANDSdesc 'DEFAULT. Create and cleanup snapshot\'s'command [:s, :snap] do |c| c.desc 'Select api version.' c.arg_name '1' c.flag [:p,:protocol], default_value: 2, type: Numeric
c.desc 'How much snapshots you want to keep?' c.arg_name '5' c.flag [:k,:keep], default_value: 10, type: Numeric ... c.desc 'Stop creating snapshots if maximum is reached.' c.switch [:s,:stop] c.action do |global_options,options,args| DoSnapshot::Command.new(options).snap endend
desc 'Shows the version of the currently installed DoSnapshot gem'version DoSnapshot::VERSION
gist
ADDSOMELOGICpre do |global,command,options,args| $some_service = DoSnapshot::Service.new(options) trueend
post do |global,command,options,args| $some_service = nilend
on_error do |exception| $some_service.send(exception) end
exit run(ARGV)
TIMETOTRY:)$ do_snapshot helpNAME do_snapshot - `do_snapshot` able to create and cleanup snapshots on your droplets.
SYNOPSIS do_snapshot [global options] command [command options] [arguments...]
GLOBAL OPTIONS -c, --clean=arg - Cleanup snapshots after create. If you have more images than you want to `keep`, older will be deleted. (default: true) -d, --delay=5 - Delay between snapshot operation status requests. (default: 10) --digital_ocean_access_token=YOURLONGAPITOKEN - DIGITAL_OCEAN_ACCESS_TOKEN. if you can't use environment. (default: none) --help - Show this message -k, --keep=5 - How much snapshots you want to keep? (default: 10) -l, --log=/Users/someone/.do_snapshot/main.log - Log file path. By default logging is disabled. (default: none) -p, --protocol=1 - Select api version. (default: 2) --smtp=user_name:[email protected] - SMTP options. (default: none) -q, --quiet=arg - Quiet mode. If don't need any messages and in console. (default: none) -s, --stop=arg - Stop creating snapshots if maximum is reached. (default: none) --timeout=250 - Timeout in sec's for events like Power Off or Create Snapshot. (default: 3600) -v, --trace=arg - Verbose mode. (default: none)
COMMANDS version - Shows the version of the currently installed DoSnapshot gem help - Shows a list of commands or help for one command s, snap - DEFAULT. Create and cleanup snapshot's
FEATURETEST# features/some.featureFeature: My bootstrapped app kinda works In order to get going on coding my awesome app I want to have aruba and cucumber setup So I don't have to do it myself
Scenario: App just runs When I get help for "some" Then the exit status should be 0
# features/step_definitions/some_steps.rbWhen /^I get help for "([^"]*)"$/ do |app_name| @app_name = app_name step %(I run `#{app_name} help`)end
OPTIONS&ARGUMENTSCOMPARISON
Feature OP Thor GLI
Advancedoptionmode No Yes No
Multipleoptionsone-liner No Yes No
Optionsorder No Yes No
Arrayarguments No Yes Yes
Hasharguments Yes/No Yes No
Enumarguments No Yes No
Global(class-wide)arguments No Yes No
CUSTOMPARSERSaccept Array do |value| value.split(/\s/).map(&:strip)end
accept Hash do |value| result = {} value.split(/\s/).each do |pair| k,v = pair.split(/:/) result[k] = v end resultend
...
desc 'SMTP options.'arg_name 'user_name:[email protected]'flag :smtp, type: Hash
$ do_snapshot -k 5 --smtp=user_name:user1 password:123456
gist
Thorisatoolkitforbuildingpowerfulcommand-lineinterfaces.Widelyused.Easytosplitmonolithapplication.ThesyntaxisRake-like.ThorismorethanjustoptionparserAlotoftutorials.
THOR ERIKHUDA/THOR
binBinaryfile(s)
distRakedeployscripts
lib/*/runnerApplicationrunner
lib/*/cliCLImonolithorparent
lib/*/commandCommandinterface
lib/*/logApplicationlogger
specRSpectestsincludingfeatures&fixtures
├── bin│ └── do_snapshot├── dist│ ├── ...│ ├── gem.rake│ ├── manifest.rake│ └── zip.rake├── lib│ ├── do_snapshot│ │ ├── cli.rb│ │ ├── command.rbb│ │ ├── log.rb│ │ ├── runner.rb│ │ └── ...│ └── do_snapshot.rb├── spec│ ├── do_snapshot│ │ └── ...│ ├── fixtures│ ├── support│ │ ├── aruba.rb│ │ └── ...│ ├── do_snapshot_spec.rb│ └── spec_helper.rb├── Gemfile├── README.md├── Rakefile└── do_snapshot.gemspec
BINARY#!/usr/bin/env ruby
Signal.trap('INT') { exit 1 }
# resolve bin path, ignoring symlinksrequire 'pathname'bin_file = Pathname.new(__FILE__).realpath
# add self to libpath$LOAD_PATH.unshift File.expand_path('../../lib', bin_file)
require 'do_snapshot/runner'
DoSnapshot::Runner.new(ARGV.dup).execute!
RUNNERclass Runner def initialize(argv, stdin = STDIN, stdout = STDOUT, stderr = STDERR, kernel = Kernel) @argv, @stdin, @stdout, @stderr, @kernel = argv, stdin, stdout, stderr, kernel end def execute! exit_code = begin run_cli rescue StandardError => e display_backtrace_otherwise(e) rescue SystemExit => e e.status ensure clean_before_exit end @kernel.exit(exit_code) end ...end
github
SAMPLECLIMONOLITHSampleclassforCLIapplication.
map-mappingcommands.
initialize-prepareenvironment.
no_commands-definehelperorprivatemethods.
module DoSnapshot class CLI < Thor include DoSnapshot::Helpers
default_task :snap
map %w( c s create ) => :snap map %w( -V ) => :version
def initialize(*args) super
# custom initialization end
...
no_commands do # define helpers end endend
github
THORDSLdesc-description&shortcuts
long_desc-multilinecommanddescription.
method_option-commandoption
desc 'c / s / snap / create', '...'long_desc <<-LONGDESC`do_snapshot` able to create snapshots ...
VERSION: #{DoSnapshot::VERSION}LONGDESCmethod_option :mail, type: :hash, aliases: %w( -m ), banner: 'to:[email protected]', desc: 'Receive mail if fail or maximum is reached.'
def snap ...end
github
METHOD_OPTIONaliases—Alistofaliasesforoption.banner—Theshortdescriptionoftheoption,printedoutintheusagedescription.default—Thedefaultvalueofthisoptionifitisnotprovided.lazy_default—Adefaultthatisonlypassediftheclioptionispassedwithoutavalue.desc—Adescriptionfortheoption.required—Indicatesthatanoptionisrequiredtype—:string,:hash,:array,:numeric,or:booleanenum—Alistofallowedvaluesforthisoption.
ARUBA&RSPECAREFRIENDS# support/aruba.rb
require 'aruba/rspec'require 'do_snapshot/runner'
Aruba.configure do |config| config.command_launcher = :in_process config.main_class = DoSnapshot::Runnerend
ARUBAWITHINRSPECRSpec.describe DoSnapshot::Runner, type: :aruba do context 'commands' do context '.help' do it 'shows a help message' do run 'do_snapshot help' expect(all_stdout) .to match('Commands:') end end
context '.version' do it 'with right version' do run 'do_snapshot version' expect(all_stdout).to include(DoSnapshot::VERSION) end end endend
$ do_snapshot help sUsage: do_snapshot c / s / snap / create
Options: -p, [--protocol=1] # Select api version. # Default: 1 -o, [--only=123456 123456 123456] # Select some droplets. -e, [--exclude=123456 123456 123456] # Except some droplets. -k, [--keep=5] # How much snapshots you want to keep? # Default: 10 -d, [--delay=5] # Delay between snapshot operation status requests. # Default: 10 -m, [--mail=to:[email protected]] # Receive mail if fail or maximum is reached. -t, [--smtp=user_name:[email protected]] # SMTP options. -l, [--log=/Users/someone/.do_snapshot/main.log] # Log file path. By default logging is disabled. -s, [--stop], [--no-stop] # Stop creating snapshots if maximum is reached. -v, [--trace], [--no-trace] # Verbose mode. -q, [--quiet], [--no-quiet] # Quiet mode. If don't need any messages and in console.
Description: `do_snapshot` able to create and cleanup snapshots on your droplets.
BESTPRACTICES:Deploytorepositoryofyourchoice.UsesingleRaketaskforpushingtoanyservice.Providezip,tgzpacksofyourCLIapp.UseRubocop&Coveragemetrics.Don'tbetoolazytowritetests.Semanticversioning.Providedocsor/andwiki....So,asforanyRubyapplication.
EXAMPLES&HOW-TOgithub.com/chef/omnibusgithub.com/mitchellh/vagrantgithub.com/merqlove/do_snapshotgithub.com/pseudomuto/bookeryAwesomeCommandLineAppsThor&OptionParsercomparison.
HAPPYCODING!ThorOptionParserAPIArubaRSpecGLI