slop 3.3.2 → 3.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGES.md CHANGED
@@ -1,3 +1,10 @@
1
+ 3.3.3 (2012-08-29)
2
+ ------------------
3
+
4
+ * Ensure autocreate arguments are not created as options (#77)
5
+ * Ensure options are not swallowed when using short options with argument
6
+ included (#74)
7
+
1
8
  3.3.2 (2012-06-26)
2
9
  ------------------
3
10
 
@@ -4,7 +4,7 @@ require 'slop/commands'
4
4
  class Slop
5
5
  include Enumerable
6
6
 
7
- VERSION = '3.3.2'
7
+ VERSION = '3.3.3'
8
8
 
9
9
  # The main Error class, all Exception classes inherit from this class.
10
10
  class Error < StandardError; end
@@ -433,7 +433,7 @@ class Slop
433
433
  elsif option.accepts_optional_argument?
434
434
  argument ||= items.at(index + 1)
435
435
 
436
- if argument && argument =~ /\A([^-\-?]|-\d)+/
436
+ if argument && argument =~ /\A([^\-?]|-\d)+/
437
437
  execute_option(option, argument, index, item)
438
438
  else
439
439
  option.call(nil)
@@ -467,7 +467,9 @@ class Slop
467
467
  end
468
468
 
469
469
  if argument
470
- @trash << index + 1 unless item && item.end_with?("=#{argument}")
470
+ unless item && item.end_with?("=#{argument}")
471
+ @trash << index + 1 unless option.argument_in_value
472
+ end
471
473
  option.value = argument
472
474
  else
473
475
  option.value = option.count > 0
@@ -511,6 +513,7 @@ class Slop
511
513
  case flag
512
514
  when /\A--?([^=]+)=(.+)\z/, /\A-([a-zA-Z])(.+)\z/, /\A--no-(.+)\z/
513
515
  option, argument = fetch_option($1), ($2 || false)
516
+ option.argument_in_value = true if option
514
517
  end
515
518
  end
516
519
 
@@ -525,7 +528,7 @@ class Slop
525
528
  # Returns nothing.
526
529
  def autocreate(items, index)
527
530
  flag = items[index]
528
- unless present?(flag)
531
+ if !fetch_option(flag) && !@trash.include?(index)
529
532
  option = build_option(Array(flag))
530
533
  argument = items[index + 1]
531
534
  option.config[:argument] = (argument && argument !~ /\A--?/)
@@ -2,7 +2,7 @@ class Slop
2
2
  class Commands
3
3
  include Enumerable
4
4
 
5
- attr_reader :config, :commands
5
+ attr_reader :config, :commands, :arguments
6
6
  attr_writer :banner
7
7
 
8
8
  # Create a new instance of Slop::Commands and optionally build
@@ -37,6 +37,7 @@ class Slop
37
37
  @config = config
38
38
  @commands = {}
39
39
  @banner = nil
40
+ @triggered_command = nil
40
41
 
41
42
  if block_given?
42
43
  block.arity == 1 ? yield(self) : instance_eval(&block)
@@ -94,6 +95,19 @@ class Slop
94
95
  end
95
96
  alias get []
96
97
 
98
+ # Check for a command presence.
99
+ #
100
+ # Examples:
101
+ #
102
+ # cmds.parse %w( foo )
103
+ # cmds.present?(:foo) #=> true
104
+ # cmds.present?(:bar) #=> false
105
+ #
106
+ # Returns true if the given key is present in the parsed arguments.
107
+ def present?(key)
108
+ key.to_s == @triggered_command
109
+ end
110
+
97
111
  # Parse a list of items.
98
112
  #
99
113
  # items - The Array of items to parse.
@@ -149,7 +163,8 @@ class Slop
149
163
  # Returns the Array of items (with options removed if bang == true).
150
164
  def parse_items(items, bang = false)
151
165
  if opts = commands[items[0].to_s]
152
- items.shift
166
+ @triggered_command = items.shift
167
+ execute_arguments(items, bang)
153
168
  bang ? opts.parse!(items) : opts.parse(items)
154
169
  execute_global_opts(items, bang)
155
170
  else
@@ -165,6 +180,13 @@ class Slop
165
180
  items
166
181
  end
167
182
 
183
+ # Returns nothing.
184
+ def execute_arguments(items, bang)
185
+ @arguments = items.take_while { |arg| !arg.start_with?('-') }
186
+ items.shift(@arguments.size) if bang
187
+ end
188
+
189
+ # Returns nothing.
168
190
  def execute_global_opts(items, bang)
169
191
  if global_opts = commands['global']
170
192
  bang ? global_opts.parse!(items) : global_opts.parse(items)
@@ -18,8 +18,7 @@ class Slop
18
18
  }
19
19
 
20
20
  attr_reader :short, :long, :description, :config, :types
21
- attr_accessor :count
22
- attr_writer :value
21
+ attr_accessor :count, :argument_in_value
23
22
 
24
23
  # Incapsulate internal option information, mainly used to store
25
24
  # option specific configuration data, most of the meat of this
@@ -39,13 +38,13 @@ class Slop
39
38
  @config = DEFAULT_OPTIONS.merge(config)
40
39
  @count = 0
41
40
  @callback = block_given? ? block : config[:callback]
41
+ @value = nil
42
42
 
43
43
  @types = {
44
44
  :string => proc { |v| v.to_s },
45
45
  :symbol => proc { |v| v.to_sym },
46
46
  :integer => proc { |v| value_to_integer(v) },
47
47
  :float => proc { |v| value_to_float(v) },
48
- :array => proc { |v| v.split(@config[:delimiter], @config[:limit]) },
49
48
  :range => proc { |v| value_to_range(v) },
50
49
  :count => proc { |v| @count }
51
50
  }
@@ -55,7 +54,10 @@ class Slop
55
54
  end
56
55
 
57
56
  @config.each_key do |key|
58
- self.class.send(:define_method, "#{key}?") { !!@config[key] }
57
+ predicate = :"#{key}?"
58
+ unless self.class.method_defined? predicate
59
+ self.class.send(:define_method, predicate) { !!@config[key] }
60
+ end
59
61
  end
60
62
  end
61
63
 
@@ -81,6 +83,23 @@ class Slop
81
83
  @callback.call(*objects) if @callback.respond_to?(:call)
82
84
  end
83
85
 
86
+ # Set the new argument value for this option.
87
+ #
88
+ # We use this setter method to handle concatenating lists. That is,
89
+ # when an array type is specified and used more than once, values from
90
+ # both options will be grouped together and flattened into a single array.
91
+ def value=(new_value)
92
+ if config[:as].to_s.downcase == 'array'
93
+ @value ||= []
94
+
95
+ if new_value.respond_to?(:split)
96
+ @value.concat new_value.split(config[:delimiter], config[:limit])
97
+ end
98
+ else
99
+ @value = new_value
100
+ end
101
+ end
102
+
84
103
  # Fetch the argument value for this option.
85
104
  #
86
105
  # Returns the Object once any type conversions have taken place.
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'slop'
3
- s.version = '3.3.2'
3
+ s.version = '3.3.3'
4
4
  s.summary = 'Option gathering made easy'
5
5
  s.description = 'A simple DSL for gathering options and parsing the command line'
6
6
  s.author = 'Lee Jarvis'
@@ -27,6 +27,12 @@ class CommandsTest < TestCase
27
27
  assert_equal 'Force creation', @commands[:new].fetch_option(:force).description
28
28
  end
29
29
 
30
+ test "checking for a command presence" do
31
+ @commands.parse %w( new --force )
32
+ assert @commands.present?(:new)
33
+ refute @commands.present?(:version)
34
+ end
35
+
30
36
  test "to_hash" do
31
37
  assert_equal({
32
38
  :new => { :force => nil, :outdir => nil },
@@ -77,14 +83,20 @@ class CommandsTest < TestCase
77
83
  items = %w( foo bar baz )
78
84
  assert_equal items, @commands.parse(items)
79
85
 
80
- items = %w( new --force )
86
+ items = %w( new file --force )
81
87
  assert_equal items, @commands.parse(items)
82
88
  end
83
89
 
84
90
  test "parse! removes options/arguments" do
85
- items = %w( new --outdir foo )
91
+ items = %w( new file --outdir foo )
86
92
  @commands.parse!(items)
87
93
  assert_equal [], items
88
94
  end
89
95
 
90
- end
96
+ test "command arguments" do
97
+ items = %w( new file1 file2 --outdir foo )
98
+ @commands.parse(items)
99
+ assert_equal %w( file1 file2 ), @commands.arguments
100
+ end
101
+
102
+ end
@@ -1,3 +1,5 @@
1
+ $VERBOSE = true
2
+
1
3
  unless Object.const_defined? 'Slop'
2
4
  $:.unshift File.expand_path('../../lib', __FILE__)
3
5
  require 'slop'
@@ -71,14 +71,14 @@ class OptionTest < TestCase
71
71
  end
72
72
 
73
73
  test "range type cast" do
74
- assert_equal (1..10), option_value(%w/-r 1..10/, :r=, :as => Range)
75
- assert_equal (1..10), option_value(%w/-r 1-10/, :r=, :as => Range)
76
- assert_equal (1..10), option_value(%w/-r 1,10/, :r=, :as => Range)
77
- assert_equal (1...10), option_value(%w/-r 1...10/, :r=, :as => Range)
78
- assert_equal (-1..10), option_value(%w/-r -1..10/, :r=, :as => Range)
79
- assert_equal (1..-10), option_value(%w/-r 1..-10/, :r=, :as => Range)
80
- assert_equal (1..1), option_value(%w/-r 1/, :r=, :as => Range)
81
- assert_equal (-1..10), option_value(%w/-r -1..10/, :r, :as => Range, :optional_argument => true)
74
+ assert_equal((1..10), option_value(%w/-r 1..10/, :r=, :as => Range))
75
+ assert_equal((1..10), option_value(%w/-r 1-10/, :r=, :as => Range))
76
+ assert_equal((1..10), option_value(%w/-r 1,10/, :r=, :as => Range))
77
+ assert_equal((1...10), option_value(%w/-r 1...10/, :r=, :as => Range))
78
+ assert_equal((-1..10), option_value(%w/-r -1..10/, :r=, :as => Range))
79
+ assert_equal((1..-10), option_value(%w/-r 1..-10/, :r=, :as => Range))
80
+ assert_equal((1..1), option_value(%w/-r 1/, :r=, :as => Range))
81
+ assert_equal((-1..10), option_value(%w/-r -1..10/, :r, :as => Range, :optional_argument => true))
82
82
 
83
83
  opts = Slop.new(:strict => true) { on :r=, :as => Range }
84
84
  assert_raises(Slop::InvalidArgumentError) { opts.parse %w/-r abc/ }
@@ -86,6 +86,7 @@ class OptionTest < TestCase
86
86
 
87
87
  test "array type cast" do
88
88
  assert_equal %w/lee john bill/, option_value(%w/-p lee,john,bill/, :p=, :as => Array)
89
+ assert_equal %w/lee john bill jeff jill/, option_value(%w/-p lee,john,bill -p jeff,jill/, :p=, :as => Array)
89
90
  assert_equal %w/lee john bill/, option_value(%w/-p lee:john:bill/, :p=, :as => Array, :delimiter => ':')
90
91
  assert_equal %w/lee john,bill/, option_value(%w/-p lee,john,bill/, :p=, :as => Array, :limit => 2)
91
92
  assert_equal %w/lee john:bill/, option_value(%w/-p lee:john:bill/, :p=, :as => Array, :limit => 2, :delimiter => ':')
@@ -109,7 +110,7 @@ class OptionTest < TestCase
109
110
 
110
111
  test "using a default value as fallback" do
111
112
  opts = Slop.new
112
- opt = opts.on :f, :argument => :optional, :default => 'foo'
113
+ opts.on :f, :argument => :optional, :default => 'foo'
113
114
  opts.parse %w'-f'
114
115
  assert_equal 'foo', opts[:f]
115
116
  end
@@ -47,6 +47,11 @@ class SlopTest < TestCase
47
47
  slop = Slop.new { on :foo= }
48
48
  slop.parse %w' --foo=bar '
49
49
  assert_equal 'bar', slop[:foo]
50
+
51
+ slop = Slop.new(:multiple_switches => false) { on :f=; on :b= }
52
+ slop.parse %w' -fabc -bdef '
53
+ assert_equal 'abc', slop[:f]
54
+ assert_equal 'def', slop[:b]
50
55
  end
51
56
 
52
57
  test "fetch_option" do
@@ -175,6 +180,14 @@ class SlopTest < TestCase
175
180
  assert opts.fetch_option(:foo).autocreated?
176
181
  assert_equal 'bar', opts.fetch_option(:foo).value
177
182
  refute opts.fetch_option(:baz).expects_argument?
183
+ assert_equal nil, opts.fetch_option(:bar)
184
+
185
+ opts = Slop.new :autocreate => true do
186
+ on :f, :foo=
187
+ end
188
+ opts.parse %w[ --foo bar --baz stuff ]
189
+ assert_equal 'bar', opts[:foo]
190
+ assert_equal 'stuff', opts[:baz]
178
191
  end
179
192
 
180
193
  test "option terminator" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: slop
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.3.2
4
+ version: 3.3.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-06-26 00:00:00.000000000 Z
12
+ date: 2012-08-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -78,7 +78,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
78
78
  version: '0'
79
79
  segments:
80
80
  - 0
81
- hash: -3236998902673647399
81
+ hash: 3713237527878732625
82
82
  required_rubygems_version: !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
@@ -87,7 +87,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
87
87
  version: '0'
88
88
  segments:
89
89
  - 0
90
- hash: -3236998902673647399
90
+ hash: 3713237527878732625
91
91
  requirements: []
92
92
  rubyforge_project:
93
93
  rubygems_version: 1.8.23