slop 1.3.1 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.yardopts +1 -0
- data/README.md +35 -15
- data/lib/slop/option.rb +20 -45
- data/lib/slop/options.rb +37 -0
- data/lib/slop.rb +48 -8
- data/slop.gemspec +1 -1
- data/test/slop_test.rb +23 -4
- metadata +3 -3
- data/lib/slop/version.rb +0 -3
data/.yardopts
CHANGED
data/README.md
CHANGED
@@ -103,12 +103,12 @@ Parsing
|
|
103
103
|
|
104
104
|
Slop's pretty good at parsing, let's take a look at what it'll extract for you
|
105
105
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
106
|
+
Slop.parse do
|
107
|
+
on 's', 'server', true
|
108
|
+
on 'p', 'port', true, :as => :integer
|
109
|
+
on 'username', true, :matches => /[^a-zA-Z]+$/
|
110
|
+
on 'password', true
|
111
|
+
end
|
112
112
|
|
113
113
|
Now throw some options at it:
|
114
114
|
|
@@ -129,12 +129,12 @@ Callbacks
|
|
129
129
|
If you'd like to trigger an event when an option is used, you can pass a
|
130
130
|
block to your option. Here's how:
|
131
131
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
132
|
+
Slop.parse do
|
133
|
+
on :V, :version, 'Print the version' do
|
134
|
+
puts 'Version 1.0.0'
|
135
|
+
exit
|
136
|
+
end
|
137
|
+
end
|
138
138
|
|
139
139
|
Now when using the `--version` option on the command line, the trigger will
|
140
140
|
be called and its contents executed.
|
@@ -176,6 +176,26 @@ to return a false value.
|
|
176
176
|
opts[:verbose] #=> false
|
177
177
|
opts.verbose? #=> false
|
178
178
|
|
179
|
+
Short Switches
|
180
|
+
--------------
|
181
|
+
|
182
|
+
Want to enable multiple switches at once like rsync does? By default Slop will
|
183
|
+
parse `-abcd` as the option `a` with the argument `bcd`, this can be disabled
|
184
|
+
by passing the `:multiple_switches` option to a new Slop object.
|
185
|
+
|
186
|
+
opts = Slop.new(:strict, :multiple_switches) do
|
187
|
+
on :a, 'First switch'
|
188
|
+
on :b, 'Second switch'
|
189
|
+
on :c, 'Third switch'
|
190
|
+
end
|
191
|
+
|
192
|
+
opts.parse
|
193
|
+
|
194
|
+
# Using `-ac`
|
195
|
+
opts[:a] #=> true
|
196
|
+
opts[:b] #=> false
|
197
|
+
opts[:c] #=> true
|
198
|
+
|
179
199
|
Ugh, Symbols
|
180
200
|
------------
|
181
201
|
|
@@ -233,7 +253,7 @@ You can of course also parse lists into options. Here's how:
|
|
233
253
|
You can also change both the split delimiter and limit
|
234
254
|
|
235
255
|
opts = Slop.parse do
|
236
|
-
|
256
|
+
opt :people, true, :as => Array, :delimiter => ':', :limit => 2)
|
237
257
|
end
|
238
258
|
|
239
259
|
# ARGV is `--people lee:injekt:bob`
|
@@ -260,8 +280,8 @@ Significantly, however, Slop will still parse the valid options:
|
|
260
280
|
on :n, :name, 'Your name'
|
261
281
|
end
|
262
282
|
|
263
|
-
|
264
|
-
|
283
|
+
begin
|
284
|
+
slop.parse(%w/--foo --bar -z/)
|
265
285
|
rescue Slop::InvalidOptionError => e
|
266
286
|
puts "\n#{e.message}\n\n"
|
267
287
|
puts slop
|
data/lib/slop/option.rb
CHANGED
@@ -1,59 +1,28 @@
|
|
1
1
|
class Slop
|
2
|
-
class Options < Array
|
3
|
-
|
4
|
-
# @param [Boolean] symbols true to cast hash keys to symbols
|
5
|
-
# @return [Hash]
|
6
|
-
def to_hash(symbols)
|
7
|
-
out = {}
|
8
|
-
each do |option|
|
9
|
-
key = option.key
|
10
|
-
key = key.to_sym if symbols
|
11
|
-
out[key] = option.argument_value
|
12
|
-
end
|
13
|
-
out
|
14
|
-
end
|
15
|
-
|
16
|
-
# @param [Object] flag
|
17
|
-
# @return [Option] the option assoiated with this flag
|
18
|
-
def [](flag)
|
19
|
-
item = flag.to_s
|
20
|
-
if item =~ /\A\d+\z/
|
21
|
-
slice item.to_i
|
22
|
-
else
|
23
|
-
find do |option|
|
24
|
-
option.short_flag == item || option.long_flag == item
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
# @return [String]
|
30
|
-
def to_help
|
31
|
-
heads = reject {|x| x.tail }
|
32
|
-
tails = select {|x| x.tail }
|
33
|
-
(heads + tails).map(&:to_s).join("\n")
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
2
|
class Option
|
38
3
|
|
39
|
-
# @return [String, #to_s]
|
4
|
+
# @return [String, #to_s] The short flag used for this option
|
40
5
|
attr_reader :short_flag
|
41
6
|
|
42
|
-
# @return [String, #to_s]
|
7
|
+
# @return [String, #to_s] The long flag used for this option
|
43
8
|
attr_reader :long_flag
|
44
9
|
|
45
|
-
# @return [String]
|
10
|
+
# @return [String] This options description
|
46
11
|
attr_reader :description
|
47
12
|
|
48
|
-
# @return [Proc, #call]
|
13
|
+
# @return [Proc, #call] The object to execute when this option is used
|
49
14
|
attr_reader :callback
|
50
15
|
|
51
|
-
# @return [Boolean]
|
16
|
+
# @return [Boolean] True if the option should be grouped at the
|
17
|
+
# tail of the help list
|
52
18
|
attr_reader :tail
|
53
19
|
|
54
|
-
# @return [
|
20
|
+
# @return [Regexp] If provided, an options argument **must** match this
|
21
|
+
# regexp, otherwise Slop will raise an InvalidArgumentError
|
55
22
|
attr_reader :match
|
56
23
|
|
24
|
+
# @overload argument_value=(value)
|
25
|
+
# Set this options argument value
|
57
26
|
attr_writer :argument_value
|
58
27
|
|
59
28
|
# @param [Slop] slop
|
@@ -66,9 +35,9 @@ class Slop
|
|
66
35
|
# @option options [Boolean] :argument
|
67
36
|
# @option options [Object] :default
|
68
37
|
# @option options [Proc, #call] :callback
|
69
|
-
# @option options [String, #to_s] :delimiter
|
70
|
-
# @option options [Integer] :limit
|
71
|
-
# @option options [Boolean] :tail
|
38
|
+
# @option options [String, #to_s] :delimiter (',')
|
39
|
+
# @option options [Integer] :limit (0)
|
40
|
+
# @option options [Boolean] :tail (false)
|
72
41
|
# @option options [Regexp] :match
|
73
42
|
def initialize(slop, short, long, description, argument, options={}, &blk)
|
74
43
|
@slop = slop
|
@@ -102,7 +71,7 @@ class Slop
|
|
102
71
|
@expects_argument || @options[:argument]
|
103
72
|
end
|
104
73
|
|
105
|
-
# @return [Boolean] true if this option
|
74
|
+
# @return [Boolean] true if this option accepts an optional argument
|
106
75
|
def accepts_optional_argument?
|
107
76
|
@options[:optional]
|
108
77
|
end
|
@@ -140,10 +109,15 @@ class Slop
|
|
140
109
|
@forced = true
|
141
110
|
end
|
142
111
|
|
112
|
+
# @return [Boolean] true if this argument value has been forced
|
143
113
|
def forced?
|
144
114
|
@forced
|
145
115
|
end
|
146
116
|
|
117
|
+
# This option in a nice pretty string, including a short flag, long
|
118
|
+
# flag, and description (if they exist).
|
119
|
+
# @see Slop#help
|
120
|
+
# @return [String]
|
147
121
|
def to_s
|
148
122
|
out = " "
|
149
123
|
out += @short_flag ? "-#{@short_flag}, " : ' ' * 4
|
@@ -161,6 +135,7 @@ class Slop
|
|
161
135
|
"#{out}#{@description}"
|
162
136
|
end
|
163
137
|
|
138
|
+
# @return [String]
|
164
139
|
def inspect
|
165
140
|
"#<Slop::Option short_flag=#{@short_flag.inspect} " +
|
166
141
|
"long_flag=#{@long_flag.inspect} " +
|
data/lib/slop/options.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
class Slop
|
2
|
+
class Options < Array
|
3
|
+
|
4
|
+
# @param [Boolean] symbols true to cast hash keys to symbols
|
5
|
+
# @return [Hash]
|
6
|
+
def to_hash(symbols)
|
7
|
+
out = {}
|
8
|
+
each do |option|
|
9
|
+
key = option.key
|
10
|
+
key = key.to_sym if symbols
|
11
|
+
out[key] = option.argument_value
|
12
|
+
end
|
13
|
+
out
|
14
|
+
end
|
15
|
+
|
16
|
+
# @param [Object] flag The short/long flag representing the option
|
17
|
+
# @return [Option] the option assoiated with this flag
|
18
|
+
def [](flag)
|
19
|
+
item = flag.to_s
|
20
|
+
if item =~ /\A\d+\z/
|
21
|
+
slice item.to_i
|
22
|
+
else
|
23
|
+
find do |option|
|
24
|
+
option.short_flag == item || option.long_flag == item
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# @see Slop#help
|
30
|
+
# @return [String] All options in a pretty help string
|
31
|
+
def to_help
|
32
|
+
heads = reject {|x| x.tail }
|
33
|
+
tails = select {|x| x.tail }
|
34
|
+
(heads + tails).map(&:to_s).join("\n")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/slop.rb
CHANGED
@@ -1,13 +1,23 @@
|
|
1
|
+
require 'slop/options'
|
1
2
|
require 'slop/option'
|
2
|
-
require 'slop/version'
|
3
3
|
|
4
4
|
class Slop
|
5
5
|
include Enumerable
|
6
6
|
|
7
|
+
# Raised when an option expects an argument and none is given
|
7
8
|
class MissingArgumentError < RuntimeError; end
|
9
|
+
|
10
|
+
# Raised when an option specifies the `:match` attribute and this
|
11
|
+
# options argument does not match this regexp
|
8
12
|
class InvalidArgumentError < RuntimeError; end
|
13
|
+
|
14
|
+
# Raised when the `:strict` option is enabled and an unknown
|
15
|
+
# or unspecified option is used
|
9
16
|
class InvalidOptionError < RuntimeError; end
|
10
17
|
|
18
|
+
# @return [String] The current version string
|
19
|
+
VERSION = '1.4.0'
|
20
|
+
|
11
21
|
# Parses the items from a CLI format into a friendly object.
|
12
22
|
#
|
13
23
|
# @param [Array] items Items to parse into options.
|
@@ -38,21 +48,29 @@ class Slop
|
|
38
48
|
attr_accessor :longest_flag
|
39
49
|
|
40
50
|
# @param [Hash] options
|
41
|
-
# @option
|
42
|
-
# @option
|
51
|
+
# @option opts [Boolean] :help Automatically add the `help` option
|
52
|
+
# @option opts [Boolean] :strict Strict mode raises when a non listed
|
43
53
|
# option is found, false by default
|
44
|
-
|
54
|
+
# @option opts [Boolean] :multiple_switches Allows `-abc` to be processed
|
55
|
+
# as the options 'a', 'b', 'c' and will force their argument values to
|
56
|
+
# true. By default Slop with parse this as 'a' with the argument 'bc'
|
57
|
+
def initialize(*opts, &block)
|
58
|
+
sloptions = {}
|
59
|
+
sloptions.merge! opts.pop if opts.last.is_a? Hash
|
60
|
+
opts.each { |o| sloptions[o] = true }
|
61
|
+
|
45
62
|
@options = Options.new
|
46
63
|
@banner = nil
|
47
64
|
@longest_flag = 0
|
48
|
-
@strict =
|
65
|
+
@strict = sloptions[:strict]
|
49
66
|
@invalid_options = []
|
67
|
+
@multiple_switches = sloptions[:multiple_switches]
|
50
68
|
|
51
69
|
if block_given?
|
52
70
|
block.arity == 1 ? yield(self) : instance_eval(&block)
|
53
71
|
end
|
54
72
|
|
55
|
-
if
|
73
|
+
if sloptions[:help]
|
56
74
|
on :h, :help, 'Print this help message', :tail => true do
|
57
75
|
puts help
|
58
76
|
exit
|
@@ -201,8 +219,13 @@ private
|
|
201
219
|
unless option
|
202
220
|
case item
|
203
221
|
when /\A-[^-]/
|
204
|
-
|
205
|
-
|
222
|
+
if @multiple_switches
|
223
|
+
enable_multiple_switches(item)
|
224
|
+
next
|
225
|
+
else
|
226
|
+
flag, argument = flag.split('', 2)
|
227
|
+
option = @options[flag]
|
228
|
+
end
|
206
229
|
when /\A--([^=]+)=(.+)\z/
|
207
230
|
option = @options[$1]
|
208
231
|
argument = $2
|
@@ -270,6 +293,23 @@ private
|
|
270
293
|
@invalid_options << flag if item[/\A--?/] && @strict
|
271
294
|
end
|
272
295
|
|
296
|
+
def enable_multiple_switches(item)
|
297
|
+
item[1..-1].split('').each do |switch|
|
298
|
+
if option = @options[switch]
|
299
|
+
if option.expects_argument?
|
300
|
+
raise MissingArgumentError,
|
301
|
+
"'-#{switch}' expects an argument, used in multiple_switch context"
|
302
|
+
else
|
303
|
+
option.argument_value = true
|
304
|
+
end
|
305
|
+
else
|
306
|
+
if @strict
|
307
|
+
raise InvalidOptionError, "Unknown option '-#{switch}'"
|
308
|
+
end
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
273
313
|
def clean_options(args)
|
274
314
|
options = []
|
275
315
|
|
data/slop.gemspec
CHANGED
data/test/slop_test.rb
CHANGED
@@ -5,14 +5,18 @@ class SlopTest < TestCase
|
|
5
5
|
Slop.new.send(:clean_options, args)
|
6
6
|
end
|
7
7
|
|
8
|
-
def parse(items, &block)
|
9
|
-
Slop.parse(items, &block)
|
10
|
-
end
|
11
|
-
|
12
8
|
test 'includes Enumerable' do
|
13
9
|
assert Slop.included_modules.include?(Enumerable)
|
14
10
|
end
|
15
11
|
|
12
|
+
test 'new accepts a hash or array of symbols' do
|
13
|
+
slop = Slop.new :strict, :multiple_switches => true
|
14
|
+
|
15
|
+
[ :@multiple_switches, :@strict ].each do |var|
|
16
|
+
assert slop.instance_variable_get var
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
16
20
|
test 'parse returns a Slop object' do
|
17
21
|
slop = Slop.parse([])
|
18
22
|
assert_kind_of Slop, slop
|
@@ -26,6 +30,21 @@ class SlopTest < TestCase
|
|
26
30
|
slop.each { |option| assert option }
|
27
31
|
end
|
28
32
|
|
33
|
+
test 'multiple switches with the :multiple_switches flag' do
|
34
|
+
slop = Slop.new :multiple_switches => true, :strict => true
|
35
|
+
%w/a b c/.each { |f| slop.on f }
|
36
|
+
slop.on :z, true
|
37
|
+
slop.parse %w/-abc/
|
38
|
+
|
39
|
+
%w/a b c/.each do |flag|
|
40
|
+
assert slop[flag]
|
41
|
+
assert slop.send(flag + '?')
|
42
|
+
end
|
43
|
+
|
44
|
+
assert_raises(Slop::InvalidOptionError, /d/) { slop.parse %w/-abcd/ }
|
45
|
+
assert_raises(Slop::MissingArgumentError, /z/) { slop.parse %w/-abcz/ }
|
46
|
+
end
|
47
|
+
|
29
48
|
test 'passing a block' do
|
30
49
|
assert Slop.new {}
|
31
50
|
slop = nil
|
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.4.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-03
|
13
|
+
date: 2011-04-03 00:00:00 +01:00
|
14
14
|
default_executable:
|
15
15
|
dependencies: []
|
16
16
|
|
@@ -31,7 +31,7 @@ files:
|
|
31
31
|
- Rakefile
|
32
32
|
- lib/slop.rb
|
33
33
|
- lib/slop/option.rb
|
34
|
-
- lib/slop/
|
34
|
+
- lib/slop/options.rb
|
35
35
|
- slop.gemspec
|
36
36
|
- test/helper.rb
|
37
37
|
- test/option_test.rb
|
data/lib/slop/version.rb
DELETED