diff options
author | Lee Jarvis <lee@jarvis.co> | 2011-04-16 19:36:14 +0100 |
---|---|---|
committer | Lee Jarvis <lee@jarvis.co> | 2011-04-16 19:36:14 +0100 |
commit | 72a91e7f3ec795caea95b9f3dd805c4db3bb31ee (patch) | |
tree | ee90882b9506ab4b069ddcb4df151a079d2d5147 | |
parent | 9869038dfcba7de5eeb9497d8aa1324085cf435e (diff) | |
parent | 37561c7dc1e370fdacef7642935a7929acadf380 (diff) | |
download | slop-72a91e7f3ec795caea95b9f3dd805c4db3bb31ee.tar.gz |
Merge branch 'commands'
-rw-r--r-- | README.md | 38 | ||||
-rw-r--r-- | lib/slop.rb | 59 | ||||
-rw-r--r-- | test/commands_test.rb | 72 | ||||
-rw-r--r-- | test/slop_test.rb | 23 |
4 files changed, 180 insertions, 12 deletions
@@ -315,6 +315,44 @@ yields: -n, --name Your name -h, --help Print this help message +Commands +-------- + +Slop allows you to nest more instances of Slop inside of `commands`. These +instances will then be used to parse arguments if they're called upon. + +Slop will use the first argument in the list of items passed to `parse` to +check if it is a `command`. + + Slop.parse ['foo', '--bar', 'baz'] + +Slop will look to see if the `foo` command exists, and if it does, it'll pass +the options `['--bar', 'baz']` to the instance of Slop that belongs to `foo`. +Here's how commands might look: + + opts = Slop.new do + command :foo do + on :b, :bar, 'something', true + end + + command :clean do + on :v, :verbose, do + puts 'Enabled verbose mode for clean' + end + end + + # non-command specific options + on :v, :version do + puts 'version 1' + end + end + +* Run with `run.rb -v` +* Output: `version 1` + +* Run with: `run.rb clean -v` +* Output: `Enabled verbose mode for clean` + Woah woah, why you hating on OptionParser? ------------------------------------------ diff --git a/lib/slop.rb b/lib/slop.rb index ae95559..02047b4 100644 --- a/lib/slop.rb +++ b/lib/slop.rb @@ -44,6 +44,9 @@ class Slop # @return [Options] attr_reader :options + # @return [Hash] + attr_reader :commands + attr_writer :banner attr_accessor :longest_flag @@ -54,6 +57,9 @@ class Slop # @option opts [Boolean] :multiple_switches Allows `-abc` to be processed # as the options 'a', 'b', 'c' and will force their argument values to # true. By default Slop with parse this as 'a' with the argument 'bc' + # @option opts [String] :banner The banner text used for the help + # @option opts [Proc, #call] :on_empty Any object that respondes to `call` + # which is executed when Slop has no items to parse def initialize(*opts, &block) sloptions = {} sloptions.merge! opts.pop if opts.last.is_a? Hash @@ -61,11 +67,16 @@ class Slop opts.each { |o| sloptions[o] = true } @options = Options.new + @commands = {} + @longest_flag = 0 - @strict = sloptions[:strict] @invalid_options = [] + + @banner ||= sloptions[:banner] + @strict = sloptions[:strict] @multiple_switches = sloptions[:multiple_switches] @on_empty = sloptions[:on_empty] + @sloptions = sloptions if block_given? block.arity == 1 ? yield(self) : instance_eval(&block) @@ -119,7 +130,7 @@ class Slop # @return [Object] Returns the value associated with that option. def [](key) option = @options[key] - option.argument_value if option + option ? option.argument_value : @commands[key] end # Specify an option with a short or long version, description and type. @@ -155,6 +166,37 @@ class Slop alias :opt :option alias :on :option + + # Namespace options depending on what command is executed + # + # @param [Symbol, String] label + # @param [Hash] options + # @example + # opts = Slop.new do + # command :create do + # on :v, :verbose + # end + # end + # + # # ARGV is `create -v` + # opts.commands[:create].verbose? #=> true + # @return [Slop] a new instance of Slop namespaced to +label+ + def command(label, options={}, &block) + if @commands[label] + raise ArgumentError, "command `#{label}` already exists" + end + + options = @sloptions.merge(options) + slop = Slop.new(options) + @commands[label] = slop + + if block_given? + block.arity == 1 ? yield(slop) : slop.instance_eval(&block) + end + + slop + end + # Add an object to be called when Slop has no values to parse # # @param [Object, nil] proc The object (which can be anything @@ -231,6 +273,8 @@ class Slop return end + return if execute_command(items, delete) + trash = [] items.each_with_index do |item, index| @@ -341,6 +385,17 @@ class Slop end end + def execute_command(items, delete) + command = items[0] + command = @commands.keys.find { |cmd| cmd.to_s == command.to_s } + if @commands.key?(command) + items.shift + opts = @commands[command] + delete ? opts.parse!(items) : opts.parse(items) + true + end + end + def clean_options(args) options = [] diff --git a/test/commands_test.rb b/test/commands_test.rb new file mode 100644 index 0000000..4240a8a --- /dev/null +++ b/test/commands_test.rb @@ -0,0 +1,72 @@ +require File.dirname(__FILE__) + '/helper' + +class CommandsTest < TestCase + test 'creating commands' do + slop = Slop.new do + command :foo do on :f, :foo, 'foo option' end + command :bar do on :f, :foo; on :b, :bar, true end + end + + slop.commands.each_value do |command| + assert_kind_of Slop, command + end + + assert 'foo option', slop.commands[:foo].options[:foo].description + + slop.parse %w/bar --bar baz/ + assert 'baz', slop.commands[:bar][:bar] + assert_nil slop.commands['bar'] + end + + test 'repeating existing commands' do + slop = Slop.new + assert slop.command :foo + assert_raises(ArgumentError) { slop.command :foo } + end + + test 'commands inheriting options' do + slop = Slop.new :strict do + command :foo do end + end + assert slop.commands[:foo].instance_variable_get(:@strict) + end + + test 'commands setting options' do + slop = Slop.new :strict => false do + command :foo, :strict => true do end + end + assert slop.commands[:foo].instance_variable_get(:@strict) + end + + test 'inception' do + slop = Slop.new do + command(:foo) { command(:bar) { command(:baz) { on :f, 'D:' } } } + end + desc = slop.commands[:foo].commands[:bar].commands[:baz].options[:f].description + assert_equal 'D:', desc + end + + test 'commands with banners' do + slop = Slop.new do + command(:foo, :banner => 'bar') { } + command(:bar) { banner 'bar' } + end + assert_equal 'bar', slop.commands[:foo].banner + assert_equal 'bar', slop.commands[:bar].banner + end + + test 'executing on_empty on separate commands' do + incmd = inslop = false + slop = Slop.new do + command(:foo) { on(:bar) {}; on_empty { incmd = true }} + on_empty { inslop = true } + end + slop.parse %w// + assert inslop + refute incmd + inslop = false + slop.parse %w/foo/ + assert incmd + refute inslop + end +end
\ No newline at end of file diff --git a/test/slop_test.rb b/test/slop_test.rb index 2ada9a9..5648ffc 100644 --- a/test/slop_test.rb +++ b/test/slop_test.rb @@ -1,5 +1,3 @@ -require File.dirname(__FILE__) + '/helper' - class SlopTest < TestCase def clean_options(*args) Slop.new.send(:clean_options, args) @@ -19,7 +17,6 @@ class SlopTest < TestCase test 'new accepts a hash or array of symbols' do slop = Slop.new :strict, :multiple_switches => true - [ :@multiple_switches, :@strict ].each do |var| assert slop.instance_variable_get var end @@ -94,10 +91,8 @@ class SlopTest < TestCase test 'preserving order when yielding non-options' do items = [] - slop = Slop.new { on(:name, true) { |name| items << name } } slop.parse(%w/foo --name bar baz/) { |value| items << value } - assert_equal %w/foo bar baz/, items end @@ -113,6 +108,9 @@ class SlopTest < TestCase slop = Slop.new "foo bar" assert_equal "foo bar", slop.banner + + slop = Slop.new :banner => "foo bar" + assert_equal "foo bar", slop.banner end test 'storing long option lengths' do @@ -128,7 +126,6 @@ class SlopTest < TestCase opts = Slop.new do on :name, true end - assert_equal %w/a/, opts.parse!(%w/--name lee a/) assert_equal %w/--name lee a/, opts.parse(%w/--name lee a/) end @@ -181,13 +178,21 @@ class SlopTest < TestCase assert_equal(['c', nil, nil, false], clean_options(:c, false)) end - test '[] returns an options argument value or nil' do + test '[] returns an options argument value or a command or nil (in that order)' do slop = Slop.new slop.opt :n, :name, true - slop.parse %w/--name lee/ + slop.opt :foo + slop.command(:foo) { } + slop.command(:bar) { } + slop.parse %w/--name lee --foo/ assert_equal 'lee', slop[:name] assert_equal 'lee', slop[:n] + + assert_equal true, slop[:foo] + assert_kind_of Slop, slop[:bar] + + assert_nil slop[:baz] end test 'arguments ending ? test for option existance' do @@ -246,7 +251,6 @@ class SlopTest < TestCase slop = Slop.new slop.banner = 'Usage: foo [options]' slop.parse - assert slop.to_s =~ /^Usage: foo/ end @@ -307,7 +311,6 @@ class SlopTest < TestCase test 'parsing options with options as arguments' do slop = Slop.new { on :f, :foo, true } - assert_raises(Slop::MissingArgumentError) { slop.parse %w/-f --bar/ } end end |