[Build Status](https://travis-ci.org/commander-rb/commander) [![Inline docs](https://inch-ci.org/github/commander-rb/commander.svg)](https://inch-ci.org/github/commander-rb/commander) # Commander The complete solution for Ruby command-line executables. Commander bridges the gap between other terminal related libraries you know and love (OptionParser, HighLine), while providing many new features, and an elegant API. ## Features * Easier than baking cookies * Parses options using OptionParser * Auto-populates struct with options ( no more `{ |v| options[:recursive] = v }` ) * Auto-generates help documentation via pluggable help formatters * Optional default command when none is present * Global / Command level options * Packaged with two help formatters (Terminal, TerminalCompact) * Imports the highline gem for interacting with the terminal * Adds additional user interaction functionality * Highly customizable progress bar with intuitive, simple usage * Multi-word command name support such as `drupal module install MOD`, rather than `drupal module_install MOD` * Sexy paging for long bodies of text * Support for MacOS text-to-speech * Command aliasing (very powerful, as both switches and arguments can be used) * Growl notification support for MacOS * Use the `commander` executable to initialize a commander driven program ## Installation $ gem install commander ## Quick Start To generate a quick template for a commander app, run: $ commander init yourfile.rb To generate a quick modular style template for a commander app, run: $ commander init --modular yourfile.rb ## Example For more option examples view the `Commander::Command#option` method. Also an important feature to note is that action may be a class to instantiate, as well as an object, specifying a method to call, so view the RDoc for more information. ### Classic style ```ruby require 'rubygems' require 'commander/import' # :name is optional, otherwise uses the basename of this executable program :name, 'Foo Bar' program :version, '1.0.0' program :description, 'Stupid command that prints foo or bar.' command :foo do |c| c.syntax = 'foobar foo' c.description = 'Displays foo' c.action do |args, options| say 'foo' end end command :bar do |c| c.syntax = 'foobar bar [options]' c.description = 'Display bar with optional prefix and suffix' c.option '--prefix STRING', String, 'Adds a prefix to bar' c.option '--suffix STRING', String, 'Adds a suffix to bar' c.action do |args, options| options.default :prefix => '(', :suffix => ')' say "#{options.prefix}bar#{options.suffix}" end end ``` Example output: ``` $ foobar bar # => (bar) $ foobar bar --suffix '}' --prefix '{' # => {bar} ``` ### Modular style **NOTE:** Make sure to use `require 'commander'` rather than `require 'commander/import'`, otherwise Commander methods will still be imported into the global namespace. ```ruby require 'rubygems' require 'commander' class MyApplication include Commander::Methods def run program :name, 'Foo Bar' program :version, '1.0.0' program :description, 'Stupid command that prints foo or bar.' command :foo do |c| c.syntax = 'foobar foo' c.description = 'Displays foo' c.action do |args, options| say 'foo' end end run! end end MyApplication.new.run if $0 == __FILE__ ``` ### Block style ```ruby require 'rubygems' require 'commander' Commander.configure do program :name, 'Foo Bar' program :version, '1.0.0' program :description, 'Stupid command that prints foo or bar.' # see classic style example for options end ``` ## HighLine As mentioned above, the highline gem is imported into the global scope. Here are some quick examples for how to utilize highline in your commands: ```ruby # Ask for password masked with '*' character ask("Password: ") { |q| q.echo = "*" } # Ask for password ask("Password: ") { |q| q.echo = false } # Ask if the user agrees (yes or no) agree("Do something?") # Asks on a single line (note the space after ':') ask("Name: ") # Asks with new line after "Description:" ask("Description:") # Calls Date#parse to parse the date string passed ask("Birthday? ", Date) # Ensures Integer is within the range specified ask("Age? ", Integer) { |q| q.in = 0..105 } # Asks for a list of strings, converts to array ask("Fav colors?", Array) ``` ## HighLine & Interaction Additions In addition to highline's fantastic choice of methods, commander adds the following methods to simplify common tasks: ```ruby # Ask for password password # Ask for password with specific message and mask character password "Enter your password please:", '-' # Ask for CLASS, which may be any valid class responding to #parse. Date, Time, Array, etc names = ask_for_array 'Names: ' bday = ask_for_date 'Birthday?: ' # Simple progress bar (Commander::UI::ProgressBar) uris = %w[ http://vision-media.ca http://google.com http://yahoo.com ] progress uris do |uri| res = open uri # Do something with response end # 'Log' action to stdout log "create", "path/to/file.rb" # Enable paging of output after this point enable_paging # Ask editor for input (EDITOR environment variable or whichever is available: TextMate, vim, vi, emacs, nano, pico) ask_editor # Ask editor, supplying initial text ask_editor 'previous data to update' # Ask editor, preferring a specific editor ask_editor 'previous data', 'vim' # Choose from an array of elements choice = choose("Favorite language?", :ruby, :perl, :js) # Alter IO for the duration of the block io new_input, new_output do new_input_contents = $stdin.read puts new_input_contents # outputs to new_output stream end # $stdin / $stdout reset back to original streams # Speech synthesis speak 'What is your favorite food? ' food = ask 'favorite food?: ' speak "Wow, I like #{food} too. We have so much in common." speak "I like #{food} as well!", "Victoria", 190 # Execute arbitrary applescript applescript 'foo' # Converse with speech recognition server case converse 'What is the best food?', :cookies => 'Cookies', :unknown => 'Nothing' when :cookies speak 'o.m.g. you are awesome!' else case converse 'That is lame, shall I convince you cookies are the best?', :yes => 'Ok', :no => 'No', :maybe => 'Maybe another time' when :yes speak 'Well you see, cookies are just fantastic, they melt in your mouth.' else speak 'Ok then, bye.' end end ``` ## Growl Notifications Commander provides methods for displaying Growl notifications. To use these methods you need to install https://github.com/tj/growl which utilizes the [growlnotify](https://growl.info/extras.php#growlnotify) executable. Note that growl is auto-imported by Commander when available, no need to require. ```ruby # Display a generic Growl notification notify 'Something happened' # Display an 'info' status notification notify_info 'You have #{emails.length} new email(s)' # Display an 'ok' status notification notify_ok 'Gems updated' # Display a 'warning' status notification notify_warning '1 gem failed installation' # Display an 'error' status notification notify_error "Gem #{name} failed" ``` ## Commander Goodies ### Option Defaults The options struct passed to `#action` provides a `#default` method, allowing you to set defaults in a clean manner for options which have not been set. ```ruby command :foo do |c| c.option '--interval SECONDS', Integer, 'Interval in seconds' c.option '--timeout SECONDS', Integer, 'Timeout in seconds' c.action do |args, options| options.default \ :interval => 2, :timeout => 60 end end ``` ### Command Aliasing Aliases can be created using the `#alias_command` method like below: ```ruby command :'install gem' do |c| c.action { puts 'foo' } end alias_command :'gem install', :'install gem' ``` Or more complicated aliases can be made, passing any arguments as if it was invoked via the command line: ```ruby command :'install gem' do |c| c.syntax = 'install gem [options]' c.option '--dest DIR', String, 'Destination directory' c.action { |args, options| puts "installing #{args.first} to #{options.dest}" } end alias_command :update, :'install gem', 'rubygems', '--dest', 'some_path' ``` ``` $ foo update # => installing rubygems to some_path ``` ### Command Defaults Although working with a command executable framework provides many benefits over a single command implementation, sometimes you still want the ability to create a terse syntax for your command. With that in mind we may use `#default_command` to help with this. Considering our previous `:'install gem'` example: ```ruby default_command :update ``` ``` $ foo # => installing rubygems to some_path ``` Keeping in mind that commander searches for the longest possible match when considering a command, so if you were to pass arguments to foo like below, expecting them to be passed to `:update`, this would be incorrect, and would end up calling `:'install gem'`, so be careful that the users do not need to use command names within the arguments. ``` $ foo install gem # => installing to ``` ### Long descriptions If you need to have a long command description, keep your short description under `summary`, and consider multi-line strings for `description`: ```ruby program :summary, 'Stupid command that prints foo or bar.' program :description, %q( #{c.summary} More information about that stupid command that prints foo or bar. And more ) ``` ### Additional Global Help Arbitrary help can be added using the following `#program` symbol: ```ruby program :help, 'Author', 'TJ Holowaychuk ' ``` Which will output the rest of the help doc, along with: AUTHOR: TJ Holowaychuk ### Global Options Although most switches will be at the command level, several are available by default at the global level, such as `--version`, and `--help`. Using `#global_option` you can add additional global options: ```ruby global_option('-c', '--config FILE', 'Load config data for your commands to use') { |file| ... } ``` This method accepts the same syntax as `Commander::Command#option` so check it out for documentation. All global options regardless of providing a block are accessable at the command level. This means that instead of the following: ```ruby global_option('--verbose') { $verbose = true } ... c.action do |args, options| say 'foo' if $verbose ... ``` You may: ```ruby global_option '--verbose' ... c.action do |args, options| say 'foo' if options.verbose ... ``` ### Formatters Two core formatters are currently available, the default `Terminal` formatter as well as `TerminalCompact`. To utilize a different formatter simply use `:help_formatter` like below: ```ruby program :help_formatter, Commander::HelpFormatter::TerminalCompact ``` Or utilize the help formatter aliases: ```ruby program :help_formatter, :compact ``` This abstraction could be utilized to generate HTML documentation for your executable. ### Tracing By default the `-t` and `--trace` global options are provided to allow users to get a backtrace to aid debugging. You can disable these options: ```ruby never_trace! ``` Or make it always on: ```ruby always_trace! ``` ## Tips When adding a global or command option, OptionParser implicitly adds a small switch even when not explicitly created, for example `-c` will be the same as `--config` in both examples, however `-c` will only appear in the documentation when explicitly assigning it. ```ruby global_option '-c', '--config FILE' global_option '--config FILE' ``` ## ASCII Tables For feature rich ASCII tables for your terminal app check out the terminal-table gem at https://github.com/tj/terminal-table +----------+-------+----+--------+-----------------------+ | Terminal | Table | Is | Wicked | Awesome | +----------+-------+----+--------+-----------------------+ | | | | | get it while its hot! | +----------+-------+----+--------+-----------------------+ ## Running Specifications $ rake spec OR $ spec --color spec ## Contrib Feel free to fork and request a pull, or submit a ticket https://github.com/commander-rb/commander/issues ## License This project is available under the MIT license. See LICENSE for details.