{<img src="https://secure.travis-ci.org/ggilder/commander.png?branch=master" alt="Build Status" />}[http://travis-ci.org/ggilder/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

== 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.

   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

   $ foobar bar
   # => (bar)

   $ foobar bar --suffix '}' --prefix '{'
   # => {bar}

== HighLine

As mentioned above the highline gem is imported into 'global scope', below
are some quick examples for how to utilize highline in your command(s):
   
   # 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:

   # 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 http://github.com/visionmedia/growl which utilizes
the growlnotify[http://growl.info/extras.php#growlnotify] executable. Note that
growl is auto-imported by Commander when available, no need to require.

  # 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.

  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:

  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:

  command :'install gem' do |c|
    c.syntax = 'install gem <name> [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:

  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 

=== Additional Global Help

Arbitrary help can be added using the following #program symbol:

  program :help, 'Author', 'TJ Holowaychuk <tj@vision-media.ca>'

Which will output the rest of the help doc, along with:

  AUTHOR:

    TJ Holowaychuk <tj@vision-media.ca>

=== 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:

  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:

  global_option('--verbose') { $verbose = true }
  ...
  c.action do |args, options|
    say 'foo' if $verbose
  ...

You may:

  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:

  program :help_formatter, Commander::HelpFormatter::TerminalCompact

Or utilize the help formatter aliases:

  program :help_formatter, :compact

This abstraction could be utilized to generate HTML documentation for your executable.

== 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.

  global_option '-c', '--config FILE'
  global_option '--config FILE'

== ASCII Tables

For feature rich ASCII tables for your terminal app check out visionmedia's terminal-table gem at
http://github.com/visionmedia/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
http://github.com/visionmedia/commander/issues

== License

(The MIT License)

Copyright (c) 2008-2009 TJ Holowaychuk <tj@vision-media.ca>

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
