[DRE-commits] [ruby-commander] 01/11: New upstream version 4.4.1

Daisuke Higuchi dai at moszumanska.debian.org
Sat Oct 21 12:40:35 UTC 2017


This is an automated email from the git hooks/post-receive script.

dai pushed a commit to branch master
in repository ruby-commander.

commit 242f29889bf7a17bdb3cf6d1ab1d959fc572bf93
Author: HIGUCHI Daisuke (VDR dai) <dai at debian.org>
Date:   Sat Oct 21 21:16:39 2017 +0900

    New upstream version 4.4.1
---
 .rspec                                             |   2 +
 .rubocop.yml                                       |   9 +
 .rubocop_todo.yml                                  |  77 +++
 .travis.yml                                        |  11 +-
 Gemfile                                            |   2 +-
 History.rdoc                                       |  65 +++
 LICENSE                                            |  22 +
 README.md                                          | 460 ++++++++++++++++++
 README.rdoc                                        | 372 ---------------
 Rakefile                                           |  11 +-
 bin/commander                                      |  87 +++-
 commander.gemspec                                  |  39 +-
 lib/commander.rb                                   |   3 +
 lib/commander/blank.rb                             |   5 +-
 lib/commander/command.rb                           | 131 +++--
 lib/commander/configure.rb                         |  14 +
 lib/commander/core_ext.rb                          |   3 +-
 lib/commander/core_ext/array.rb                    |   6 +-
 lib/commander/core_ext/object.rb                   |   5 +-
 lib/commander/delegates.rb                         |  24 +-
 lib/commander/help_formatters.rb                   |  42 +-
 lib/commander/help_formatters/base.rb              |  22 +-
 lib/commander/help_formatters/terminal.rb          |  15 +-
 .../help_formatters/terminal/command_help.erb      |   2 +-
 lib/commander/help_formatters/terminal/help.erb    |   4 +-
 lib/commander/help_formatters/terminal_compact.rb  |   5 +-
 .../help_formatters/terminal_compact/help.erb      |   4 +-
 lib/commander/import.rb                            |   7 +-
 lib/commander/methods.rb                           |  11 +
 lib/commander/platform.rb                          |   1 -
 lib/commander/runner.rb                            | 293 +++++++-----
 lib/commander/user_interaction.rb                  | 245 +++++-----
 lib/commander/version.rb                           |   2 +-
 metadata.yml                                       | 157 ------
 spec/command_spec.rb                               | 150 +++---
 spec/configure_spec.rb                             |  37 ++
 spec/core_ext/array_spec.rb                        |  16 +-
 spec/core_ext/object_spec.rb                       |  18 +-
 spec/help_formatters/terminal_compact_spec.rb      |  69 +++
 spec/help_formatters/terminal_spec.rb              |  58 +--
 spec/methods_spec.rb                               |  20 +
 spec/runner_spec.rb                                | 527 ++++++++++++---------
 spec/spec_helper.rb                                |  58 +--
 spec/ui_spec.rb                                    |  26 +-
 44 files changed, 1813 insertions(+), 1324 deletions(-)

diff --git a/.rspec b/.rspec
new file mode 100644
index 0000000..83e16f8
--- /dev/null
+++ b/.rspec
@@ -0,0 +1,2 @@
+--color
+--require spec_helper
diff --git a/.rubocop.yml b/.rubocop.yml
new file mode 100644
index 0000000..a44b4d9
--- /dev/null
+++ b/.rubocop.yml
@@ -0,0 +1,9 @@
+inherit_from: .rubocop_todo.yml
+
+# Offense count: 5
+Encoding:
+  Enabled: false
+
+# Enforce trailing comma after last item of multiline hashes.
+Style/TrailingComma:
+  EnforcedStyleForMultiline: comma
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
new file mode 100644
index 0000000..6f806dc
--- /dev/null
+++ b/.rubocop_todo.yml
@@ -0,0 +1,77 @@
+# This configuration was generated by `rubocop --auto-gen-config`
+# on 2015-02-16 16:08:54 -0800 using RuboCop version 0.29.0.
+# The point is for the user to remove these configuration records
+# one by one as the offenses are removed from the code base.
+# Note that changes in the inspected code, or installation of new
+# versions of RuboCop, may require this file to be generated again.
+
+# Offense count: 2
+Lint/Eval:
+  Enabled: false
+
+# Offense count: 2
+Lint/HandleExceptions:
+  Enabled: false
+
+# Offense count: 5
+Metrics/AbcSize:
+  Max: 29
+
+# Offense count: 1
+# Configuration parameters: CountComments.
+Metrics/ClassLength:
+  Enabled: false
+
+# Offense count: 4
+Metrics/CyclomaticComplexity:
+  Max: 13
+
+# Offense count: 89
+# Configuration parameters: AllowURI, URISchemes.
+Metrics/LineLength:
+  Max: 242
+
+# Offense count: 7
+# Configuration parameters: CountComments.
+Metrics/MethodLength:
+  Max: 36
+
+# Offense count: 4
+Metrics/PerceivedComplexity:
+  Max: 14
+
+# Offense count: 1
+Style/AccessorMethodName:
+  Enabled: false
+
+# Offense count: 18
+Style/Documentation:
+  Enabled: false
+
+# Offense count: 12
+# Configuration parameters: AllowedVariables.
+Style/GlobalVars:
+  Enabled: false
+
+# Offense count: 1
+# Configuration parameters: MaxLineLength.
+Style/IfUnlessModifier:
+  Enabled: false
+
+# Offense count: 1
+Style/MultilineBlockChain:
+  Enabled: false
+
+# Offense count: 1
+Style/MultilineTernaryOperator:
+  Enabled: false
+
+# Offense count: 5
+Style/RescueModifier:
+  Enabled: false
+
+# Offense count: 2
+# Cop supports --auto-correct.
+# Configuration parameters: ExactNameMatch, AllowPredicates, AllowDSLWriters, Whitelist.
+Style/TrivialAccessors:
+  Enabled: false
diff --git a/.travis.yml b/.travis.yml
index 78d5e9c..eb94999 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,11 +1,10 @@
 language: ruby
-before_install: gem update --system
+before_install:
+  - gem update --system
+  - gem update bundler
 rvm:
-  - 1.8.7
-  - 1.9.2
   - 1.9.3
   - 2.0.0
-  - jruby-18mode
+  - 2.1.0
+  - 2.2.0
   - jruby-19mode
-  - rbx-18mode
-  - rbx-19mode
diff --git a/Gemfile b/Gemfile
index c80ee36..fa75df1 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,3 +1,3 @@
-source "http://rubygems.org"
+source 'https://rubygems.org'
 
 gemspec
diff --git a/History.rdoc b/History.rdoc
index 4951319..d05c0e9 100644
--- a/History.rdoc
+++ b/History.rdoc
@@ -1,3 +1,68 @@
+=== 4.4.1 / 2016-12-02
+
+* Fix #36 - Warning about MissingSourceFile (@fallwith)
+* Fix build on Ruby 1.9
+
+=== 4.4.0 / 2016-02-19
+
+* Add modular style template initialization. (@lebogan)
+* Allow option names that start with a global option name.
+* Fix handling of negatable global flags. (@mfurtak)
+
+=== 4.3.8 / 2016-02-09
+
+* Fix regression for deprecation warnings.
+
+=== 4.3.7 / 2016-01-26
+
+* Fix regression in help formatter introduced in 4.3.6.
+
+=== 4.3.6 / 2016-01-26 [YANKED]
+
+* Fix deprecation warnings on Ruby 2.3.0.
+* Indent option descriptions the same way as program and command descriptions. (@badeball)
+
+=== 4.3.5 / 2015-08-09
+
+* Fixed a bug with small terminal widths, changed minimum screen width for wrapping to 40 columns. (@toolmantim)
+
+=== 4.3.4 / 2015-05-03
+
+* Fixed a regression with the compact help formatter.
+
+=== 4.3.3 / 2015-04-21
+
+* Updated to highline 1.7.2 to fix a regression with terminal size (https://github.com/JEG2/highline/pull/139).
+* Help formatting updated to look better for commands with long names. (@jszwedko)
+
+=== 4.3.2 / 2015-03-31
+
+* Version bump to publish new location of Commander to Rubygems. Moved to https://github.com/commander-rb/commander
+
+=== 4.3.1 / 2015-03-27
+
+* Fix various Ruby warnings for circular requires, etc.
+* Update to use highline 1.7 (@SkyTrix)
+
+=== 4.3.0 / 2015-02-07
+
+* Drops support for Ruby 1.8. Please use 4.2.1 if you still need Ruby 1.8 compatibility.
+* Fixed a bug with `always_trace` (#91) (@KrauseFx)
+* Renamed `commands` to `defined_commands` for better compatibility with Pry
+
+=== 4.2.1 / 2014-09-28
+
+* Improve `choose` compatibility with HighLine's version (#79)
+
+=== 4.2.0 / 2014-04-29
+
+* Add ability to use commander without importing into the global namespace (#61) (@krissi)
+
+=== 4.1.6 / 2014-02-11
+
+* Respect environment setting for $LESS (@ellemenno)
+* Add ability to hide trace flags and globally enable tracing (#16, #17) (@jamesrwhite)
+
 === 4.1.5 / 2013-08-11
 
 * Prevent deprecation warning when loaded in a Rails 4 environment (#58)
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..02caa4d
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2008-2013 TJ Holowaychuk <tj at 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.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d47d804
--- /dev/null
+++ b/README.md
@@ -0,0 +1,460 @@
+[<img src="https://secure.travis-ci.org/commander-rb/commander.png?branch=master" alt="Build Status" />](http://travis-ci.org/commander-rb/commander)
+[![Inline docs](http://inch-ci.org/github/commander-rb/commander.png)](http://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 http://github.com/tj/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.
+
+```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 <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:
+
+```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
+```
+
+### Additional Global Help
+
+Arbitrary help can be added using the following `#program` symbol:
+
+```ruby
+program :help, 'Author', 'TJ Holowaychuk <tj at vision-media.ca>'
+```
+
+Which will output the rest of the help doc, along with:
+
+    AUTHOR:
+
+      TJ Holowaychuk <tj at 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:
+
+```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 http://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
+http://github.com/commander-rb/commander/issues
+
+## License
+
+This project is available under the MIT license. See LICENSE for details.
diff --git a/README.rdoc b/README.rdoc
deleted file mode 100644
index 373047d..0000000
--- a/README.rdoc
+++ /dev/null
@@ -1,372 +0,0 @@
-{<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 at vision-media.ca>'
-
-Which will output the rest of the help doc, along with:
-
-  AUTHOR:
-
-    TJ Holowaychuk <tj at 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 at 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.
diff --git a/Rakefile b/Rakefile
index 0d2bb42..33bbf85 100644
--- a/Rakefile
+++ b/Rakefile
@@ -1,10 +1,13 @@
-require "rspec/core/rake_task"
-require "bundler/gem_tasks"
+require 'bundler/gem_tasks'
+require 'rspec/core/rake_task'
+require 'rubocop/rake_task'
 
-desc "Run specs"
+desc 'Run specs'
 RSpec::Core::RakeTask.new do |t|
   t.verbose = false
   t.rspec_opts = '--color --order random'
 end
 
-task :default => :spec
+RuboCop::RakeTask.new
+
+task default: [:spec, :rubocop]
diff --git a/bin/commander b/bin/commander
index 393daec..faaf322 100755
--- a/bin/commander
+++ b/bin/commander
@@ -8,30 +8,78 @@ program :version, Commander::VERSION
 program :description, 'Commander utility program.'
 
 command :init do |c|
-  c.syntax = 'commander init <file>'
+  c.syntax = 'commander init [option] <file>'
   c.summary = 'Initialize a commander template'
-  c.description = 'Initialize an empty <file> with a commander template, 
+  c.description = 'Initialize an empty <file> with a commander template,
     allowing very quick creation of commander executables.'
-  c.example 'Create a new file with a commander template.', 'commander init bin/my_executable'
+  c.example 'Create a new classic style template file.', 'commander init bin/my_executable'
+  c.example 'Create a new modular style template file.', 'commander init --modular bin/my_executable'
+  c.option '-m', '--modular', 'Initialize a modular style template'
   c.action do |args, options|
     file = args.shift || abort('file argument required.')
     name = ask 'Machine name of program: '
     description = ask 'Describe your program: '
     commands = ask_for_array 'List the commands you wish to create: '
     begin
-      File.open(file, 'w') do |f|
-        f.write <<-"...".gsub!(/^ {10}/, '')
+      if options.modular
+        File.open(file, 'w') do |f|
+          f.write <<-"...".gsub!(/^ {10}/, '')
           #!/usr/bin/env ruby
-          
+
+          require 'rubygems'
+          require 'commander'
+
+          class MyApplication
+            include Commander::Methods
+            # include whatever modules you need
+
+            def run
+              program :name, '#{name}'
+              program :version, '0.0.1'
+              program :description, '#{description}'
+
+          ...
+          commands.each do |command|
+            f.write <<-"...".gsub!(/^ {12}/, '')
+                command :#{command} do |c|
+                  c.syntax = '#{name} #{command} [options]'
+                  c.summary = ''
+                  c.description = ''
+                  c.example 'description', 'command example'
+                  c.option '--some-switch', 'Some switch that does something'
+                  c.action do |args, options|
+                    # Do something or c.when_called #{name.capitalize}::Commands::#{command.capitalize}
+                  end
+                end
+
+            ...
+          end
+          f.write <<-"...".gsub!(/^ {12}/, '')
+                run!
+              end
+            end
+
+            MyApplication.new.run if $0 == __FILE__
+          ...
+        end
+
+        File.chmod(0755, file)
+        say "Initialized modular template in #{file}"
+      else
+        File.open(file, 'w') do |f|
+          f.write <<-"...".gsub!(/^ {10}/, '')
+          #!/usr/bin/env ruby
+
           require 'rubygems'
           require 'commander/import'
-          
+
+          program :name, '#{name}'
           program :version, '0.0.1'
           program :description, '#{description}'
-           
-        ...
-        commands.each do |command|
-          f.write <<-"...".gsub!(/^ {12}/, '')
+
+          ...
+          commands.each do |command|
+            f.write <<-"...".gsub!(/^ {12}/, '')
             command :#{command} do |c|
               c.syntax = '#{name} #{command} [options]'
               c.summary = ''
@@ -43,13 +91,14 @@ command :init do |c|
               end
             end
 
-          ...
+            ...
+          end
         end
-       end
-       File.chmod 0755, file
-       say "Initialized template in #{file}"
-     rescue Exception => e
-       abort e
-     end
+        File.chmod 0755, file
+        say "Initialized template in #{file}"
+      end
+    rescue => e
+      abort e
+    end
   end
-end
\ No newline at end of file
+end
diff --git a/commander.gemspec b/commander.gemspec
index 15cbb35..1990387 100644
--- a/commander.gemspec
+++ b/commander.gemspec
@@ -1,26 +1,29 @@
 # -*- encoding: utf-8 -*-
-$:.push File.expand_path("../lib", __FILE__)
-require "commander/version"
+$LOAD_PATH.push File.expand_path('../lib', __FILE__)
+require 'commander/version'
 
 Gem::Specification.new do |s|
-  s.name        = "commander"
+  s.name        = 'commander'
   s.version     = Commander::VERSION
-  s.authors     = ["TJ Holowaychuk", "Gabriel Gilder"]
-  s.email       = ["ggilder at tractionco.com"]
-  s.homepage    = "http://visionmedia.github.com/commander"
-  s.summary     = "The complete solution for Ruby command-line executables"
-  s.description = "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."
-
-  s.rubyforge_project = "commander"
+  s.authors     = ['TJ Holowaychuk', 'Gabriel Gilder']
+  s.email       = ['gabriel at gabrielgilder.com']
+  s.license     = 'MIT'
+  s.homepage    = 'https://github.com/commander-rb/commander'
+  s.summary     = 'The complete solution for Ruby command-line executables'
+  s.description = '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.'
 
   s.files         = `git ls-files`.split("\n")
   s.test_files    = `git ls-files -- {test,spec,features}/*`.split("\n")
-  s.executables   = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
-  s.require_paths = ["lib"]
+  s.executables   = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
+  s.require_paths = ['lib']
+
+  s.add_runtime_dependency('highline', '~> 1.7.2')
 
-  s.add_runtime_dependency("highline", "~> 1.6.11")
-  
-  s.add_development_dependency("rspec", "~> 2")
-  s.add_development_dependency("rake")
-  s.add_development_dependency("simplecov")
-end
\ No newline at end of file
+  s.add_development_dependency('rspec', '~> 3.2')
+  s.add_development_dependency('rake')
+  s.add_development_dependency('simplecov')
+  s.add_development_dependency('rubocop', '~> 0.29.1')
+  if RUBY_VERSION < '2.0'
+    s.add_development_dependency('json', '< 2.0')
+  end
+end
diff --git a/lib/commander.rb b/lib/commander.rb
index ee93f7b..b0decd6 100644
--- a/lib/commander.rb
+++ b/lib/commander.rb
@@ -30,3 +30,6 @@ require 'commander/runner'
 require 'commander/command'
 require 'commander/help_formatters'
 require 'commander/platform'
+require 'commander/delegates'
+require 'commander/methods'
+require 'commander/configure'
diff --git a/lib/commander/blank.rb b/lib/commander/blank.rb
index 68e764d..07164a4 100644
--- a/lib/commander/blank.rb
+++ b/lib/commander/blank.rb
@@ -1,8 +1,7 @@
-
 module Blank
-  def self.included base
+  def self.included(base)
     base.class_eval do
       instance_methods.each { |m| undef_method m unless m =~ /^__|object_id/ }
     end
   end
-end
\ No newline at end of file
+end
diff --git a/lib/commander/command.rb b/lib/commander/command.rb
index 7a76d54..fb15816 100644
--- a/lib/commander/command.rb
+++ b/lib/commander/command.rb
@@ -1,47 +1,45 @@
-
 require 'optparse'
 
 module Commander
   class Command
-    
     attr_accessor :name, :examples, :syntax, :description
     attr_accessor :summary, :proxy_options, :options
-    
+
     ##
     # Options struct.
 
     class Options
       include Blank
-      
+
       def initialize
         @table = {}
       end
-      
+
       def __hash__
         @table
       end
-      
-      def method_missing meth, *args, &block
+
+      def method_missing(meth, *args)
         meth.to_s =~ /=$/ ? @table[meth.to_s.chop.to_sym] = args.first : @table[meth]
       end
-      
-      def default defaults = {}
+
+      def default(defaults = {})
         @table = defaults.merge! @table
       end
-      
+
       def inspect
-        "<Commander::Command::Options #{ __hash__.map { |k,v| "#{k}=#{v.inspect}" }.join(', ') }>"
+        "<Commander::Command::Options #{ __hash__.map { |k, v| "#{k}=#{v.inspect}" }.join(', ') }>"
       end
     end
-        
+
     ##
     # Initialize new command with specified _name_.
-    
-    def initialize name
+
+    def initialize(name)
       @name, @examples, @when_called = name.to_s, [], []
       @options, @proxy_options = [], []
     end
-    
+
     ##
     # Add a usage example for this command.
     #
@@ -49,22 +47,22 @@ module Commander
     # created by the help formatters.
     #
     # === Examples
-    #    
+    #
     #   command :something do |c|
     #     c.example "Should do something", "my_command something"
     #   end
     #
-    
-    def example description, command 
+
+    def example(description, command)
       @examples << [description, command]
     end
-    
+
     ##
     # Add an option.
     #
     # Options are parsed via OptionParser so view it
     # for additional usage documentation. A block may optionally be
-    # passed to handle the option, otherwise the _options_ struct seen below 
+    # passed to handle the option, otherwise the _options_ struct seen below
     # contains the results of this option. This handles common formats such as:
     #
     #   -h, --help          options.help           # => bool
@@ -75,18 +73,18 @@ module Commander
     #   --date [DATE]       options.date           # => date or nil when optional argument not set
     #
     # === Examples
-    #    
+    #
     #   command :something do |c|
     #     c.option '--recursive', 'Do something recursively'
     #     c.option '--file FILE', 'Specify a file'
     #     c.option('--info', 'Display info') { puts "handle with block" }
     #     c.option '--[no-]feature', 'With or without feature'
     #     c.option '--list FILES', Array, 'List the files specified'
-    #   
+    #
     #     c.when_called do |args, options|
     #       do_something_recursively if options.recursive
     #       do_something_with_file options.file if options.file
-    #     end 
+    #     end
     #   end
     #
     # === Help Formatters
@@ -105,109 +103,108 @@ module Commander
     #   c.option '--time TIME', Time
     #   c.option '--date [DATE]', Date
     #
-    
-    def option *args, &block
+
+    def option(*args, &block)
       switches, description = Runner.separate_switches_from_description(*args)
       proc = block || option_proc(switches)
       @options << {
-        :args => args,
-        :proc => proc,
-        :switches => switches,
-        :description => description,
+        args: args,
+        proc: proc,
+        switches: switches,
+        description: description,
       }
     end
-    
+
     ##
-    # Handle execution of command. The handler may be a class, 
+    # Handle execution of command. The handler may be a class,
     # object, or block (see examples below).
     #
     # === Examples
-    #    
+    #
     #   # Simple block handling
     #   c.when_called do |args, options|
     #      # do something
-    #   end 
-    #   
+    #   end
+    #
     #   # Create inst of Something and pass args / options
     #   c.when_called MyLib::Command::Something
-    #   
+    #
     #   # Create inst of Something and use arbitrary method
     #    c.when_called MyLib::Command::Something, :some_method
-    #   
+    #
     #   # Pass an object to handle callback (requires method symbol)
     #   c.when_called SomeObject, :some_method
     #
-    
-    def when_called *args, &block
-      raise ArgumentError, 'must pass an object, class, or block.' if args.empty? and !block
+
+    def when_called(*args, &block)
+      fail ArgumentError, 'must pass an object, class, or block.' if args.empty? && !block
       @when_called = block ? [block] : args
     end
-    alias :action :when_called
-    
+    alias_method :action, :when_called
+
     ##
     # Run the command with _args_.
     #
     # * parses options, call option blocks
     # * invokes when_called proc
     #
-    
-    def run *args
+
+    def run(*args)
       call parse_options_and_call_procs(*args)
     end
-    
+
     #:stopdoc:
-    
+
     ##
-    # Parses options and calls associated procs, 
+    # Parses options and calls associated procs,
     # returning the arguments remaining.
-    
-    def parse_options_and_call_procs *args
+
+    def parse_options_and_call_procs(*args)
       return args if args.empty?
-      @options.inject OptionParser.new do |opts, option| 
+      @options.each_with_object(OptionParser.new) do |option, opts|
         opts.on(*option[:args], &option[:proc])
         opts
       end.parse! args
     end
-    
+
     ##
     # Call the commands when_called block with _args_.
-    
-    def call args = []
+
+    def call(args = [])
       object = @when_called.shift
       meth = @when_called.shift || :call
       options = proxy_option_struct
       case object
-      when Proc  ; object.call(args, options)
-      when Class ; meth != :call ? object.new.send(meth, args, options) : object.new(args, options)
-      else         object.send(meth, args, options) if object
-      end 
+      when Proc then object.call(args, options)
+      when Class then meth != :call ? object.new.send(meth, args, options) : object.new(args, options)
+      else object.send(meth, args, options) if object
+      end
     end
-    
+
     ##
     # Creates an Options instance populated with the option values
     # collected by the #option_proc.
-    
+
     def proxy_option_struct
-      proxy_options.inject Options.new do |options, (option, value)|
+      proxy_options.each_with_object(Options.new) do |(option, value), options|
         # options that are present will evaluate to true
         value = true if value.nil?
         options.__send__ :"#{option}=", value
         options
       end
     end
-    
+
     ##
     # Option proxy proc used when a block is not explicitly passed
     # via the #option method. This allows commander to auto-populate
     # and work with option values.
-    
-    def option_proc switches
-      lambda { |value| proxy_options << [Runner.switch_to_sym(switches.last), value] } 
+
+    def option_proc(switches)
+      ->(value) { proxy_options << [Runner.switch_to_sym(switches.last), value] }
     end
-    
-    def inspect 
+
+    def inspect
       "<Commander::Command:#{name}>"
     end
-    
   end
-end
\ No newline at end of file
+end
diff --git a/lib/commander/configure.rb b/lib/commander/configure.rb
new file mode 100644
index 0000000..eaefe25
--- /dev/null
+++ b/lib/commander/configure.rb
@@ -0,0 +1,14 @@
+module Commander
+  def configure(*configuration_opts, &configuration_block)
+    configuration_module = Module.new
+    configuration_module.extend Commander::Methods
+
+    configuration_module.class_exec(*configuration_opts, &configuration_block)
+
+    configuration_module.class_exec do
+      run!
+    end
+  end
+
+  module_function :configure
+end
diff --git a/lib/commander/core_ext.rb b/lib/commander/core_ext.rb
index 016f323..d1d9a8d 100644
--- a/lib/commander/core_ext.rb
+++ b/lib/commander/core_ext.rb
@@ -1,3 +1,2 @@
-
 require 'commander/core_ext/array'
-require 'commander/core_ext/object'
\ No newline at end of file
+require 'commander/core_ext/object'
diff --git a/lib/commander/core_ext/array.rb b/lib/commander/core_ext/array.rb
index 80ac3b7..daf765a 100644
--- a/lib/commander/core_ext/array.rb
+++ b/lib/commander/core_ext/array.rb
@@ -1,6 +1,4 @@
-
 class Array
-
   ##
   # Split _string_ into an array. Used in
   # conjunction with Highline's #ask, or #ask_for_array
@@ -18,9 +16,9 @@ class Array
   #   list = ask_for_array 'Favorite cookies: '
   #
 
-  def self.parse string
+  def self.parse(string)
     # Using reverse + lookahead to work around Ruby 1.8's lack of lookbehind
+    # TODO: simplify now that we don't support Ruby 1.8
     string.reverse.split(/\s(?!\\)/).reverse.map { |s| s.reverse.gsub('\\ ', ' ') }
   end
-
 end
diff --git a/lib/commander/core_ext/object.rb b/lib/commander/core_ext/object.rb
index 9d33f16..7319de6 100644
--- a/lib/commander/core_ext/object.rb
+++ b/lib/commander/core_ext/object.rb
@@ -1,11 +1,8 @@
-
 class Object
-
   ##
   # Return the current binding.
-  
+
   def get_binding
     binding
   end
-
 end
diff --git a/lib/commander/delegates.rb b/lib/commander/delegates.rb
index f069ad5..8071803 100644
--- a/lib/commander/delegates.rb
+++ b/lib/commander/delegates.rb
@@ -1,13 +1,25 @@
-
 module Commander
   module Delegates
-    %w( add_command command program run! global_option 
-        commands alias_command default_command ).each do |meth|
+    %w(
+      add_command
+      command
+      program
+      run!
+      global_option
+      alias_command
+      default_command
+      always_trace!
+      never_trace!
+    ).each do |meth|
       eval <<-END, binding, __FILE__, __LINE__
-        def #{meth} *args, &block
-          ::Commander::Runner.instance.#{meth} *args, &block
+        def #{meth}(*args, &block)
+          ::Commander::Runner.instance.#{meth}(*args, &block)
         end
       END
     end
+
+    def defined_commands(*args, &block)
+      ::Commander::Runner.instance.commands(*args, &block)
+    end
   end
-end
\ No newline at end of file
+end
diff --git a/lib/commander/help_formatters.rb b/lib/commander/help_formatters.rb
index 00a23ff..95c9d24 100644
--- a/lib/commander/help_formatters.rb
+++ b/lib/commander/help_formatters.rb
@@ -1,13 +1,49 @@
-
 module Commander
   module HelpFormatter
     autoload :Base, 'commander/help_formatters/base'
     autoload :Terminal, 'commander/help_formatters/terminal'
     autoload :TerminalCompact, 'commander/help_formatters/terminal_compact'
 
+    class Context
+      def initialize(target)
+        @target = target
+      end
+
+      def get_binding
+        @target.instance_eval { binding }.tap do |bind|
+          decorate_binding(bind)
+        end
+      end
+
+      # No-op, override in subclasses.
+      def decorate_binding(_bind)
+      end
+    end
+
+    class ProgramContext < Context
+      def decorate_binding(bind)
+        bind.eval("max_command_length = #{max_command_length(bind)}")
+        bind.eval("max_aliases_length = #{max_aliases_length(bind)}")
+      end
+
+      def max_command_length(bind)
+        max_key_length(bind.eval('@commands'))
+      end
+
+      def max_aliases_length(bind)
+        max_key_length(bind.eval('@aliases'))
+      end
+
+      def max_key_length(hash, default = 20)
+        longest = hash.keys.max_by(&:size)
+        longest ? longest.size : default
+      end
+    end
+
     module_function
-    def indent amount, text
-      text.gsub("\n", "\n" + (' ' * amount))
+
+    def indent(amount, text)
+      text.to_s.gsub("\n", "\n" + (' ' * amount))
     end
   end
 end
diff --git a/lib/commander/help_formatters/base.rb b/lib/commander/help_formatters/base.rb
index 59d120f..9227904 100644
--- a/lib/commander/help_formatters/base.rb
+++ b/lib/commander/help_formatters/base.rb
@@ -1,18 +1,24 @@
-
 module Commander
-  
   ##
   # = Help Formatter
   #
   # Commander's help formatters control the output when
   # either the help command, or --help switch are called.
   # The default formatter is Commander::HelpFormatter::Terminal.
-  
+
   module HelpFormatter
-    class Base 
-      def initialize runner; @runner = runner  end
-      def render; 'Implement global help here' end
-      def render_command command; "Implement help for #{command.name} here" end
+    class Base
+      def initialize(runner)
+        @runner = runner
+      end
+
+      def render
+        'Implement global help here'
+      end
+
+      def render_command(command)
+        "Implement help for #{command.name} here"
+      end
     end
   end
-end
\ No newline at end of file
+end
diff --git a/lib/commander/help_formatters/terminal.rb b/lib/commander/help_formatters/terminal.rb
index 743469f..fb6ecf0 100644
--- a/lib/commander/help_formatters/terminal.rb
+++ b/lib/commander/help_formatters/terminal.rb
@@ -1,20 +1,19 @@
-
 require 'erb'
 
 module Commander
   module HelpFormatter
     class Terminal < Base
       def render
-        template(:help).result @runner.get_binding
+        template(:help).result(ProgramContext.new(@runner).get_binding)
       end
-      
-      def render_command command
-        template(:command_help).result command.get_binding
+
+      def render_command(command)
+        template(:command_help).result(Context.new(command).get_binding)
       end
-      
-      def template name
+
+      def template(name)
         ERB.new(File.read(File.join(File.dirname(__FILE__), 'terminal', "#{name}.erb")), nil, '-')
       end
     end
   end
-end
\ No newline at end of file
+end
diff --git a/lib/commander/help_formatters/terminal/command_help.erb b/lib/commander/help_formatters/terminal/command_help.erb
index 19b58df..2635907 100644
--- a/lib/commander/help_formatters/terminal/command_help.erb
+++ b/lib/commander/help_formatters/terminal/command_help.erb
@@ -29,7 +29,7 @@
 	<% for option in @options -%>
 
     <%= option[:switches].join ', ' %> 
-        <%= option[:description] %>
+        <%= Commander::HelpFormatter.indent 8, option[:description] %>
 	<% end -%>
 <% end -%>
 
diff --git a/lib/commander/help_formatters/terminal/help.erb b/lib/commander/help_formatters/terminal/help.erb
index 32b153a..7386531 100644
--- a/lib/commander/help_formatters/terminal/help.erb
+++ b/lib/commander/help_formatters/terminal/help.erb
@@ -9,13 +9,13 @@
   <%= $terminal.color "COMMANDS", :bold %>:
 <% for name, command in @commands.sort -%>
 	<% unless alias? name %>
-    <%= "%-20s %s" % [command.name, command.summary || command.description] -%>
+    <%= "%-#{max_command_length}s %s" % [command.name, command.summary || command.description] -%>
 	<% end -%>
 <% end %>
 <% unless @aliases.empty? %>
   <%= $terminal.color "ALIASES", :bold %>:
   <% for alias_name, args in @aliases.sort %>
-    <%= "%-20s %s %s" % [alias_name, command(alias_name).name, args.join(' ')] -%>
+    <%= "%-#{max_aliases_length}s %s %s" % [alias_name, command(alias_name).name, args.join(' ')] -%>
   <% end %>
 <% end %>
 <% unless @options.empty? -%>
diff --git a/lib/commander/help_formatters/terminal_compact.rb b/lib/commander/help_formatters/terminal_compact.rb
index 27f1e0b..88d77ca 100644
--- a/lib/commander/help_formatters/terminal_compact.rb
+++ b/lib/commander/help_formatters/terminal_compact.rb
@@ -1,12 +1,11 @@
-
 require 'erb'
 
 module Commander
   module HelpFormatter
     class TerminalCompact < Terminal
-      def template name
+      def template(name)
         ERB.new(File.read(File.join(File.dirname(__FILE__), 'terminal_compact', "#{name}.erb")), nil, '-')
       end
     end
   end
-end
\ No newline at end of file
+end
diff --git a/lib/commander/help_formatters/terminal_compact/help.erb b/lib/commander/help_formatters/terminal_compact/help.erb
index 7d5f1da..a01a432 100644
--- a/lib/commander/help_formatters/terminal_compact/help.erb
+++ b/lib/commander/help_formatters/terminal_compact/help.erb
@@ -5,13 +5,13 @@
   Commands:
 <% for name, command in @commands.sort -%>
 <% unless alias? name -%>
-    <%= "%-20s %s" % [command.name, command.summary || command.description] %>
+    <%= "%-#{max_command_length}s %s" % [command.name, command.summary || command.description] %>
 <% end -%>
 <% end -%>
 <% unless @aliases.empty? %>
   Aliases:
 <% for alias_name, args in @aliases.sort -%>
-    <%= "%-20s %s %s" % [alias_name, command(alias_name).name, args.join(' ')] %>
+    <%= "%-#{max_aliases_length}s %s %s" % [alias_name, command(alias_name).name, args.join(' ')] %>
 <% end -%>
 <% end %>
 <% unless @options.empty? -%>
diff --git a/lib/commander/import.rb b/lib/commander/import.rb
index dab5efe..e2e846d 100644
--- a/lib/commander/import.rb
+++ b/lib/commander/import.rb
@@ -1,10 +1,5 @@
-
 require 'commander'
-require 'commander/delegates'
 
-include Commander::UI
-include Commander::UI::AskForClass
-include Commander::Delegates
+include Commander::Methods
 
-$terminal.wrap_at = HighLine::SystemExtensions.terminal_size.first - 5 rescue 80 if $stdin.tty?
 at_exit { run! }
diff --git a/lib/commander/methods.rb b/lib/commander/methods.rb
new file mode 100644
index 0000000..a9f2387
--- /dev/null
+++ b/lib/commander/methods.rb
@@ -0,0 +1,11 @@
+module Commander
+  module Methods
+    include Commander::UI
+    include Commander::UI::AskForClass
+    include Commander::Delegates
+
+    if $stdin.tty? && (cols = $terminal.output_cols) >= 40
+      $terminal.wrap_at = cols - 5
+    end
+  end
+end
diff --git a/lib/commander/platform.rb b/lib/commander/platform.rb
index e39f8b1..47eb827 100644
--- a/lib/commander/platform.rb
+++ b/lib/commander/platform.rb
@@ -1,4 +1,3 @@
-
 module Commander
   module Platform
     def self.jruby?
diff --git a/lib/commander/runner.rb b/lib/commander/runner.rb
index 64d644e..1d90d5f 100644
--- a/lib/commander/runner.rb
+++ b/lib/commander/runner.rb
@@ -1,96 +1,119 @@
-
 require 'optparse'
 
 module Commander
   class Runner
-    
     #--
     # Exceptions
     #++
 
     class CommandError < StandardError; end
     class InvalidCommandError < CommandError; end
-    
+
     ##
     # Array of commands.
-    
+
     attr_reader :commands
-    
+
     ##
     # Global options.
-    
+
     attr_reader :options
-    
+
     ##
     # Hash of help formatter aliases.
-    
+
     attr_reader :help_formatter_aliases
 
     ##
     # Initialize a new command runner. Optionally
     # supplying _args_ for mocking, or arbitrary usage.
-    
-    def initialize args = ARGV
+
+    def initialize(args = ARGV)
       @args, @commands, @aliases, @options = args, {}, {}, []
       @help_formatter_aliases = help_formatter_alias_defaults
       @program = program_defaults
+      @always_trace = false
+      @never_trace = false
       create_default_commands
     end
-    
+
     ##
     # Return singleton Runner instance.
-    
+
     def self.instance
       @singleton ||= new
     end
-    
+
     ##
     # Run command parsing and execution process.
-    
+
     def run!
-      trace = false
+      trace = @always_trace || false
       require_program :version, :description
       trap('INT') { abort program(:int_message) } if program(:int_message)
       trap('INT') { program(:int_block).call } if program(:int_block)
       global_option('-h', '--help', 'Display help documentation') do
-        args = @args - %w[-h --help]
+        args = @args - %w(-h --help)
         command(:help).run(*args)
         return
       end
-      global_option('-v', '--version', 'Display version information') { say version; return } 
-      global_option('-t', '--trace', 'Display backtrace when an error occurs') { trace = true }
+      global_option('-v', '--version', 'Display version information') do
+        say version
+        return
+      end
+      global_option('-t', '--trace', 'Display backtrace when an error occurs') { trace = true } unless @never_trace || @always_trace
       parse_global_options
       remove_global_options options, @args
-      unless trace
+      if trace
+        run_active_command
+      else
         begin
           run_active_command
         rescue InvalidCommandError => e
           abort "#{e}. Use --help for more information"
         rescue \
-          OptionParser::InvalidOption, 
+          OptionParser::InvalidOption,
           OptionParser::InvalidArgument,
           OptionParser::MissingArgument => e
           abort e.to_s
         rescue => e
-          abort "error: #{e}. Use --trace to view backtrace"
+          if @never_trace
+            abort "error: #{e}."
+          else
+            abort "error: #{e}. Use --trace to view backtrace"
+          end
         end
-      else
-        run_active_command
       end
     end
-    
+
     ##
     # Return program version.
-    
+
     def version
-      '%s %s' % [program(:name), program(:version)]
+      format('%s %s', program(:name), program(:version))
     end
-    
+
+    ##
+    # Enable tracing on all executions (bypasses --trace)
+
+    def always_trace!
+      @always_trace = true
+      @never_trace = false
+    end
+
+    ##
+    # Hide the trace option from the help menus and don't add it as a global option
+
+    def never_trace!
+      @never_trace = true
+      @always_trace = false
+    end
+
     ##
     # Assign program information.
     #
     # === Examples
-    #    
+    #
     #   # Set data
     #   program :name, 'Commander'
     #   program :version, Commander::VERSION
@@ -100,7 +123,7 @@ module Commander
     #   program :int_message 'Bye bye!'
     #   program :help_formatter, :compact
     #   program :help_formatter, Commander::HelpFormatter::TerminalCompact
-    #   
+    #
     #   # Get data
     #   program :name # => 'Commander'
     #
@@ -113,9 +136,9 @@ module Commander
     #   :help            Allows addition of arbitrary global help blocks
     #   :int_message     Message to display when interrupted (CTRL + C)
     #
-    
-    def program key, *args, &block
-      if key == :help and !args.empty?
+
+    def program(key, *args, &block)
+      if key == :help && !args.empty?
         @program[:help] ||= {}
         @program[:help][args.first] = args.at(1)
       elsif key == :help_formatter && !args.empty?
@@ -129,150 +152,154 @@ module Commander
         @program[key]
       end
     end
-    
+
     ##
     # Creates and yields a command instance when a block is passed.
     # Otherwise attempts to return the command, raising InvalidCommandError when
     # it does not exist.
     #
     # === Examples
-    #    
+    #
     #   command :my_command do |c|
     #     c.when_called do |args|
     #       # Code
     #     end
     #   end
     #
-    
-    def command name, &block
+
+    def command(name, &block)
       yield add_command(Commander::Command.new(name)) if block
       @commands[name.to_s]
     end
-    
+
     ##
     # Add a global option; follows the same syntax as Command#option
     # This would be used for switches such as --version, --trace, etc.
-    
-    def global_option *args, &block
-      switches, description = Runner.separate_switches_from_description *args
+
+    def global_option(*args, &block)
+      switches, description = Runner.separate_switches_from_description(*args)
       @options << {
-        :args => args,
-        :proc => block,
-        :switches => switches,
-        :description => description,
+        args: args,
+        proc: block,
+        switches: switches,
+        description: description,
       }
     end
-    
+
     ##
     # Alias command _name_ with _alias_name_. Optionally _args_ may be passed
     # as if they were being passed straight to the original command via the command-line.
-    
-    def alias_command alias_name, name, *args
+
+    def alias_command(alias_name, name, *args)
       @commands[alias_name.to_s] = command name
       @aliases[alias_name.to_s] = args
     end
-    
+
     ##
     # Default command _name_ to be used when no other
     # command is found in the arguments.
-    
-    def default_command name
+
+    def default_command(name)
       @default_command = name
     end
-    
+
     ##
     # Add a command object to this runner.
-    
-    def add_command command
+
+    def add_command(command)
       @commands[command.name] = command
     end
-    
+
     ##
     # Check if command _name_ is an alias.
-    
-    def alias? name
+
+    def alias?(name)
       @aliases.include? name.to_s
     end
-    
+
     ##
     # Check if a command _name_ exists.
-    
-    def command_exists? name
+
+    def command_exists?(name)
       @commands[name.to_s]
     end
-    
+
     #:stopdoc:
-    
+
     ##
     # Get active command within arguments passed to this runner.
-    
+
     def active_command
       @__active_command ||= command(command_name_from_args)
     end
-    
+
     ##
     # Attempts to locate a command name from within the arguments.
     # Supports multi-word commands, using the largest possible match.
-    
+
     def command_name_from_args
       @__command_name_from_args ||= (valid_command_names_from(*@args.dup).sort.last || @default_command)
     end
-    
+
     ##
     # Returns array of valid command names found within _args_.
-    
-    def valid_command_names_from *args
+
+    def valid_command_names_from(*args)
       arg_string = args.delete_if { |value| value =~ /^-/ }.join ' '
       commands.keys.find_all { |name| name if /^#{name}\b/.match arg_string }
     end
-    
+
     ##
     # Help formatter instance.
-    
+
     def help_formatter
       @__help_formatter ||= program(:help_formatter).new self
     end
-    
+
     ##
     # Return arguments without the command name.
-    
+
     def args_without_command_name
       removed = []
       parts = command_name_from_args.split rescue []
       @args.dup.delete_if do |arg|
-        removed << arg if parts.include?(arg) and not removed.include?(arg)
+        removed << arg if parts.include?(arg) && !removed.include?(arg)
       end
     end
-    
+
     ##
     # Returns hash of help formatter alias defaults.
-    
+
     def help_formatter_alias_defaults
-      return :compact => HelpFormatter::TerminalCompact
+      {
+        compact: HelpFormatter::TerminalCompact,
+      }
     end
-    
+
     ##
     # Returns hash of program defaults.
-    
+
     def program_defaults
-      return :help_formatter => HelpFormatter::Terminal, 
-             :name => File.basename($0)
+      {
+        help_formatter: HelpFormatter::Terminal,
+        name: File.basename($PROGRAM_NAME),
+      }
     end
-    
+
     ##
-    # Creates default commands such as 'help' which is 
+    # Creates default commands such as 'help' which is
     # essentially the same as using the --help switch.
-    
+
     def create_default_commands
       command :help do |c|
         c.syntax = 'commander help [command]'
-        c.description = 'Display global or [command] help documentation.'
+        c.description = 'Display global or [command] help documentation'
         c.example 'Display global help', 'command help'
         c.example "Display help for 'foo'", 'command help foo'
-        c.when_called do |args, options|
-          enable_paging
+        c.when_called do |args, _options|
+          UI.enable_paging
           if args.empty?
-            say help_formatter.render 
+            say help_formatter.render
           else
             command = command args.join(' ')
             begin
@@ -285,33 +312,35 @@ module Commander
         end
       end
     end
-    
+
     ##
     # Raises InvalidCommandError when a _command_ is not found.
-    
-    def require_valid_command command = active_command
-      raise InvalidCommandError, 'invalid command', caller if command.nil?
+
+    def require_valid_command(command = active_command)
+      fail InvalidCommandError, 'invalid command', caller if command.nil?
     end
-    
+
     ##
     # Removes global _options_ from _args_. This prevents an invalid
     # option error from occurring when options are parsed
     # again for the command.
-    
-    def remove_global_options options, args
+
+    def remove_global_options(options, args)
       # TODO: refactor with flipflop, please TJ ! have time to refactor me !
       options.each do |option|
         switches = option[:switches].dup
         next if switches.empty?
 
-        if switchHasArg = switches.any? { |s| s =~ /[ =]/ }
+        if (switch_has_arg = switches.any? { |s| s =~ /[ =]/ })
           switches.map! { |s| s[0, s.index('=') || s.index(' ') || s.length] }
         end
 
+        switches = expand_optionally_negative_switches(switches)
+
         past_switch, arg_removed = false, false
         args.delete_if do |arg|
-          if switches.any? { |s| arg[0, s.length] == s }
-            arg_removed = !switchHasArg
+          if switches.any? { |s| s[0, arg.length] == arg }
+            arg_removed = !switch_has_arg
             past_switch = true
           elsif past_switch && !arg_removed && arg !~ /^-/
             arg_removed = true
@@ -322,14 +351,27 @@ module Commander
         end
       end
     end
-            
+
+    # expand switches of the style '--[no-]blah' into both their
+    # '--blah' and '--no-blah' variants, so that they can be
+    # properly detected and removed
+    def expand_optionally_negative_switches(switches)
+      switches.reduce([]) do |memo, val|
+        if val =~ /\[no-\]/
+          memo << val.gsub(/\[no-\]/, '')
+          memo << val.gsub(/\[no-\]/, 'no-')
+        else
+          memo << val
+        end
+      end
+    end
+
     ##
     # Parse global command options.
-    
-    def parse_global_options
 
+    def parse_global_options
       parser = options.inject(OptionParser.new) do |options, option|
-        options.on *option[:args], &global_option_proc(option[:switches], &option[:proc])
+        options.on(*option[:args], &global_option_proc(option[:switches], &option[:proc]))
       end
 
       options = @args.dup
@@ -341,44 +383,44 @@ module Commander
         retry
       end
     end
-    
+
     ##
     # Returns a proc allowing for commands to inherit global options.
     # This functionality works whether a block is present for the global
     # option or not, so simple switches such as --verbose can be used
     # without a block, and used throughout all commands.
-    
-    def global_option_proc switches, &block
+
+    def global_option_proc(switches, &block)
       lambda do |value|
         unless active_command.nil?
           active_command.proxy_options << [Runner.switch_to_sym(switches.last), value]
         end
-        yield value if block and !value.nil?
+        yield value if block && !value.nil?
       end
     end
-    
+
     ##
     # Raises a CommandError when the program any of the _keys_ are not present, or empty.
-        
-    def require_program *keys
+
+    def require_program(*keys)
       keys.each do |key|
-        raise CommandError, "program #{key} required" if program(key).nil? or program(key).empty?
+        fail CommandError, "program #{key} required" if program(key).nil? || program(key).empty?
       end
     end
-    
+
     ##
     # Return switches and description separated from the _args_ passed.
 
-    def self.separate_switches_from_description *args
-      switches = args.find_all { |arg| arg.to_s =~ /^-/ } 
-      description = args.last unless !args.last.is_a? String or args.last.match(/^-/)
-      return switches, description
+    def self.separate_switches_from_description(*args)
+      switches = args.find_all { |arg| arg.to_s =~ /^-/ }
+      description = args.last if args.last.is_a?(String) && !args.last.match(/^-/)
+      [switches, description]
     end
-    
+
     ##
     # Attempts to generate a method name symbol from +switch+.
     # For example:
-    # 
+    #
     #   -h                 # => :h
     #   --trace            # => :trace
     #   --some-switch      # => :some_switch
@@ -386,26 +428,25 @@ module Commander
     #   --file FILE        # => :file
     #   --list of,things   # => :list
     #
-    
-    def self.switch_to_sym switch
+
+    def self.switch_to_sym(switch)
       switch.scan(/[\-\]](\w+)/).join('_').to_sym rescue nil
     end
-    
+
     ##
     # Run the active command.
-    
+
     def run_active_command
       require_valid_command
       if alias? command_name_from_args
-        active_command.run *(@aliases[command_name_from_args.to_s] + args_without_command_name)
+        active_command.run(*(@aliases[command_name_from_args.to_s] + args_without_command_name))
       else
-        active_command.run *args_without_command_name
-      end      
-    end
-     
-    def say *args #:nodoc: 
-      $terminal.say *args
+        active_command.run(*args_without_command_name)
+      end
     end
 
+    def say(*args) #:nodoc:
+      $terminal.say(*args)
+    end
   end
 end
diff --git a/lib/commander/user_interaction.rb b/lib/commander/user_interaction.rb
index 653d482..08b5923 100644
--- a/lib/commander/user_interaction.rb
+++ b/lib/commander/user_interaction.rb
@@ -2,22 +2,20 @@ require 'tempfile'
 require 'shellwords'
 
 module Commander
-  
   ##
   # = User Interaction
   #
   # Commander's user interaction module mixes in common
-  # methods which extend HighLine's functionality such 
+  # methods which extend HighLine's functionality such
   # as a #password method rather than calling #ask directly.
-  
+
   module UI
-    
     module_function
-    
+
     #--
     # Auto include growl when available.
     #++
-    
+
     begin
       require 'growl'
     rescue LoadError
@@ -25,26 +23,26 @@ module Commander
     else
       include Growl
     end
-    
+
     ##
     # Ask the user for a password. Specify a custom
-    # _message_ other than 'Password: ' or override the 
+    # _message_ other than 'Password: ' or override the
     # default _mask_ of '*'.
-    
-    def password message = 'Password: ', mask = '*'
+
+    def password(message = 'Password: ', mask = '*')
       pass = ask(message) { |q| q.echo = mask }
       pass = password message, mask if pass.nil? || pass.empty?
       pass
     end
-    
+
     ##
     # Choose from a set array of _choices_.
-    
-    def choose message, *choices
-      say message
-      super(*choices)
+
+    def choose(message = nil, *choices, &block)
+      say message if message
+      super(*choices, &block)
     end
-    
+
     ##
     # 'Log' an _action_ to the terminal. This is typically used
     # for verbose output regarding actions performed. For example:
@@ -53,9 +51,9 @@ module Commander
     #   remove  path/to/old_file.rb
     #   remove  path/to/old_file2.rb
     #
-    
-    def log action, *args
-      say '%15s  %s' % [action, args.join(' ')]
+
+    def log(action, *args)
+      say format('%15s  %s', action, args.join(' '))
     end
 
     ##
@@ -66,7 +64,7 @@ module Commander
     #   say_ok 'It is ok', 'This is ok too'
     #
 
-    def say_ok *args
+    def say_ok(*args)
       args.each do |arg|
         say $terminal.color(arg, :green)
       end
@@ -80,7 +78,7 @@ module Commander
     #   say_warning 'Be careful', 'Think about it'
     #
 
-    def say_warning *args
+    def say_warning(*args)
       args.each do |arg|
         say $terminal.color(arg, :yellow)
       end
@@ -94,7 +92,7 @@ module Commander
     #   say_error 'It is not ok', 'This is not ok too'
     #
 
-    def say_error *args
+    def say_error(*args)
       args.each do |arg|
         say $terminal.color(arg, :red)
       end
@@ -120,28 +118,28 @@ module Commander
 
     ##
     # Speak _message_ using _voice_ at a speaking rate of _rate_
-    # 
+    #
     # Voice defaults to 'Alex', which is one of the better voices.
     # Speaking rate defaults to 175 words per minute
     #
     # === Examples
-    #    
+    #
     #   speak 'What is your favorite food? '
     #   food = ask 'favorite food?: '
-    #   speak "Wow, I like #{food} too. We have so much in common." 
+    #   speak "Wow, I like #{food} too. We have so much in common."
     #   speak "I like #{food} as well!", "Victoria", 190
     #
     # === Notes
     #
     # * MacOS only
     #
-    
-    def speak message, voice = :Alex, rate = 175
+
+    def speak(message, voice = :Alex, rate = 175)
       Thread.new { applescript "say #{message.inspect} using #{voice.to_s.inspect} speaking rate #{rate}" }
     end
-    
+
     ##
-    # Converse with speech recognition. 
+    # Converse with speech recognition.
     #
     # Currently a "poorman's" DSL to utilize applescript and
     # the MacOS speech recognition server.
@@ -149,7 +147,7 @@ module Commander
     # === Examples
     #
     #   case converse 'What is the best food?', :cookies => 'Cookies', :unknown => 'Nothing'
-    #   when :cookies 
+    #   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'
@@ -164,31 +162,36 @@ module Commander
     #
     # * MacOS only
     #
-    
-    def converse prompt, responses = {}
-      i, commands = 0, responses.map { |key, value| value.inspect }.join(',')
-      statement = responses.inject '' do |statement, (key, value)|
-        statement << (((i += 1) == 1 ? 
-          %(if response is "#{value}" then\n):
-            %(else if response is "#{value}" then\n))) <<
-              %(do shell script "echo '#{key}'"\n)
+
+    def converse(prompt, responses = {})
+      i, commands = 0, responses.map { |_key, value| value.inspect }.join(',')
+      statement = responses.inject '' do |inner_statement, (key, value)|
+        inner_statement <<
+        (
+          (i += 1) == 1 ?
+          %(if response is "#{value}" then\n) :
+          %(else if response is "#{value}" then\n)
+        ) <<
+        %(do shell script "echo '#{key}'"\n)
       end
-      applescript(%(
-        tell application "SpeechRecognitionServer" 
+      applescript(
+        %(
+        tell application "SpeechRecognitionServer"
           set response to listen for {#{commands}} with prompt "#{prompt}"
           #{statement}
           end if
         end tell
-      )).strip.to_sym
+        ),
+      ).strip.to_sym
     end
-    
+
     ##
     # Execute apple _script_.
-    
-    def applescript script
+
+    def applescript(script)
       `osascript -e "#{ script.gsub('"', '\"') }"`
     end
-    
+
     ##
     # Normalize IO streams, allowing for redirection of
     # +input+ and/or +output+, for example:
@@ -213,19 +216,18 @@ module Commander
     #     end
     #   end
     #
-    
-    def io input = nil, output = nil, &block
+
+    def io(input = nil, output = nil, &block)
       $stdin = File.new(input) if input
       $stdout = File.new(output, 'r+') if output
-      if block
-        yield
-        reset_io
-      end
+      return unless block
+      yield
+      reset_io
     end
-    
+
     ##
     # Reset IO to initial constant streams.
-    
+
     def reset_io
       $stdin, $stdout = STDIN, STDOUT
     end
@@ -234,12 +236,12 @@ module Commander
     # Find an editor available in path. Optionally supply the _preferred_
     # editor. Returns the name as a string, nil if none is available.
 
-    def available_editor preferred = nil
-      [preferred, ENV['EDITOR'], 'mate -w', 'vim', 'vi', 'emacs', 'nano', 'pico'].
-        compact.
-        find {|name| system("hash #{name.split.first} 2>&-") }
+    def available_editor(preferred = nil)
+      [preferred, ENV['EDITOR'], 'mate -w', 'vim', 'vi', 'emacs', 'nano', 'pico']
+        .compact
+        .find { |name| system("hash #{name.split.first} 2>&-") }
     end
-    
+
     ##
     # Prompt an editor for input. Optionally supply initial
     # _input_ which is written to the editor.
@@ -252,8 +254,8 @@ module Commander
     #   ask_editor('foo')         # => prompts EDITOR with default text of 'foo'
     #   ask_editor('foo', 'mate -w')  # => prompts TextMate with default text of 'foo'
     #
-       
-    def ask_editor input = nil, preferred_editor = nil
+
+    def ask_editor(input = nil, preferred_editor = nil)
       editor = available_editor preferred_editor
       program = Commander::Runner.instance.program(:name).downcase rescue 'commander'
       tmpfile = Tempfile.new program
@@ -265,10 +267,10 @@ module Commander
         tmpfile.unlink
       end
     end
-    
+
     ##
     # Enable paging of output after called.
-    
+
     def enable_paging
       return unless $stdout.tty?
       return unless Process.respond_to? :fork
@@ -279,19 +281,21 @@ module Commander
       # configurations that don't support it, but versions before 1.9 don't
       # seem to do this reliably and instead raise a NotImplementedError
       # (which is rescued below).
-      
+
       if Kernel.fork
         $stdin.reopen read
-        write.close; read.close
+        write.close
+        read.close
         Kernel.select [$stdin]
-        ENV['LESS'] = 'FSRX'
+        ENV['LESS'] = 'FSRX' unless ENV.key? 'LESS'
         pager = ENV['PAGER'] || 'less'
         exec pager rescue exec '/bin/sh', '-c', pager
       else
         # subprocess
         $stdout.reopen write
         $stderr.reopen write if $stderr.tty?
-        write.close; read.close
+        write.close
+        read.close
       end
     rescue NotImplementedError
     ensure
@@ -310,40 +314,42 @@ module Commander
     #   end
     #
 
-    def progress arr, options = {}, &block
+    def progress(arr, options = {})
       bar = ProgressBar.new arr.length, options
       bar.show
       arr.each { |v| bar.increment yield(v) }
     end
-        
+
     ##
     # Implements ask_for_CLASS methods.
-    
+
     module AskForClass
       # All special cases in HighLine::Question#convert, except those that implement #parse
-      ([Float, Integer, String, Symbol, Regexp, Array, File, Pathname] +
-      # All Classes that respond to #parse
-      Object.constants.map do |const|
-        # const_get(:Config) issues a deprecation warning on ruby 1.8.7
-        Object.const_get(const) unless const == :Config
-      end.select do |const|
-        const.class == Class && const.respond_to?(:parse)
-      end).each do |klass|
+      (
+        [Float, Integer, String, Symbol, Regexp, Array, File, Pathname] +
+        # All Classes that respond to #parse
+        Object.constants.map do |const|
+          # Ignore constants that trigger deprecation warnings
+          Object.const_get(const) unless [:Config, :TimeoutError, :MissingSourceFile].include?(const)
+        end.select do |const|
+          const.class == Class && const.respond_to?(:parse)
+        end
+      ).each do |klass|
         define_method "ask_for_#{klass.to_s.downcase}" do |prompt|
           $terminal.ask(prompt, klass)
         end
       end
     end
-    
+
     ##
     # Substitute _hash_'s keys with their associated values in _str_.
-    
-    def replace_tokens str, hash #:nodoc:
-      hash.inject str do |str, (key, value)|
-        str.gsub ":#{key}", value.to_s
+
+    def replace_tokens(str, hash) #:nodoc:
+      hash.inject(str) do |string, (key, value)|
+        string.gsub ":#{key}", value.to_s
       end
     end
-    
+
     ##
     # = Progress Bar
     #
@@ -352,12 +358,12 @@ module Commander
     # be incremented. Note that a hash of tokens may be passed to
     # #increment, (or returned when using Object#progress).
     #
-    #   uris = %w( 
+    #   uris = %w(
     #     http://vision-media.ca
     #     http://yahoo.com
     #     http://google.com
     #     )
-    #   
+    #
     #   bar = Commander::UI::ProgressBar.new uris.length, options
     #   threads = []
     #   uris.each do |uri|
@@ -381,12 +387,11 @@ module Commander
     #
 
     class ProgressBar
-
       ##
       # Creates a new progress bar.
       #
       # === Options
-      #    
+      #
       #   :title              Title, defaults to "Progress"
       #   :width              Width of :progress_bar
       #   :progress_str       Progress string, defaults to "="
@@ -397,7 +402,7 @@ module Commander
       #
       # === Tokens
       #
-      #   :title 
+      #   :title
       #   :percent_complete
       #   :progress_bar
       #   :step
@@ -407,7 +412,7 @@ module Commander
       #   :time_remaining
       #
 
-      def initialize total, options = {}
+      def initialize(total, options = {})
         @total_steps, @step, @start_time = total, 0, Time.now
         @title = options.fetch :title, 'Progress'
         @width = options.fetch :width, 25
@@ -417,10 +422,10 @@ module Commander
         @format = options.fetch :format, ':title |:progress_bar| :percent_complete% complete '
         @tokens = options.fetch :tokens, {}
       end
-      
+
       ##
       # Completion percentage.
-      
+
       def percent_complete
         if @total_steps.zero?
           100
@@ -428,69 +433,67 @@ module Commander
           @step * 100 / @total_steps
         end
       end
-      
+
       ##
       # Time that has elapsed since the operation started.
-      
+
       def time_elapsed
         Time.now - @start_time
       end
-      
+
       ##
       # Estimated time remaining.
-      
+
       def time_remaining
         (time_elapsed / @step) * steps_remaining
       end
-      
+
       ##
       # Number of steps left.
-      
+
       def steps_remaining
         @total_steps - @step
       end
-      
+
       ##
       # Formatted progress bar.
-      
+
       def progress_bar
         (@progress_str * (@width * percent_complete / 100)).ljust @width, @incomplete_str
       end
-      
+
       ##
       # Generates tokens for this step.
-      
+
       def generate_tokens
         {
-          :title => @title,
-          :percent_complete => percent_complete,
-          :progress_bar => progress_bar, 
-          :step => @step,
-          :steps_remaining => steps_remaining,
-          :total_steps => @total_steps, 
-          :time_elapsed => "%0.2fs" % time_elapsed,
-          :time_remaining => @step > 0 ? "%0.2fs" % time_remaining : '',
-        }.
-        merge! @tokens
+          title: @title,
+          percent_complete: percent_complete,
+          progress_bar: progress_bar,
+          step: @step,
+          steps_remaining: steps_remaining,
+          total_steps: @total_steps,
+          time_elapsed: format('%0.2fs', time_elapsed),
+          time_remaining: @step > 0 ? format('%0.2fs', time_remaining) : '',
+        }.merge! @tokens
       end
 
       ##
       # Output the progress bar.
 
       def show
-        unless finished?
-          erase_line
-          if completed?
-            $terminal.say UI.replace_tokens(@complete_message, generate_tokens) if @complete_message.is_a? String
-          else
-            $terminal.say UI.replace_tokens(@format, generate_tokens) << ' '
-          end
+        return if finished?
+        erase_line
+        if completed?
+          $terminal.say UI.replace_tokens(@complete_message, generate_tokens) if @complete_message.is_a? String
+        else
+          $terminal.say UI.replace_tokens(@format, generate_tokens) << ' '
         end
       end
-      
+
       ##
       # Whether or not the operation is complete, and we have finished.
-      
+
       def finished?
         @step == @total_steps + 1
       end
@@ -506,7 +509,7 @@ module Commander
       # Increment progress. Optionally pass _tokens_ which
       # can be displayed in the output format.
 
-      def increment tokens = {}
+      def increment(tokens = {})
         @step += 1
         @tokens.merge! tokens if tokens.is_a? Hash
         show
diff --git a/lib/commander/version.rb b/lib/commander/version.rb
index baeffbd..faa019f 100644
--- a/lib/commander/version.rb
+++ b/lib/commander/version.rb
@@ -1,3 +1,3 @@
 module Commander
-  VERSION = '4.1.5'
+  VERSION = '4.4.1'
 end
diff --git a/metadata.yml b/metadata.yml
deleted file mode 100644
index ba801dc..0000000
--- a/metadata.yml
+++ /dev/null
@@ -1,157 +0,0 @@
---- !ruby/object:Gem::Specification
-name: commander
-version: !ruby/object:Gem::Version
-  version: 4.1.5
-  prerelease: 
-platform: ruby
-authors:
-- TJ Holowaychuk
-- Gabriel Gilder
-autorequire: 
-bindir: bin
-cert_chain: []
-date: 2013-08-11 00:00:00.000000000 Z
-dependencies:
-- !ruby/object:Gem::Dependency
-  name: highline
-  requirement: !ruby/object:Gem::Requirement
-    none: false
-    requirements:
-    - - ~>
-      - !ruby/object:Gem::Version
-        version: 1.6.11
-  type: :runtime
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    none: false
-    requirements:
-    - - ~>
-      - !ruby/object:Gem::Version
-        version: 1.6.11
-- !ruby/object:Gem::Dependency
-  name: rspec
-  requirement: !ruby/object:Gem::Requirement
-    none: false
-    requirements:
-    - - ~>
-      - !ruby/object:Gem::Version
-        version: '2'
-  type: :development
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    none: false
-    requirements:
-    - - ~>
-      - !ruby/object:Gem::Version
-        version: '2'
-- !ruby/object:Gem::Dependency
-  name: rake
-  requirement: !ruby/object:Gem::Requirement
-    none: false
-    requirements:
-    - - ! '>='
-      - !ruby/object:Gem::Version
-        version: '0'
-  type: :development
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    none: false
-    requirements:
-    - - ! '>='
-      - !ruby/object:Gem::Version
-        version: '0'
-- !ruby/object:Gem::Dependency
-  name: simplecov
-  requirement: !ruby/object:Gem::Requirement
-    none: false
-    requirements:
-    - - ! '>='
-      - !ruby/object:Gem::Version
-        version: '0'
-  type: :development
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    none: false
-    requirements:
-    - - ! '>='
-      - !ruby/object:Gem::Version
-        version: '0'
-description: 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.
-email:
-- ggilder at tractionco.com
-executables:
-- commander
-extensions: []
-extra_rdoc_files: []
-files:
-- .gitignore
-- .travis.yml
-- DEVELOPMENT
-- Gemfile
-- History.rdoc
-- Manifest
-- README.rdoc
-- Rakefile
-- bin/commander
-- commander.gemspec
-- lib/commander.rb
-- lib/commander/blank.rb
-- lib/commander/command.rb
-- lib/commander/core_ext.rb
-- lib/commander/core_ext/array.rb
-- lib/commander/core_ext/object.rb
-- lib/commander/delegates.rb
-- lib/commander/help_formatters.rb
-- lib/commander/help_formatters/base.rb
-- lib/commander/help_formatters/terminal.rb
-- lib/commander/help_formatters/terminal/command_help.erb
-- lib/commander/help_formatters/terminal/help.erb
-- lib/commander/help_formatters/terminal_compact.rb
-- lib/commander/help_formatters/terminal_compact/command_help.erb
-- lib/commander/help_formatters/terminal_compact/help.erb
-- lib/commander/import.rb
-- lib/commander/platform.rb
-- lib/commander/runner.rb
-- lib/commander/user_interaction.rb
-- lib/commander/version.rb
-- spec/command_spec.rb
-- spec/core_ext/array_spec.rb
-- spec/core_ext/object_spec.rb
-- spec/help_formatters/terminal_spec.rb
-- spec/runner_spec.rb
-- spec/spec_helper.rb
-- spec/ui_spec.rb
-homepage: http://visionmedia.github.com/commander
-licenses: []
-post_install_message: 
-rdoc_options: []
-require_paths:
-- lib
-required_ruby_version: !ruby/object:Gem::Requirement
-  none: false
-  requirements:
-  - - ! '>='
-    - !ruby/object:Gem::Version
-      version: '0'
-required_rubygems_version: !ruby/object:Gem::Requirement
-  none: false
-  requirements:
-  - - ! '>='
-    - !ruby/object:Gem::Version
-      version: '0'
-requirements: []
-rubyforge_project: commander
-rubygems_version: 1.8.22
-signing_key: 
-specification_version: 3
-summary: The complete solution for Ruby command-line executables
-test_files:
-- spec/command_spec.rb
-- spec/core_ext/array_spec.rb
-- spec/core_ext/object_spec.rb
-- spec/help_formatters/terminal_spec.rb
-- spec/runner_spec.rb
-- spec/spec_helper.rb
-- spec/ui_spec.rb
diff --git a/spec/command_spec.rb b/spec/command_spec.rb
index 2026f3d..75c2296 100644
--- a/spec/command_spec.rb
+++ b/spec/command_spec.rb
@@ -1,157 +1,157 @@
 require 'spec_helper'
 
 describe Commander::Command do
-  
+  include Commander::Methods
+
   before :each do
     mock_terminal
     create_test_command
   end
-  
+
   describe 'Options' do
     before :each do
-      @options = Commander::Command::Options.new  
+      @options = Commander::Command::Options.new
     end
-    
-    it "should act like an open struct" do
+
+    it 'should act like an open struct' do
       @options.send = 'mail'
       @options.call = true
-      @options.send.should eq('mail')
-      @options.call.should eq(true)
+      expect(@options.send).to eq('mail')
+      expect(@options.call).to eq(true)
     end
-    
-    it "should allow __send__ to function as always" do
+
+    it 'should allow __send__ to function as always' do
       @options.send = 'foo'
-      @options.__send__(:send).should eq('foo')
+      expect(@options.__send__(:send)).to eq('foo')
     end
   end
-  
-  describe "#option" do
-    it "should add options" do
-      lambda { @command.option '--recursive' }.should change(@command.options, :length).from(1).to(2)
+
+  describe '#option' do
+    it 'should add options' do
+      expect { @command.option '--recursive' }.to change(@command.options, :length).from(1).to(2)
     end
-    
-    it "should allow procs as option handlers" do
-      @command.option('--recursive') { |recursive| recursive.should be_true }
+
+    it 'should allow procs as option handlers' do
+      @command.option('--recursive') { |recursive| expect(recursive).to be true }
       @command.run '--recursive'
     end
-    
-    it "should allow usage of common method names" do
+
+    it 'should allow usage of common method names' do
       @command.option '--open file'
-      @command.when_called { |_, options| options.open.should eq('foo') }  
+      @command.when_called { |_, options| expect(options.open).to eq('foo') }
       @command.run '--open', 'foo'
     end
   end
-  
-  describe "#run" do
-    describe "should invoke #when_called" do
-      it "with arguments seperated from options" do
-        @command.when_called { |args, options| args.join(' ').should eq('just some args') }  
+
+  describe '#run' do
+    describe 'should invoke #when_called' do
+      it 'with arguments seperated from options' do
+        @command.when_called { |args, _options| expect(args.join(' ')).to eq('just some args') }
         @command.run '--verbose', 'just', 'some', 'args'
       end
-      
-      it "calling the #call method by default when an object is called" do
-        object = mock 'Object'
-        object.should_receive(:call).once
+
+      it 'calling the #call method by default when an object is called' do
+        object = double 'Object'
+        expect(object).to receive(:call).once
         @command.when_called object
-        @command.run 'foo'        
+        @command.run 'foo'
       end
-      
-      it "should allow #action as an alias to #when_called" do
-        object = mock 'Object'
-        object.should_receive(:call).once
+
+      it 'should allow #action as an alias to #when_called' do
+        object = double 'Object'
+        expect(object).to receive(:call).once
         @command.action object
         @command.run 'foo'
       end
-            
-      it "calling an arbitrary method when an object is called" do
-        object = mock 'Object'
-        object.should_receive(:foo).once
+
+      it 'calling an arbitrary method when an object is called' do
+        object = double 'Object'
+        expect(object).to receive(:foo).once
         @command.when_called object, :foo
-        @command.run 'foo'        
+        @command.run 'foo'
       end
-      
-      it "should raise an error when no handler is present" do
-        lambda { @command.when_called }.should raise_error(ArgumentError)
+
+      it 'should raise an error when no handler is present' do
+        expect { @command.when_called }.to raise_error(ArgumentError)
       end
     end
-    
-    describe "should populate options with" do
-      it "boolean values" do
+
+    describe 'should populate options with' do
+      it 'boolean values' do
         @command.option '--[no-]toggle'
-        @command.when_called { |_, options| options.toggle.should be_true }  
+        @command.when_called { |_, options| expect(options.toggle).to be true }
         @command.run '--toggle'
-        @command.when_called { |_, options| options.toggle.should be_false }  
+        @command.when_called { |_, options| expect(options.toggle).to be false }
         @command.run '--no-toggle'
       end
 
-      it "mandatory arguments" do
+      it 'mandatory arguments' do
         @command.option '--file FILE'
-        @command.when_called { |_, options| options.file.should eq('foo') }  
+        @command.when_called { |_, options| expect(options.file).to eq('foo') }
         @command.run '--file', 'foo'
-        lambda { @command.run '--file' }.should raise_error(OptionParser::MissingArgument)
+        expect { @command.run '--file' }.to raise_error(OptionParser::MissingArgument)
       end
 
-      describe "optional arguments" do
+      describe 'optional arguments' do
         before do
           @command.option '--use-config [file] '
         end
 
-        it "should return the argument when provided" do
-          @command.when_called { |_, options| options.use_config.should eq('foo') }
+        it 'should return the argument when provided' do
+          @command.when_called { |_, options| expect(options.use_config).to eq('foo') }
           @command.run '--use-config', 'foo'
         end
 
-        it "should return true when present without an argument" do
-          @command.when_called { |_, options| options.use_config.should be_true }
+        it 'should return true when present without an argument' do
+          @command.when_called { |_, options| expect(options.use_config).to be true }
           @command.run '--use-config'
         end
 
-        it "should return nil when not present" do
-          @command.when_called { |_, options| options.use_config.should be_nil }
+        it 'should return nil when not present' do
+          @command.when_called { |_, options| expect(options.use_config).to be_nil }
           @command.run
         end
       end
 
-      describe "typed arguments" do
+      describe 'typed arguments' do
         before do
           @command.option '--interval N', Integer
         end
 
-        it "should parse valid values" do
-          @command.when_called { |_, options| options.interval.should eq(5) }
+        it 'should parse valid values' do
+          @command.when_called { |_, options| expect(options.interval).to eq(5) }
           @command.run '--interval', '5'
         end
 
-        it "should reject invalid values" do
-          lambda { @command.run '--interval', 'invalid' }.should raise_error(OptionParser::InvalidArgument)
+        it 'should reject invalid values' do
+          expect { @command.run '--interval', 'invalid' }.to raise_error(OptionParser::InvalidArgument)
         end
       end
 
-      it "lists" do
+      it 'lists' do
         @command.option '--fav COLORS', Array
-        @command.when_called { |_, options| options.fav.should eq(['red', 'green', 'blue']) }  
+        @command.when_called { |_, options| expect(options.fav).to eq(%w(red green blue)) }
         @command.run '--fav', 'red,green,blue'
       end
-      
-      it "lists with multi-word items" do
+
+      it 'lists with multi-word items' do
         @command.option '--fav MOVIES', Array
-        @command.when_called { |_, options| options.fav.should eq(['super\ bad', 'nightmare']) }  
-        @command.run '--fav', 'super\ bad,nightmare'        
+        @command.when_called { |_, options| expect(options.fav).to eq(['super\ bad', 'nightmare']) }
+        @command.run '--fav', 'super\ bad,nightmare'
       end
-      
-      it "defaults" do
+
+      it 'defaults' do
         @command.option '--files LIST', Array
         @command.option '--interval N', Integer
         @command.when_called do |_, options|
           options.default \
-            :files => ['foo', 'bar'],
-            :interval => 5
-          options.files.should eq(['foo', 'bar'])
-          options.interval.should eq(15)
+            files: %w(foo bar),
+            interval: 5
+          expect(options.files).to eq(%w(foo bar))
+          expect(options.interval).to eq(15)
         end
         @command.run '--interval', '15'
       end
     end
   end
-  
 end
diff --git a/spec/configure_spec.rb b/spec/configure_spec.rb
new file mode 100644
index 0000000..5426ade
--- /dev/null
+++ b/spec/configure_spec.rb
@@ -0,0 +1,37 @@
+require 'spec_helper'
+require 'commander/configure'
+
+describe Commander do
+  describe '.configure' do
+    it 'calls the given block' do
+      expect { Commander.configure { throw :block_called } }.to throw_symbol(:block_called)
+    end
+
+    describe 'called block' do
+      before(:each) do
+        allow(Commander::Runner.instance).to receive(:run!)
+      end
+
+      it 'provides Commander configuration methods' do
+        Commander.configure do
+          program :name, 'test'
+        end
+
+        expect(Commander::Runner.instance.program(:name)).to eq('test')
+      end
+
+      it 'passes all arguments to the block' do
+        Commander.configure('foo') do |first_arg|
+          program :name, first_arg
+        end
+
+        expect(Commander::Runner.instance.program(:name)).to eq('foo')
+      end
+    end
+
+    it 'calls Runner#run! after calling the configuration block' do
+      expect(Commander::Runner.instance).to receive(:run!)
+      Commander.configure {}
+    end
+  end
+end
diff --git a/spec/core_ext/array_spec.rb b/spec/core_ext/array_spec.rb
index 64c6987..16f7174 100644
--- a/spec/core_ext/array_spec.rb
+++ b/spec/core_ext/array_spec.rb
@@ -1,20 +1,18 @@
 require 'spec_helper'
 
 describe Array do
-
-  describe "#parse" do
-    it "should seperate a list of words into an array" do
-      Array.parse('just a test').should eq(['just', 'a', 'test'])
+  describe '#parse' do
+    it 'should seperate a list of words into an array' do
+      expect(Array.parse('just a test')).to eq(%w(just a test))
     end
 
-    it "should preserve escaped whitespace" do
-      Array.parse('just a\ test').should eq(['just', 'a test'])
+    it 'should preserve escaped whitespace' do
+      expect(Array.parse('just a\ test')).to eq(['just', 'a test'])
     end
 
-    it "should match %w behavior with multiple backslashes" do
+    it 'should match %w behavior with multiple backslashes' do
       str = 'just a\\ test'
-      Array.parse(str).should eq(eval("%w(#{str})"))
+      expect(Array.parse(str)).to eq(eval("%w(#{str})"))
     end
   end
-
 end
diff --git a/spec/core_ext/object_spec.rb b/spec/core_ext/object_spec.rb
index b6c0f41..852823b 100644
--- a/spec/core_ext/object_spec.rb
+++ b/spec/core_ext/object_spec.rb
@@ -1,21 +1,19 @@
 require 'spec_helper'
 
 describe Object do
-  
-  describe "#get_binding" do
-    it "should return the objects binding" do
-      lambda {}.get_binding.should be_instance_of(Binding)
+  describe '#get_binding' do
+    it 'should return the objects binding' do
+      expect(-> {}.get_binding).to be_instance_of(Binding)
     end
   end
 
-  describe "#method_missing" do
-    it "should preserve its original behavior for missing methods" do
-      lambda { i_am_a_missing_method() }.should raise_error(NoMethodError)
+  describe '#method_missing' do
+    it 'should preserve its original behavior for missing methods' do
+      expect { send(:i_am_a_missing_method) }.to raise_error(NoMethodError)
     end
 
-    it "should preserve its original behavior for missing variables" do
-      lambda { i_am_a_missing_variable }.should raise_error(NameError)
+    it 'should preserve its original behavior for missing variables' do
+      expect { i_am_a_missing_variable }.to raise_error(NameError)
     end
   end
-
 end
diff --git a/spec/help_formatters/terminal_compact_spec.rb b/spec/help_formatters/terminal_compact_spec.rb
new file mode 100644
index 0000000..ca9eb5c
--- /dev/null
+++ b/spec/help_formatters/terminal_compact_spec.rb
@@ -0,0 +1,69 @@
+require 'spec_helper'
+
+describe Commander::HelpFormatter::TerminalCompact do
+  include Commander::Methods
+
+  before :each do
+    mock_terminal
+  end
+
+  describe 'global help' do
+    before :each do
+      new_command_runner 'help' do
+        program :help_formatter, :compact
+        command :'install gem' do |c|
+          c.syntax = 'foo install gem [options]'
+          c.summary = 'Install some gem'
+        end
+      end.run!
+      @global_help = @output.string
+    end
+
+    describe 'should display' do
+      it 'the command name' do
+        expect(@global_help).to include('install gem')
+      end
+
+      it 'the summary' do
+        expect(@global_help).to include('Install some gem')
+      end
+    end
+  end
+
+  describe 'command help' do
+    before :each do
+      new_command_runner 'help', 'install', 'gem' do
+        program :help_formatter, :compact
+        command :'install gem' do |c|
+          c.syntax = 'foo install gem [options]'
+          c.summary = 'Install some gem'
+          c.description = 'Install some gem, blah blah blah'
+          c.example 'one', 'two'
+          c.example 'three', 'four'
+        end
+      end.run!
+      @command_help = @output.string
+    end
+
+    describe 'should display' do
+      it 'the command name' do
+        expect(@command_help).to include('install gem')
+      end
+
+      it 'the description' do
+        expect(@command_help).to include('Install some gem, blah blah blah')
+      end
+
+      it 'all examples' do
+        expect(@command_help).to include('# one')
+        expect(@command_help).to include('two')
+        expect(@command_help).to include('# three')
+        expect(@command_help).to include('four')
+      end
+
+      it 'the syntax' do
+        expect(@command_help).to include('foo install gem [options]')
+      end
+    end
+  end
+end
diff --git a/spec/help_formatters/terminal_spec.rb b/spec/help_formatters/terminal_spec.rb
index ee0ce29..c0f5810 100644
--- a/spec/help_formatters/terminal_spec.rb
+++ b/spec/help_formatters/terminal_spec.rb
@@ -1,12 +1,13 @@
 require 'spec_helper'
 
 describe Commander::HelpFormatter::Terminal do
-  
+  include Commander::Methods
+
   before :each do
     mock_terminal
   end
-  
-  describe "global help" do
+
+  describe 'global help' do
     before :each do
       new_command_runner 'help' do
         command :'install gem' do |c|
@@ -16,19 +17,19 @@ describe Commander::HelpFormatter::Terminal do
       end.run!
       @global_help = @output.string
     end
-    
-    describe "should display" do
-      it "the command name" do
-        @global_help.should include('install gem')
+
+    describe 'should display' do
+      it 'the command name' do
+        expect(@global_help).to include('install gem')
       end
-      
-      it "the summary" do
-        @global_help.should include('Install some gem')
+
+      it 'the summary' do
+        expect(@global_help).to include('Install some gem')
       end
     end
   end
-  
-  describe "command help" do
+
+  describe 'command help' do
     before :each do
       new_command_runner 'help', 'install', 'gem' do
         command :'install gem' do |c|
@@ -41,27 +42,26 @@ describe Commander::HelpFormatter::Terminal do
       end.run!
       @command_help = @output.string
     end
-    
-    describe "should display" do
-      it "the command name" do
-        @command_help.should include('install gem')
+
+    describe 'should display' do
+      it 'the command name' do
+        expect(@command_help).to include('install gem')
       end
-      
-      it "the description" do
-        @command_help.should include('Install some gem, blah blah blah')
+
+      it 'the description' do
+        expect(@command_help).to include('Install some gem, blah blah blah')
       end
-      
-      it "all examples" do
-        @command_help.should include('# one')
-        @command_help.should include('two')
-        @command_help.should include('# three')
-        @command_help.should include('four')
+
+      it 'all examples' do
+        expect(@command_help).to include('# one')
+        expect(@command_help).to include('two')
+        expect(@command_help).to include('# three')
+        expect(@command_help).to include('four')
       end
-      
-      it "the syntax" do
-        @command_help.should include('foo install gem [options]')
+
+      it 'the syntax' do
+        expect(@command_help).to include('foo install gem [options]')
       end
     end
   end
-  
 end
diff --git a/spec/methods_spec.rb b/spec/methods_spec.rb
new file mode 100644
index 0000000..853d32c
--- /dev/null
+++ b/spec/methods_spec.rb
@@ -0,0 +1,20 @@
+require 'spec_helper'
+require 'commander/methods'
+
+describe Commander::Methods do
+  it 'includes Commander::UI' do
+    expect(subject.ancestors).to include(Commander::UI)
+  end
+
+  it 'includes Commander::UI::AskForClass' do
+    expect(subject.ancestors).to include(Commander::UI::AskForClass)
+  end
+
+  it 'includes Commander::Delegates' do
+    expect(subject.ancestors).to include(Commander::Delegates)
+  end
+
+  it 'does not change the Object ancestors' do
+    expect(Object.ancestors).not_to include(Commander::UI)
+  end
+end
diff --git a/spec/runner_spec.rb b/spec/runner_spec.rb
index 620aec5..828f308 100644
--- a/spec/runner_spec.rb
+++ b/spec/runner_spec.rb
@@ -1,116 +1,140 @@
 require 'spec_helper'
 
 describe Commander do
+  include Commander::Methods
+
   before :each do
     $stderr = StringIO.new
     mock_terminal
     create_test_command
   end
-  
-  describe "#program" do
-    it "should set / get program information" do
+
+  describe '#program' do
+    it 'should set / get program information' do
       program :name, 'test'
-      program(:name).should eq('test')
+      expect(program(:name)).to eq('test')
     end
-    
-    it "should allow arbitrary blocks of global help documentation" do
+
+    it 'should allow arbitrary blocks of global help documentation' do
       program :help, 'Copyright', 'TJ Holowaychuk'
-      program(:help)['Copyright'].should eq('TJ Holowaychuk')
+      expect(program(:help)['Copyright']).to eq('TJ Holowaychuk')
     end
-    
-    it "should raise an error when required info has not been set" do
+
+    it 'should raise an error when required info has not been set' do
       new_command_runner '--help'
       program :version, ''
-      lambda { run! }.should raise_error(Commander::Runner::CommandError)
+      expect { run! }.to raise_error(Commander::Runner::CommandError)
     end
-    
-    it "should allow aliases of help formatters" do
+
+    it 'should allow aliases of help formatters' do
       program :help_formatter, :compact
-      program(:help_formatter).should eq(Commander::HelpFormatter::TerminalCompact)
+      expect(program(:help_formatter)).to eq(Commander::HelpFormatter::TerminalCompact)
     end
   end
-  
-  describe "#command" do
-    it "should return a command instance when only the name is passed" do
-      command(:test).should be_instance_of(Commander::Command)
+
+  describe '#command' do
+    it 'should return a command instance when only the name is passed' do
+      expect(command(:test)).to be_instance_of(Commander::Command)
     end
-    
-    it "should return nil when the command does not exist" do
-      command(:im_not_real).should be_nil
+
+    it 'should return nil when the command does not exist' do
+      expect(command(:im_not_real)).to be_nil
     end
   end
-  
-  describe "#separate_switches_from_description" do
-    it "should seperate switches and description returning both" do
+
+  describe '#separate_switches_from_description' do
+    it 'should seperate switches and description returning both' do
       switches, description = *Commander::Runner.separate_switches_from_description('-h', '--help', 'display help')
-      switches.should eq(['-h', '--help'])
-      description.should eq('display help')
+      expect(switches).to eq(['-h', '--help'])
+      expect(description).to eq('display help')
     end
   end
-  
-  describe "#switch_to_sym" do
-    it "should return a symbol based on the switch name" do
-     Commander::Runner.switch_to_sym('--trace').should eq(:trace)
-     Commander::Runner.switch_to_sym('--foo-bar').should eq(:foo_bar)
-     Commander::Runner.switch_to_sym('--[no-]feature"').should eq(:feature)
-     Commander::Runner.switch_to_sym('--[no-]feature ARG').should eq(:feature)
-     Commander::Runner.switch_to_sym('--file [ARG]').should eq(:file)
-     Commander::Runner.switch_to_sym('--colors colors').should eq(:colors)
+
+  describe '#switch_to_sym' do
+    it 'should return a symbol based on the switch name' do
+      expect(Commander::Runner.switch_to_sym('--trace')).to eq(:trace)
+      expect(Commander::Runner.switch_to_sym('--foo-bar')).to eq(:foo_bar)
+      expect(Commander::Runner.switch_to_sym('--[no-]feature"')).to eq(:feature)
+      expect(Commander::Runner.switch_to_sym('--[no-]feature ARG')).to eq(:feature)
+      expect(Commander::Runner.switch_to_sym('--file [ARG]')).to eq(:file)
+      expect(Commander::Runner.switch_to_sym('--colors colors')).to eq(:colors)
     end
   end
-  
-  describe "#alias_command" do
-    it "should alias a command" do
+
+  describe '#alias_command' do
+    it 'should alias a command' do
       alias_command :foo, :test
-      command(:foo).should eq(command(:test))
+      expect(command(:foo)).to eq(command(:test))
     end
-    
-    it "should pass arguments passed to the alias when called" do
+
+    it 'should pass arguments passed to the alias when called' do
       gem_name = ''
       new_command_runner 'install', 'gem', 'commander' do
         command :install do |c|
           c.option '--gem-name NAME', 'Install a gem'
           c.when_called { |_, options| gem_name = options.gem_name }
-        end 
+        end
         alias_command :'install gem', :install, '--gem-name'
       end.run!
-      gem_name.should eq('commander')
+      expect(gem_name).to eq('commander')
     end
   end
-  
-  describe "#global_option" do
-    it "should be invoked when used in the args list" do
+
+  describe '#global_option' do
+    it 'should be invoked when used in the args list' do
       file = ''
       new_command_runner 'test', '--config', 'foo' do
         global_option('--config FILE') { |f| file = f }
       end.run!
-      file.should eq('foo')
+      expect(file).to eq('foo')
     end
-    
-    it "should be inherited by commands" do
+
+    it 'should be inherited by commands' do
       quiet = nil
       new_command_runner 'foo', '--quiet' do
         global_option('--quiet', 'Suppress output')
         command :foo do |c|
-          c.when_called { |_, options| quiet = options.quiet } 
+          c.when_called { |_, options| quiet = options.quiet }
         end
       end.run!
-      quiet.should be_true
+      expect(quiet).to be true
     end
-    
-    it "should be inherited by commands even when a block is present" do
+
+    it 'should be inherited by commands even when a block is present' do
       quiet = nil
       new_command_runner 'foo', '--quiet' do
         global_option('--quiet', 'Suppress output') {}
         command :foo do |c|
-          c.when_called { |_, options| quiet = options.quiet } 
+          c.when_called { |_, options| quiet = options.quiet }
+        end
+      end.run!
+      expect(quiet).to be true
+    end
+
+    it 'should be inherited by commands when the positive form of a [no-] option' do
+      quiet = nil
+      new_command_runner 'foo', '--quiet' do
+        global_option('--[no-]quiet', 'Suppress output') {}
+        command :foo do |c|
+          c.when_called { |_, options| quiet = options.quiet }
         end
       end.run!
-      quiet.should be_true      
+      expect(quiet).to be true
+    end
+
+    it 'should be inherited by commands when the negative form of a [no-] option' do
+      quiet = nil
+      new_command_runner 'foo', '--no-quiet' do
+        global_option('--[no-]quiet', 'Suppress output') {}
+        command :foo do |c|
+          c.when_called { |_, options| quiet = options.quiet }
+        end
+      end.run!
+      expect(quiet).to be false
     end
   end
 
-  describe "#parse_global_options" do
+  describe '#parse_global_options' do
     it 'should parse global options before command' do
       global_option = nil
       new_command_runner('--testing-global', 'foo') do
@@ -120,19 +144,19 @@ describe Commander do
           c.when_called {}
         end
       end.run!
-      global_option.should eq('MAGIC')
+      expect(global_option).to eq('MAGIC')
     end
 
     it 'should parse global options after command' do
       global_option = nil
-      new_command_runner('foo','--testing-global') do
+      new_command_runner('foo', '--testing-global') do
         global_option('--testing-global') { global_option = 'MAGIC' }
 
         command :foo do |c|
           c.when_called {}
         end
       end.run!
-      global_option.should eq('MAGIC')
+      expect(global_option).to eq('MAGIC')
     end
 
     it 'should parse global options placed before command options' do
@@ -146,7 +170,7 @@ describe Commander do
         end
       end.run!
 
-      global_option.should eq('MAGIC')
+      expect(global_option).to eq('MAGIC')
     end
 
     it 'should parse global options placed after command options' do
@@ -160,7 +184,7 @@ describe Commander do
         end
       end.run!
 
-      global_option.should eq('MAGIC')
+      expect(global_option).to eq('MAGIC')
     end
 
     it 'should parse global options surrounded by command options' do
@@ -175,7 +199,7 @@ describe Commander do
         end
       end.run!
 
-      global_option.should eq('MAGIC')
+      expect(global_option).to eq('MAGIC')
     end
 
     it 'should not parse command options' do
@@ -190,8 +214,8 @@ describe Commander do
         end
       end.parse_global_options
 
-      command_option.should be_nil
-      global_option.should eq('MAGIC')
+      expect(command_option).to be_nil
+      expect(global_option).to eq('MAGIC')
     end
 
     it 'should not affect command arguments with values' do
@@ -206,8 +230,8 @@ describe Commander do
         end
       end.run!
 
-      command_option.should eq('bar')
-      global_option.should eq('MAGIC')
+      expect(command_option).to eq('bar')
+      expect(global_option).to eq('MAGIC')
     end
 
     it 'should not affect global arguments with values' do
@@ -216,14 +240,14 @@ describe Commander do
         global_option('--testing-global VALUE') { |v| global_option = v }
 
         command :foo do |c|
-          c.option('--testing-command') { }
+          c.option('--testing-command') {}
           c.when_called {}
         end
       end.run!
 
-      global_option.should eq('bar')
+      expect(global_option).to eq('bar')
     end
-    
+
     it 'should allow global arguments with values before command arguments (github issue #8)' do
       global_option = nil
       command_option = nil
@@ -236,297 +260,370 @@ describe Commander do
         end
       end.run!
 
-      global_option.should eq('path')
-      command_option.should eq('bar')
+      expect(global_option).to eq('path')
+      expect(command_option).to eq('bar')
     end
   end
 
-  
-  describe "#remove_global_options" do
-    it "should remove only specified switches" do
+  describe '#remove_global_options' do
+    it 'should remove only specified switches' do
       options, args = [], []
-      options << { :switches => ['-t', '--trace'] }
-      options << { :switches => ['--help'] }
-      options << { :switches => ['--paths PATHS'] }
+      options << { switches: ['-t', '--trace'] }
+      options << { switches: ['--help'] }
+      options << { switches: ['--paths PATHS'] }
       args << '-t'
       args << '--help'
       args << '--command'
       args << '--command-with-arg' << 'rawr'
       args << '--paths' << '"lib/**/*.js","spec/**/*.js"'
       command_runner.remove_global_options options, args
-      args.should eq(['--command', '--command-with-arg', 'rawr'])
+      expect(args).to eq(['--command', '--command-with-arg', 'rawr'])
     end
 
-    it "should not swallow an argument unless it expects an argument" do
+    it 'should not swallow an argument unless it expects an argument' do
       options, args = [], []
-      options << { :switches => ['-n', '--no-arg'] }
-      options << { :switches => ['-y', '--yes ARG'] }
-      options << { :switches => ['-a', '--alternative=ARG'] }
+      options << { switches: ['-n', '--no-arg'] }
+      options << { switches: ['-y', '--yes ARG'] }
+      options << { switches: ['-a', '--alternative=ARG'] }
       args << '-n' << 'alpha'
       args << '--yes' << 'deleted'
       args << '-a' << 'deleted'
       args << 'beta'
       command_runner.remove_global_options options, args
-      args.should eq(['alpha', 'beta'])
+      expect(args).to eq(%w(alpha beta))
+    end
+
+    it 'should remove a switch that is the positive form of the [no-] option' do
+      options, args = [], []
+      options << { switches: ['-g', '--[no-]good'] }
+      options << { switches: ['-y', '--yes ARG'] }
+      options << { switches: ['-a', '--alternative=ARG'] }
+      args << '--good' << 'alpha'
+      args << '--yes' << 'deleted'
+      args << '-a' << 'deleted'
+      args << 'beta'
+      command_runner.remove_global_options options, args
+      expect(args).to eq(%w(alpha beta))
+    end
+
+    it 'should remove a switch that is the negative form of the [no-] option' do
+      options, args = [], []
+      options << { switches: ['-g', '--[no-]good'] }
+      options << { switches: ['-y', '--yes ARG'] }
+      options << { switches: ['-a', '--alternative=ARG'] }
+      args << '--no-good' << 'alpha'
+      args << '--yes' << 'deleted'
+      args << '-a' << 'deleted'
+      args << 'beta'
+      command_runner.remove_global_options options, args
+      expect(args).to eq(%w(alpha beta))
+    end
+
+    it 'should not remove options that start with a global option name' do
+      options, args = [], []
+      options << { switches: ['-v', '--version'] }
+      args << '--versionCode' << 'something'
+      command_runner.remove_global_options options, args
+      expect(args).to eq(%w(--versionCode something))
     end
   end
-  
-  describe "--trace" do
-    it "should display pretty errors by default" do
-      pending("JRuby's Kernel.abort implementation is not testable") if Commander::Platform::jruby?
-      lambda {
+
+  describe '--trace' do
+    it 'should display pretty errors by default' do
+      expect do
         new_command_runner 'foo' do
-          command(:foo) { |c| c.when_called { raise 'cookies!' } }
+          command(:foo) { |c| c.when_called { fail 'cookies!' } }
         end.run!
-      }.should raise_error(SystemExit, /error: cookies!. Use --trace/)
+      end.to raise_error(SystemExit, /error: cookies!. Use --trace/)
     end
-    
-    it "should display callstack when using this switch" do
-      lambda {
+
+    it 'should display callstack when using this switch' do
+      expect do
         new_command_runner 'foo', '--trace' do
-          command(:foo) { |c| c.when_called { raise 'cookies!' } }
-        end.run!  
-      }.should raise_error(RuntimeError)
+          command(:foo) { |c| c.when_called { fail 'cookies!' } }
+        end.run!
+      end.to raise_error(RuntimeError)
     end
   end
-  
-  describe "--version" do
-    it "should output program version" do
-      run('--version').should eq("test 1.2.3\n")
+
+  describe '#always_trace!' do
+    it 'should enable tracing globally, regardless of whether --trace was passed or not' do
+      expect do
+        new_command_runner 'foo' do
+          always_trace!
+          command(:foo) { |c| c.when_called { fail 'cookies!' } }
+        end.run!
+      end.to raise_error(RuntimeError)
     end
   end
-  
-  describe "--help" do
-    it "should not output an invalid command message" do
-      run('--help').should_not == "invalid command. Use --help for more information\n"
+
+  describe '#never_trace!' do
+    it 'should disable tracing globally, regardless of whether --trace was passed or not' do
+      expect do
+        new_command_runner 'help', '--trace' do
+          never_trace!
+        end.run!
+      end.to raise_error(SystemExit, /invalid option: --trace/)
+    end
+
+    it 'should not prompt to use --trace switch on errors' do
+      msg = nil
+      begin
+        new_command_runner 'foo' do
+          never_trace!
+          command(:foo) { |c| c.when_called { fail 'cookies!' } }
+        end.run!
+      rescue SystemExit => e
+        msg = e.message
+      end
+      expect(msg).to match(/error: cookies!/)
+      expect(msg).not_to match(/--trace/)
     end
-    
-    it "can be used before or after the command and options" do
-      run('test', '--help').should eq("Implement help for test here\n")
+  end
+
+  context 'conflict between #always_trace! and #never_trace!' do
+    it 'respects the last used command' do
+      expect do
+        new_command_runner 'foo' do
+          never_trace!
+          always_trace!
+          command(:foo) { |c| c.when_called { fail 'cookies!' } }
+        end.run!
+      end.to raise_error(RuntimeError)
     end
   end
-  
-  describe "with invalid options" do
-    it "should output an invalid option message" do
-      pending("JRuby's Kernel.abort implementation is not testable") if Commander::Platform::jruby?
-      lambda {
-        run('test', '--invalid-option')  
-      }.should raise_error(SystemExit, /invalid option: --invalid-option/)
+
+  describe '--version' do
+    it 'should output program version' do
+      expect(run('--version')).to eq("test 1.2.3\n")
     end
   end
-  
-  describe "with invalid command passed" do
-    it "should output an invalid command message" do
-      pending("JRuby's Kernel.abort implementation is not testable") if Commander::Platform::jruby?
-      lambda {
-        run('foo')  
-      }.should raise_error(SystemExit, /invalid command. Use --help for more information/)
+
+  describe '--help' do
+    it 'should not output an invalid command message' do
+      expect(run('--help')).not_to eq("invalid command. Use --help for more information\n")
+    end
+
+    it 'can be used before or after the command and options' do
+      expect(run('test', '--help')).to eq("Implement help for test here\n")
     end
   end
-  
-  describe "with invalid command passed to help" do
-    it "should output an invalid command message" do
-      pending("JRuby's Kernel.abort implementation is not testable") if Commander::Platform::jruby?
-      lambda {
+
+  describe 'with invalid options' do
+    it 'should output an invalid option message' do
+      expect do
+        run('test', '--invalid-option')
+      end.to raise_error(SystemExit, /invalid option: --invalid-option/)
+    end
+  end
+
+  describe 'with invalid command passed' do
+    it 'should output an invalid command message' do
+      expect do
+        run('foo')
+      end.to raise_error(SystemExit, /invalid command. Use --help for more information/)
+    end
+  end
+
+  describe 'with invalid command passed to help' do
+    it 'should output an invalid command message' do
+      expect do
         run('help', 'does_not_exist')
-      }.should raise_error(SystemExit, /invalid command. Use --help for more information/)
+      end.to raise_error(SystemExit, /invalid command. Use --help for more information/)
     end
   end
-  
-  describe "with invalid command passed to --help" do
-    it "should output an invalid command message" do
-      pending("JRuby's Kernel.abort implementation is not testable") if Commander::Platform::jruby?
-      lambda {
+
+  describe 'with invalid command passed to --help' do
+    it 'should output an invalid command message' do
+      expect do
         run('--help', 'does_not_exist')
-      }.should raise_error(SystemExit, /invalid command. Use --help for more information/)
+      end.to raise_error(SystemExit, /invalid command. Use --help for more information/)
     end
   end
 
-  describe "with invalid option passed to --help" do
-    it "should output an invalid option message" do
-      pending("JRuby's Kernel.abort implementation is not testable") if Commander::Platform::jruby?
-      lambda {
+  describe 'with invalid option passed to --help' do
+    it 'should output an invalid option message' do
+      expect do
         run('--help', 'test', '--invalid-option')
-      }.should raise_error(SystemExit, /invalid option: --invalid-option/)
+      end.to raise_error(SystemExit, /invalid option: --invalid-option/)
     end
   end
-  
-  describe "#valid_command_names_from" do
-    it "should return array of valid command names" do
+
+  describe '#valid_command_names_from' do
+    it 'should return array of valid command names' do
       new_command_runner do
         command('foo bar') {}
         command('foo bar foo') {}
-        command_runner.valid_command_names_from('foo', 'bar', 'foo').sort.should eq(['foo bar', 'foo bar foo'])
+        expect(command_runner.valid_command_names_from('foo', 'bar', 'foo').sort).to eq(['foo bar', 'foo bar foo'])
       end
     end
-    
-    it "should return empty array when no possible command names exist" do
+
+    it 'should return empty array when no possible command names exist' do
       new_command_runner do
-        command_runner.valid_command_names_from('fake', 'command', 'name').should eq([])
+        expect(command_runner.valid_command_names_from('fake', 'command', 'name')).to eq([])
       end
     end
 
-    it "should match exact commands only" do
+    it 'should match exact commands only' do
       new_command_runner do
         command('foo') {}
-        command_runner.valid_command_names_from('foobar').should eq([])
+        expect(command_runner.valid_command_names_from('foobar')).to eq([])
       end
     end
   end
-  
-  describe "#command_name_from_args" do
-    it "should locate command within arbitrary arguments passed" do
+
+  describe '#command_name_from_args' do
+    it 'should locate command within arbitrary arguments passed' do
       new_command_runner '--help', '--arbitrary', 'test'
-      command_runner.command_name_from_args.should eq('test')
+      expect(command_runner.command_name_from_args).to eq('test')
     end
-    
-    it "should support multi-word commands" do
+
+    it 'should support multi-word commands' do
       new_command_runner '--help', '--arbitrary', 'some', 'long', 'command', 'foo'
       command('some long command') {}
-      command_runner.command_name_from_args.should eq('some long command')
+      expect(command_runner.command_name_from_args).to eq('some long command')
     end
-    
-    it "should match the longest possible command" do
+
+    it 'should match the longest possible command' do
       new_command_runner '--help', '--arbitrary', 'foo', 'bar', 'foo'
       command('foo bar') {}
       command('foo bar foo') {}
-      command_runner.command_name_from_args.should eq('foo bar foo'      )
+      expect(command_runner.command_name_from_args).to eq('foo bar foo')
     end
-    
-    it "should use the left-most command name when multiple are present" do
+
+    it 'should use the left-most command name when multiple are present' do
       new_command_runner 'help', 'test'
-      command_runner.command_name_from_args.should eq('help'      )
+      expect(command_runner.command_name_from_args).to eq('help')
     end
   end
-  
-  describe "#active_command" do
-    it "should resolve the active command" do
+
+  describe '#active_command' do
+    it 'should resolve the active command' do
       new_command_runner '--help', 'test'
-      command_runner.active_command.should be_instance_of(Commander::Command)
+      expect(command_runner.active_command).to be_instance_of(Commander::Command)
     end
-    
-    it "should resolve active command when invalid options are passed" do
+
+    it 'should resolve active command when invalid options are passed' do
       new_command_runner '--help', 'test', '--arbitrary'
-      command_runner.active_command.should be_instance_of(Commander::Command)
+      expect(command_runner.active_command).to be_instance_of(Commander::Command)
     end
-    
-    it "should return nil when the command is not found" do
+
+    it 'should return nil when the command is not found' do
       new_command_runner 'foo'
-      command_runner.active_command.should be_nil
+      expect(command_runner.active_command).to be_nil
     end
   end
-  
-  describe "#default_command" do
-    it "should allow you to default any command when one is not explicitly passed" do
+
+  describe '#default_command' do
+    it 'should allow you to default any command when one is not explicitly passed' do
       new_command_runner '--trace' do
         default_command :test
-        command(:test).should_receive(:run).once
-        command_runner.active_command.should eq(command(:test))
+        expect(command(:test)).to receive(:run).once
+        expect(command_runner.active_command).to eq(command(:test))
       end.run!
     end
-    
-    it "should not prevent other commands from being called" do
+
+    it 'should not prevent other commands from being called' do
       new_command_runner 'foo', 'bar', '--trace' do
         default_command :test
-        command(:'foo bar'){}
-        command(:'foo bar').should_receive(:run).once
-        command_runner.active_command.should eq(command(:'foo bar'))
+        command(:'foo bar') {}
+        expect(command(:'foo bar')).to receive(:run).once
+        expect(command_runner.active_command).to eq(command(:'foo bar'))
       end.run!
     end
-    
-    it "should not prevent longer commands to use the same words as the default" do
+
+    it 'should not prevent longer commands to use the same words as the default' do
       new_command_runner 'foo', 'bar', 'something'
       default_command :'foo bar'
-      command(:'foo bar'){}
-      command(:'foo bar something'){}
-      command_runner.active_command.should eq(command(:'foo bar something'))
+      command(:'foo bar') {}
+      command(:'foo bar something') {}
+      expect(command_runner.active_command).to eq(command(:'foo bar something'))
     end
-    
-    it "should allow defaulting of command aliases" do
+
+    it 'should allow defaulting of command aliases' do
       new_command_runner '--trace' do
         default_command :foobar
         alias_command :foobar, :test
-        command(:test).should_receive(:run).once
+        expect(command(:test)).to receive(:run).once
       end.run!
     end
   end
-  
-  describe "should function correctly" do
-    it "when options are passed before the command name" do
+
+  describe 'should function correctly' do
+    it 'when options are passed before the command name' do
       new_command_runner '--verbose', 'test', 'foo', 'bar' do
         @command.when_called do |args, options|
-          args.should eq(['foo', 'bar'])
-          options.verbose.should be_true
+          expect(args).to eq(%w(foo bar))
+          expect(options.verbose).to be true
         end
       end.run!
     end
 
-    it "when options are passed after the command name" do
+    it 'when options are passed after the command name' do
       new_command_runner 'test', '--verbose', 'foo', 'bar' do
         @command.when_called do |args, options|
-          args.should eq(['foo', 'bar'])
-          options.verbose.should be_true
+          expect(args).to eq(%w(foo bar))
+          expect(options.verbose).to be true
         end
       end.run!
     end
 
-    it "when an argument passed is the same name as the command" do
+    it 'when an argument passed is the same name as the command' do
       new_command_runner 'test', '--verbose', 'foo', 'test', 'bar' do
         @command.when_called do |args, options|
-          args.should eq(['foo', 'test', 'bar'])
-          options.verbose.should be_true
+          expect(args).to eq(%w(foo test bar))
+          expect(options.verbose).to be true
         end
       end.run!
     end
-    
-    it "when using multi-word commands" do
+
+    it 'when using multi-word commands' do
       new_command_runner '--verbose', 'my', 'command', 'something', 'foo', 'bar' do
         command('my command') { |c| c.option('--verbose') }
-        command_runner.command_name_from_args.should eq('my command')
-        command_runner.args_without_command_name.should eq(['--verbose', 'something', 'foo', 'bar'])
+        expect(command_runner.command_name_from_args).to eq('my command')
+        expect(command_runner.args_without_command_name).to eq(['--verbose', 'something', 'foo', 'bar'])
       end.run!
     end
 
-    it "when using multi-word commands with parts of the command name as arguments" do
+    it 'when using multi-word commands with parts of the command name as arguments' do
       new_command_runner '--verbose', 'my', 'command', 'something', 'my', 'command' do
         command('my command') { |c| c.option('--verbose') }
-        command_runner.command_name_from_args.should eq('my command')
-        command_runner.args_without_command_name.should eq(['--verbose', 'something', 'my', 'command'])
+        expect(command_runner.command_name_from_args).to eq('my command')
+        expect(command_runner.args_without_command_name).to eq(['--verbose', 'something', 'my', 'command'])
       end.run!
     end
-    
-    it "when using multi-word commands with other commands using the same words" do
+
+    it 'when using multi-word commands with other commands using the same words' do
       new_command_runner '--verbose', 'my', 'command', 'something', 'my', 'command' do
         command('my command') {}
         command('my command something') { |c| c.option('--verbose') }
-        command_runner.command_name_from_args.should eq('my command something')
-        command_runner.args_without_command_name.should eq(['--verbose', 'my', 'command'])
+        expect(command_runner.command_name_from_args).to eq('my command something')
+        expect(command_runner.args_without_command_name).to eq(['--verbose', 'my', 'command'])
       end.run!
     end
   end
 
-  describe "options with optional arguments" do
-    it "should return the argument when it is specified" do
+  describe 'options with optional arguments' do
+    it 'should return the argument when it is specified' do
       new_command_runner 'foo', '--optional', 'arg1' do
         command('foo') do |c|
           c.option('--optional [argument]')
           c.when_called do |_, options|
-            options.optional.should eq('arg1')
+            expect(options.optional).to eq('arg1')
           end
         end
       end.run!
     end
 
-    it "should return true when no argument is specified for the option" do
+    it 'should return true when no argument is specified for the option' do
       new_command_runner 'foo', '--optional' do
         command('foo') do |c|
           c.option('--optional [argument]')
           c.when_called do |_, options|
-            options.optional.should be_true
+            expect(options.optional).to be true
           end
         end
       end.run!
     end
   end
-
 end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index c302ab6..83ed668 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -1,29 +1,17 @@
 require 'rubygems'
 require 'stringio'
 require 'simplecov'
-SimpleCov.start
+SimpleCov.start do
+  add_filter '/spec/'
+end
 
 # Unshift so that local files load instead of something in gems
-$:.unshift File.dirname(__FILE__) + '/../lib'
+$LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
 
 # This basically replicates the behavior of `require 'commander/import'`
 # but without adding an `at_exit` hook, which interferes with exit code
 require 'commander'
-require 'commander/delegates'
-
-include Commander::UI
-include Commander::UI::AskForClass
-include Commander::Delegates
-
-# prevent paging from actually occurring in test environment
-
-module Commander
-  module UI
-    def enable_paging
-      return
-    end
-  end
-end
+require 'commander/methods'
 
 # Mock terminal IO streams so we can spec against them
 
@@ -37,13 +25,13 @@ end
 
 def create_test_command
   command :test do |c|
-    c.syntax = "test [options] <file>"
-    c.description = "test description"
-    c.example "description", "command"
-    c.example "description 2", "command 2"
-    c.option '-v', "--verbose", "verbose description"
-    c.when_called do |args, options|
-      "test %s" % args.join
+    c.syntax = 'test [options] <file>'
+    c.description = 'test description'
+    c.example 'description', 'command'
+    c.example 'description 2', 'command 2'
+    c.option '-v', '--verbose', 'verbose description'
+    c.when_called do |args, _options|
+      format('test %s', args.join)
     end
   end
   @command = command :test
@@ -51,7 +39,7 @@ end
 
 # Create a new command runner
 
-def new_command_runner *args, &block
+def new_command_runner(*args, &block)
   Commander::Runner.instance_variable_set :"@singleton", Commander::Runner.new(args)
   program :name, 'test'
   program :version, '1.2.3'
@@ -67,9 +55,23 @@ def command_runner
   Commander::Runner.instance
 end
 
-def run *args
+def run(*args)
   new_command_runner(*args) do
     program :help_formatter, Commander::HelpFormatter::Base
-  end.run!    
+  end.run!
   @output.string
-end
\ No newline at end of file
+end
+
+RSpec.configure do |c|
+  c.expect_with(:rspec) do |e|
+    e.syntax = :expect
+  end
+
+  c.mock_with(:rspec) do |m|
+    m.syntax = :expect
+  end
+
+  c.before(:each) do
+    allow(Commander::UI).to receive(:enable_paging)
+  end
+end
diff --git a/spec/ui_spec.rb b/spec/ui_spec.rb
index f4d3fea..a3b5fb7 100644
--- a/spec/ui_spec.rb
+++ b/spec/ui_spec.rb
@@ -1,30 +1,30 @@
 require 'spec_helper'
 
 describe Commander::UI do
-  
-  describe ".replace_tokens" do
-    it "should replace tokens within a string, with hash values" do
-      result = Commander::UI.replace_tokens 'Welcome :name, enjoy your :object'.freeze, :name => 'TJ', :object => 'cookie'
-      result.should eq('Welcome TJ, enjoy your cookie')
+  include Commander::Methods
+
+  describe '.replace_tokens' do
+    it 'should replace tokens within a string, with hash values' do
+      result = Commander::UI.replace_tokens 'Welcome :name, enjoy your :object'.freeze, name: 'TJ', object: 'cookie'
+      expect(result).to eq('Welcome TJ, enjoy your cookie')
     end
   end
 
-  describe "progress" do
-    it "should not die on an empty list" do
+  describe 'progress' do
+    it 'should not die on an empty list' do
       exception = false
       begin
         progress([]) {}
       rescue
         exception = true
       end
-      exception.should_not be_true
+      expect(exception).not_to be true
     end
   end
-  
-  describe ".available_editor" do
-    it "should not fail on available editors with shell arguments" do
-      Commander::UI.available_editor('sh -c').should eq('sh -c')
+
+  describe '.available_editor' do
+    it 'should not fail on available editors with shell arguments' do
+      expect(Commander::UI.available_editor('sh -c')).to eq('sh -c')
     end
   end
-
 end

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ruby-extras/ruby-commander.git



More information about the Pkg-ruby-extras-commits mailing list