slop 1.5.5 → 1.6.0
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 +41 -0
- data/lib/slop.rb +70 -33
- data/lib/slop/option.rb +30 -11
- data/lib/slop/options.rb +6 -0
- data/test/option_test.rb +26 -3
- data/test/slop_test.rb +24 -0
- metadata +3 -2
data/CHANGES.md
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
1.6.0 (2011-05-18)
|
2
|
+
------------------
|
3
|
+
|
4
|
+
* Add `:ignore_case` to Slop options for case insensitive option matching
|
5
|
+
* Add `:on_noopts` for triggering an event when the arguments contain no
|
6
|
+
options
|
7
|
+
* Add `:unless` to Slop::Option for omitting execution of the Options block
|
8
|
+
when this object exists in the Array of items passed to Slop.new
|
9
|
+
* Bugfix: Do not parse negative integers as options. A valid option must
|
10
|
+
start with an alphabet character
|
11
|
+
* Bugfix: Allow a Range to accept a negative Integer at either end
|
12
|
+
|
13
|
+
1.5.5 (2011-05-03)
|
14
|
+
------------------
|
15
|
+
|
16
|
+
* Bugfix: only attempt to extract options prefixed with `-`
|
17
|
+
|
18
|
+
1.5.4 (2011-05-01)
|
19
|
+
------------------
|
20
|
+
|
21
|
+
* Bugfix: `parse!` should not remove items with the same value as items used
|
22
|
+
in option arguments. Fixes #22 (Utkarsh Kukreti)
|
23
|
+
|
24
|
+
1.5.3 (2011-04-22)
|
25
|
+
------------------
|
26
|
+
|
27
|
+
* Bugfix: Use integers when fetching array indexes, not strings
|
28
|
+
|
29
|
+
1.5.2 (2011-04-17)
|
30
|
+
------------------
|
31
|
+
|
32
|
+
* Bugfix: Ensure `ARGV` is empty when using the `on_empty` event
|
33
|
+
|
34
|
+
1.5.0 (2011-04-15)
|
35
|
+
------------------
|
36
|
+
|
37
|
+
* Add `Slop#get` as alias to `Slop#[]`
|
38
|
+
* Add `Slop#present?` as alias for `Slop#<option>?`
|
39
|
+
* Add `Option#count` for monitoring how many times an option is called
|
40
|
+
* Add `:io` for using a custom IO object when using the `:help` option
|
41
|
+
* Numerous performance tweaks
|
data/lib/slop.rb
CHANGED
@@ -16,7 +16,7 @@ class Slop
|
|
16
16
|
class InvalidOptionError < RuntimeError; end
|
17
17
|
|
18
18
|
# @return [String] The current version string
|
19
|
-
VERSION = '1.
|
19
|
+
VERSION = '1.6.0'
|
20
20
|
|
21
21
|
# Parses the items from a CLI format into a friendly object.
|
22
22
|
#
|
@@ -69,6 +69,9 @@ class Slop
|
|
69
69
|
# :help => true is used
|
70
70
|
# @option opts [Boolean] :exit_on_help (true) When false and coupled with
|
71
71
|
# the :help option, Slop will not exit inside of the `help` option
|
72
|
+
# @option opts [Boolean] :ignore_case (false) Ignore options case
|
73
|
+
# @option opts [Proc, #call] :on_noopts Trigger an event when no options
|
74
|
+
# are found
|
72
75
|
def initialize(*opts, &block)
|
73
76
|
sloptions = {}
|
74
77
|
sloptions.merge! opts.pop if opts.last.is_a? Hash
|
@@ -83,8 +86,10 @@ class Slop
|
|
83
86
|
|
84
87
|
@banner = sloptions[:banner]
|
85
88
|
@strict = sloptions[:strict]
|
89
|
+
@ignore_case = sloptions[:ignore_case]
|
86
90
|
@multiple_switches = sloptions[:multiple_switches]
|
87
91
|
@on_empty = sloptions[:on_empty]
|
92
|
+
@on_noopts = sloptions[:on_noopts] || sloptions[:on_optionless]
|
88
93
|
@sloptions = sloptions
|
89
94
|
|
90
95
|
io = sloptions[:io] || $stderr
|
@@ -117,14 +122,14 @@ class Slop
|
|
117
122
|
|
118
123
|
# Parse a list of options, leaving the original Array unchanged.
|
119
124
|
#
|
120
|
-
# @param items
|
125
|
+
# @param [Array] items A list of items to parse
|
121
126
|
def parse(items=ARGV, &block)
|
122
127
|
parse_items items, &block
|
123
128
|
end
|
124
129
|
|
125
130
|
# Parse a list of options, removing parsed options from the original Array.
|
126
131
|
#
|
127
|
-
# @param items
|
132
|
+
# @param [Array] items A list of items to parse
|
128
133
|
def parse!(items=ARGV, &block)
|
129
134
|
parse_items items, true, &block
|
130
135
|
end
|
@@ -152,7 +157,8 @@ class Slop
|
|
152
157
|
# @option args [Symbol, String] :short_flag Short option name.
|
153
158
|
# @option args [Symbol, String] :long_flag Full option name.
|
154
159
|
# @option args [String] :description Option description for use in Slop#help
|
155
|
-
# @option args [Boolean] :argument Specifies whether
|
160
|
+
# @option args [Boolean] :argument Specifies whether this option requires
|
161
|
+
# an argument
|
156
162
|
# @option args [Hash] :options Optional option configurations.
|
157
163
|
# @example
|
158
164
|
# opts = Slop.parse do
|
@@ -210,10 +216,10 @@ class Slop
|
|
210
216
|
slop
|
211
217
|
end
|
212
218
|
|
213
|
-
#
|
219
|
+
# Trigger an event when Slop has no values to parse
|
214
220
|
#
|
215
221
|
# @param [Object, nil] proc The object (which can be anything
|
216
|
-
# responding to
|
222
|
+
# responding to `call`)
|
217
223
|
# @example
|
218
224
|
# Slop.parse do
|
219
225
|
# on_empty { puts 'No argument given!' }
|
@@ -224,6 +230,20 @@ class Slop
|
|
224
230
|
end
|
225
231
|
alias :on_empty= :on_empty
|
226
232
|
|
233
|
+
# Trigger an event when the arguments contain no options
|
234
|
+
#
|
235
|
+
# @param [Object, nil] obj The object to be triggered (anything
|
236
|
+
# responding to `call`)
|
237
|
+
# @example
|
238
|
+
# Slop.parse do
|
239
|
+
# on_noopts { puts 'No options here!' }
|
240
|
+
# end
|
241
|
+
# @since 1.6.0
|
242
|
+
def on_noopts(obj=nil, &block)
|
243
|
+
@on_noopts ||= (obj || block)
|
244
|
+
end
|
245
|
+
alias :on_optionless :on_noopts
|
246
|
+
|
227
247
|
# Returns the parsed list into a option/value hash.
|
228
248
|
#
|
229
249
|
# @example
|
@@ -253,6 +273,7 @@ class Slop
|
|
253
273
|
# Slop#option? but a convenience method for unacceptable method names.
|
254
274
|
#
|
255
275
|
# @param [Object] The object name to check
|
276
|
+
# @since 1.5.0
|
256
277
|
# @return [Boolean] true if this option is present
|
257
278
|
def present?(option_name)
|
258
279
|
!!get(option_name)
|
@@ -298,7 +319,10 @@ class Slop
|
|
298
319
|
def parse_items(items, delete=false, &block)
|
299
320
|
if items.empty? && @on_empty.respond_to?(:call)
|
300
321
|
@on_empty.call self
|
301
|
-
return
|
322
|
+
return items
|
323
|
+
elsif !items.any? {|i| i.to_s[/\A--?/] } && @on_noopts.respond_to?(:call)
|
324
|
+
@on_noopts.call self
|
325
|
+
return items
|
302
326
|
end
|
303
327
|
|
304
328
|
return if execute_command(items, delete)
|
@@ -308,26 +332,8 @@ class Slop
|
|
308
332
|
items.each_with_index do |item, index|
|
309
333
|
item = item.to_s
|
310
334
|
flag = item.sub(/\A--?/, '')
|
311
|
-
option =
|
312
|
-
|
313
|
-
unless option
|
314
|
-
case item
|
315
|
-
when /\A-[^-]/
|
316
|
-
if @multiple_switches
|
317
|
-
enable_multiple_switches(item)
|
318
|
-
next
|
319
|
-
else
|
320
|
-
flag, argument = flag.split('', 2)
|
321
|
-
option = @options[flag]
|
322
|
-
end
|
323
|
-
when /\A--([^=]+)=(.+)\z/
|
324
|
-
option = @options[$1]
|
325
|
-
argument = $2
|
326
|
-
when /\A--no-(.+)\z/
|
327
|
-
option = @options[$1]
|
328
|
-
option.force_argument_value(false) if option
|
329
|
-
end
|
330
|
-
end
|
335
|
+
option, argument = extract_option(item, flag)
|
336
|
+
next if @multiple_switches
|
331
337
|
|
332
338
|
if option
|
333
339
|
option.count += 1
|
@@ -343,13 +349,13 @@ class Slop
|
|
343
349
|
if argument
|
344
350
|
check_matching_argument!(option, argument)
|
345
351
|
option.argument_value = argument
|
346
|
-
option.
|
352
|
+
option.call option.argument_value unless option.omit_exec?(items)
|
347
353
|
else
|
348
354
|
option.argument_value = nil
|
349
355
|
check_optional_argument!(option, flag)
|
350
356
|
end
|
351
|
-
|
352
|
-
option.
|
357
|
+
else
|
358
|
+
option.call unless option.omit_exec?(items)
|
353
359
|
end
|
354
360
|
else
|
355
361
|
check_invalid_option!(item, flag)
|
@@ -363,7 +369,7 @@ class Slop
|
|
363
369
|
end
|
364
370
|
|
365
371
|
def check_valid_argument!(option, argument)
|
366
|
-
if !option.accepts_optional_argument? && argument
|
372
|
+
if !option.accepts_optional_argument? && flag?(argument)
|
367
373
|
raise MissingArgumentError,
|
368
374
|
"'#{option.key}' expects an argument, none given"
|
369
375
|
end
|
@@ -378,7 +384,7 @@ class Slop
|
|
378
384
|
|
379
385
|
def check_optional_argument!(option, flag)
|
380
386
|
if option.accepts_optional_argument?
|
381
|
-
option.
|
387
|
+
option.call
|
382
388
|
else
|
383
389
|
raise MissingArgumentError,
|
384
390
|
"'#{flag}' expects an argument, none given"
|
@@ -414,6 +420,33 @@ class Slop
|
|
414
420
|
end
|
415
421
|
end
|
416
422
|
|
423
|
+
def extract_option(item, flag)
|
424
|
+
if item[0, 1] == '-'
|
425
|
+
option = @options[flag]
|
426
|
+
if !option && @ignore_case
|
427
|
+
option = @options[flag.downcase]
|
428
|
+
end
|
429
|
+
end
|
430
|
+
unless option
|
431
|
+
case item
|
432
|
+
when /\A-[^-]/
|
433
|
+
if @multiple_switches
|
434
|
+
enable_multiple_switches(item)
|
435
|
+
else
|
436
|
+
flag, argument = flag.split('', 2)
|
437
|
+
option = @options[flag]
|
438
|
+
end
|
439
|
+
when /\A--([^=]+)=(.+)\z/
|
440
|
+
option = @options[$1]
|
441
|
+
argument = $2
|
442
|
+
when /\A--no-(.+)\z/
|
443
|
+
option = @options[$1]
|
444
|
+
option.force_argument_value(false) if option
|
445
|
+
end
|
446
|
+
end
|
447
|
+
[option, argument]
|
448
|
+
end
|
449
|
+
|
417
450
|
def execute_command(items, delete)
|
418
451
|
command = items[0]
|
419
452
|
command = @commands.keys.find { |cmd| cmd.to_s == command.to_s }
|
@@ -438,7 +471,7 @@ class Slop
|
|
438
471
|
|
439
472
|
long = args.first
|
440
473
|
boolean = [true, false].include?(long)
|
441
|
-
if !boolean && long.to_s =~ /\A(?:--?)?[a-zA-Z0-9_-]+\z/
|
474
|
+
if !boolean && long.to_s =~ /\A(?:--?)?[a-zA-Z][a-zA-Z0-9_-]+\z/
|
442
475
|
options.push args.shift.to_s.sub(/\A--?/, '')
|
443
476
|
else
|
444
477
|
options.push nil
|
@@ -447,4 +480,8 @@ class Slop
|
|
447
480
|
options.push args.first.respond_to?(:to_sym) ? args.shift : nil
|
448
481
|
options.push args.shift ? true : false # force true/false
|
449
482
|
end
|
483
|
+
|
484
|
+
def flag?(str)
|
485
|
+
str =~ /\A--?[a-zA-Z][a-zA-Z0-9_-]+\z/
|
486
|
+
end
|
450
487
|
end
|
data/lib/slop/option.rb
CHANGED
@@ -10,9 +10,6 @@ class Slop
|
|
10
10
|
# @return [String] This options description
|
11
11
|
attr_reader :description
|
12
12
|
|
13
|
-
# @return [Proc, #call] The object to execute when this option is used
|
14
|
-
attr_reader :callback
|
15
|
-
|
16
13
|
# @return [Boolean] True if the option should be grouped at the
|
17
14
|
# tail of the help list
|
18
15
|
attr_reader :tail
|
@@ -35,6 +32,10 @@ class Slop
|
|
35
32
|
# @return [Integer] The amount of times this option has been invoked
|
36
33
|
attr_accessor :count
|
37
34
|
|
35
|
+
# @return [Object] Omit execution of this Options block or callback if
|
36
|
+
# this object exists in the Array of items passed to `Slop.new`
|
37
|
+
attr_accessor :unless
|
38
|
+
|
38
39
|
# @param [Slop] slop
|
39
40
|
# @param [String, #to_s] short
|
40
41
|
# @param [String, #to_s] long
|
@@ -49,6 +50,7 @@ class Slop
|
|
49
50
|
# @option options [Integer] :limit (0)
|
50
51
|
# @option options [Boolean] :tail (false)
|
51
52
|
# @option options [Regexp] :match
|
53
|
+
# @option options [String, #to_s] :unless
|
52
54
|
# @option options [Boolean, String] :help
|
53
55
|
def initialize(slop, short, long, description, argument, options={}, &blk)
|
54
56
|
@slop = slop
|
@@ -64,6 +66,7 @@ class Slop
|
|
64
66
|
@match = options[:match]
|
65
67
|
@delimiter = options[:delimiter] || ','
|
66
68
|
@limit = options[:limit] || 0
|
69
|
+
@unless = options[:unless]
|
67
70
|
@help = options[:help]
|
68
71
|
@help = true if @help.nil?
|
69
72
|
|
@@ -92,7 +95,7 @@ class Slop
|
|
92
95
|
@long_flag || @short_flag
|
93
96
|
end
|
94
97
|
|
95
|
-
# @return [Object] the argument value after it's been
|
98
|
+
# @return [Object] the argument value after it's been cast
|
96
99
|
# according to the `:as` option
|
97
100
|
def argument_value
|
98
101
|
return @argument_value if @forced
|
@@ -122,8 +125,24 @@ class Slop
|
|
122
125
|
@forced = true
|
123
126
|
end
|
124
127
|
|
128
|
+
# Execute the block or callback object associated with this Option
|
129
|
+
#
|
130
|
+
# @param [Object] The object to be sent to `:call`
|
131
|
+
def call(obj=nil)
|
132
|
+
@callback.call(obj) if @callback.respond_to?(:call)
|
133
|
+
end
|
134
|
+
|
135
|
+
# @param [Array] items The original array of objects passed to `Slop.new`
|
136
|
+
# @return [Boolean] true if this options `:unless` argument exists
|
137
|
+
# inside *items*
|
138
|
+
def omit_exec?(items)
|
139
|
+
string = @unless.to_s.sub(/\A--?/, '')
|
140
|
+
items.any? { |i| i.to_s.sub(/\A--?/, '') == string }
|
141
|
+
end
|
142
|
+
|
125
143
|
# This option in a nice pretty string, including a short flag, long
|
126
|
-
#
|
144
|
+
# flag, and description (if they exist).
|
145
|
+
#
|
127
146
|
# @see Slop#help
|
128
147
|
# @return [String]
|
129
148
|
def to_s
|
@@ -160,12 +179,12 @@ class Slop
|
|
160
179
|
|
161
180
|
def value_to_range(value)
|
162
181
|
case value.to_s
|
163
|
-
when /\A(
|
164
|
-
|
165
|
-
when /\A(
|
166
|
-
|
167
|
-
when /\A
|
168
|
-
|
182
|
+
when /\A(-?\d+?)(?:\.\.|-|,)(-?\d+)\z/
|
183
|
+
$1.to_i .. $2.to_i
|
184
|
+
when /\A(-?\d+?)\.\.\.(-?\d+)\z/
|
185
|
+
$1.to_i ... $2.to_i
|
186
|
+
when /\A-?\d+\z/
|
187
|
+
value.to_i
|
169
188
|
else
|
170
189
|
value
|
171
190
|
end
|
data/lib/slop/options.rb
CHANGED
@@ -12,7 +12,13 @@ class Slop
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
+
# Fetch an Option object
|
16
|
+
#
|
15
17
|
# @param [Object] flag The short/long flag representing the option
|
18
|
+
# @example
|
19
|
+
# opts = Slop.parse { on :v, "Verbose mode" }
|
20
|
+
# opts.options[:v] #=> Option
|
21
|
+
# opts.options[:v].description #=> "Verbose mode"
|
16
22
|
# @return [Option] the option assoiated with this flag
|
17
23
|
def [](flag)
|
18
24
|
if flag.is_a?(Integer)
|
data/test/option_test.rb
CHANGED
@@ -33,10 +33,14 @@ class OptionTest < TestCase
|
|
33
33
|
end
|
34
34
|
|
35
35
|
test 'has a callback when passed a block or callback option' do
|
36
|
-
|
37
|
-
|
36
|
+
item = nil
|
37
|
+
option(:f){ item = "foo" }.call
|
38
|
+
assert_equal "foo", item
|
38
39
|
|
39
|
-
|
40
|
+
assert option(:callback => proc { item = "bar" }).call
|
41
|
+
assert_equal "bar", item
|
42
|
+
|
43
|
+
refute option(:f).call
|
40
44
|
end
|
41
45
|
|
42
46
|
test 'splits argument_value with :as => array' do
|
@@ -66,6 +70,11 @@ class OptionTest < TestCase
|
|
66
70
|
assert_equal :foo, option_value(%w/--name foo/, :name, true, :as => :sym)
|
67
71
|
assert_equal 30, option_value(%w/--age 30/, :age, true, :as => Integer)
|
68
72
|
assert_equal "1.0", option_value(%w/--id 1/, :id, true, :as => Float).to_s
|
73
|
+
|
74
|
+
assert_equal -1, option_value(%w/-i -1/, :i, true, :as => Integer)
|
75
|
+
assert_equal -1, option_value(%w/-i -1.1/, :i, true, :as => Integer)
|
76
|
+
assert_equal "-1.1", option_value(%w/-i -1.1/, :i, true, :as => Float).to_s
|
77
|
+
assert_equal "foo", option_value(%w/--foo1 foo/, :foo1, true)
|
69
78
|
end
|
70
79
|
|
71
80
|
test 'ranges' do
|
@@ -73,6 +82,8 @@ class OptionTest < TestCase
|
|
73
82
|
assert_equal (1..10), option_value(%w/-r 1-10/, :r, true, :as => Range)
|
74
83
|
assert_equal (1..10), option_value(%w/-r 1,10/, :r, true, :as => Range)
|
75
84
|
assert_equal (1...10), option_value(%w/-r 1...10/, :r, true, :as => Range)
|
85
|
+
assert_equal (-1..10), option_value(%w/-r -1..10/, :r, true, :as => Range)
|
86
|
+
assert_equal (1..-10), option_value(%w/-r 1..-10/, :r, true, :as => Range)
|
76
87
|
|
77
88
|
# default back to the string unless a regex is successful
|
78
89
|
# return value.to_i if the value is /\A\d+\z/
|
@@ -145,4 +156,16 @@ class OptionTest < TestCase
|
|
145
156
|
assert_equal 1, slop.options[:x].count
|
146
157
|
assert_equal 3, slop.options[:v].count
|
147
158
|
end
|
159
|
+
|
160
|
+
test 'omit block execution with :unless option' do
|
161
|
+
item = nil
|
162
|
+
opts = Slop.new do
|
163
|
+
on :foo
|
164
|
+
on :bar, true, :unless => 'foo' do; item = "foo"; end
|
165
|
+
end
|
166
|
+
opts.parse %w/--foo --bar 1/
|
167
|
+
|
168
|
+
assert_equal "1", opts[:bar]
|
169
|
+
refute item
|
170
|
+
end
|
148
171
|
end
|
data/test/slop_test.rb
CHANGED
@@ -29,6 +29,15 @@ class SlopTest < TestCase
|
|
29
29
|
assert_kind_of Slop, slop
|
30
30
|
end
|
31
31
|
|
32
|
+
test 'parsing calls to_s on all of the items in the array' do
|
33
|
+
opts = Slop.parse([:'--foo']) { on :foo }
|
34
|
+
assert opts.foo?
|
35
|
+
end
|
36
|
+
|
37
|
+
test '#opt returns an Slop::Option' do
|
38
|
+
assert_kind_of Slop::Option, Slop.new.option(:n)
|
39
|
+
end
|
40
|
+
|
32
41
|
test 'enumerating options' do
|
33
42
|
slop = Slop.new
|
34
43
|
slop.opt(:f, :foo, 'foo')
|
@@ -50,6 +59,13 @@ class SlopTest < TestCase
|
|
50
59
|
end
|
51
60
|
|
52
61
|
assert_equal 'foo', item1
|
62
|
+
assert_equal [], Slop.new { on_empty {} }.parse
|
63
|
+
end
|
64
|
+
|
65
|
+
test 'callback when arguments contain no options' do
|
66
|
+
item = nil
|
67
|
+
Slop.new { on_optionless { item = 'foo' } }.parse %w/a b c/
|
68
|
+
assert_equal 'foo', item
|
53
69
|
end
|
54
70
|
|
55
71
|
test 'multiple switches with the :multiple_switches flag' do
|
@@ -136,6 +152,7 @@ class SlopTest < TestCase
|
|
136
152
|
end
|
137
153
|
assert_equal %w/a/, opts.parse!(%w/--name lee a/)
|
138
154
|
assert_equal %w/--name lee a/, opts.parse(%w/--name lee a/)
|
155
|
+
assert_equal ['foo', :bar, 1], opts.parse(['foo', :bar, 1])
|
139
156
|
end
|
140
157
|
|
141
158
|
test '#parse does not remove parsed items' do
|
@@ -359,4 +376,11 @@ class SlopTest < TestCase
|
|
359
376
|
opts = Slop.new(:help => true, :io => io, :exit_on_help => false)
|
360
377
|
assert opts.parse %w/--help/
|
361
378
|
end
|
379
|
+
|
380
|
+
test 'ignoring case' do
|
381
|
+
opts = Slop.new(:ignore_case => true)
|
382
|
+
opts.on :n, :name, true
|
383
|
+
opts.parse %w/--NAME lee/
|
384
|
+
assert_equal 'lee', opts[:name]
|
385
|
+
end
|
362
386
|
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: slop
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 1.
|
5
|
+
version: 1.6.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Lee Jarvis
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-05-
|
13
|
+
date: 2011-05-18 00:00:00 +01:00
|
14
14
|
default_executable:
|
15
15
|
dependencies: []
|
16
16
|
|
@@ -26,6 +26,7 @@ files:
|
|
26
26
|
- .gemtest
|
27
27
|
- .gitignore
|
28
28
|
- .yardopts
|
29
|
+
- CHANGES.md
|
29
30
|
- LICENSE
|
30
31
|
- README.md
|
31
32
|
- Rakefile
|