slop 1.3.1 → 1.4.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/.yardopts CHANGED
@@ -3,3 +3,4 @@
3
3
  --title "Slop - Option gathering made easy"
4
4
  lib/**/*.rb
5
5
  --no-private
6
+ --main README.md
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
- 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
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
- Slop.parse do
133
- on :V, :version, 'Print the version' do
134
- puts 'Version 1.0.0'
135
- exit
136
- end
137
- end
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
- opt :people, true, :as => Array, :delimiter => ':', :limit => 2)
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
- begin
264
- slop.parse(%w/--foo --bar -z/)
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 [Regex]
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 expects an optional argument
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} " +
@@ -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 options [Boolean] :help Automatically add the `help` option
42
- # @option options [Boolean] :strict Strict mode raises when a non listed
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
- def initialize(options={}, &block)
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 = options[: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 options[:help]
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
- flag, argument = flag.split('', 2)
205
- option = @options[flag]
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
@@ -1,5 +1,5 @@
1
1
  $:.push File.expand_path('../lib', __FILE__)
2
- require 'slop/version'
2
+ require 'slop'
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = 'slop'
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.3.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-30 00:00:00 +01:00
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/version.rb
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
@@ -1,3 +0,0 @@
1
- class Slop
2
- VERSION = '1.3.1'
3
- end