slop 1.2.0 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
+ .rvmrc
1
2
  .yardoc
2
3
  doc
3
4
  *.swp
data/README.md CHANGED
@@ -13,8 +13,8 @@ Installation
13
13
  ### GitHub
14
14
 
15
15
  git clone git://github.com/injekt/slop.git
16
- gem build slop.gemspec
17
- gem install slop-<version>.gem
16
+ gem build slop.gemspec
17
+ gem install slop-<version>.gem
18
18
 
19
19
  Usage
20
20
  -----
@@ -40,23 +40,6 @@ You can also return your options as a Hash
40
40
  # Symbols
41
41
  opts.to_hash(true) #=> {:name => 'Lee Jarvis', :verbose => true, :age => nil, :sex => 'male'}
42
42
 
43
- If you pass a block to `Slop#parse`, Slop will yield non-options as
44
- they're found, just like
45
- [OptionParser](http://rubydoc.info/stdlib/optparse/1.9.2/OptionParser:order)
46
- does it.
47
-
48
- opts = Slop.new do
49
- on :n, :name, :optional => false
50
- end
51
-
52
- opts.parse do |arg|
53
- puts arg
54
- end
55
-
56
- # if ARGV is `foo --name Lee bar`
57
- foo
58
- bar
59
-
60
43
  If you don't like the method `on` (because it sounds like the option **expects**
61
44
  a block), you can use the `opt` or `option` alternatives.
62
45
 
@@ -81,7 +64,7 @@ send the Slop object to `puts` or use the `help` method.
81
64
 
82
65
  Will output something like
83
66
 
84
- -v, --verbose Enable verbose mode
67
+ -v, --verbose Enable verbose mode
85
68
  -n, --name Your name
86
69
  -a, --age Your age
87
70
 
@@ -96,22 +79,78 @@ or
96
79
  banner "Usage: foo.rb [options]"
97
80
  end
98
81
 
82
+ Helpful Help
83
+ ------------
84
+
85
+ Long form:
86
+
87
+ Slop.parse do
88
+ ...
89
+ on :h, :help, 'Print this help message', :tail => true do
90
+ puts help
91
+ exit
92
+ end
93
+ end
94
+
95
+ Shortcut:
96
+
97
+ Slop.parse :help => true do
98
+ ...
99
+ end
100
+
99
101
  Callbacks
100
102
  ---------
101
103
 
102
104
  If you'd like to trigger an event when an option is used, you can pass a
103
105
  block to your option. Here's how:
104
106
 
105
- Slop.parse do
106
- on :V, :version, 'Print the version' do
107
- puts 'Version 1.0.0'
108
- exit
109
- end
110
- end
107
+ Slop.parse do
108
+ on :V, :version, 'Print the version' do
109
+ puts 'Version 1.0.0'
110
+ exit
111
+ end
112
+ end
111
113
 
112
114
  Now when using the `--version` option on the command line, the trigger will
113
115
  be called and its contents executed.
114
116
 
117
+ Yielding Non Options
118
+ --------------------
119
+
120
+ If you pass a block to `Slop#parse`, Slop will yield non-options as
121
+ they're found, just like
122
+ [OptionParser](http://rubydoc.info/stdlib/optparse/1.9.2/OptionParser:order)
123
+ does it.
124
+
125
+ opts = Slop.new do
126
+ on :n, :name, :optional => false
127
+ end
128
+
129
+ opts.parse do |arg|
130
+ puts arg
131
+ end
132
+
133
+ # if ARGV is `foo --name Lee bar`
134
+ foo
135
+ bar
136
+
137
+ Negative Options
138
+ ----------------
139
+
140
+ Slop also allows you to prefix `--no-` to an option which will force the option
141
+ to return a false value.
142
+
143
+ opts = Slop.parse do
144
+ on :v, :verbose, :default => true
145
+ end
146
+
147
+ # with no command line options
148
+ opts[:verbose] #=> true
149
+
150
+ # with `--no-verbose`
151
+ opts[:verbose] #=> false
152
+ opts.verbose? #=> false
153
+
115
154
  Ugh, Symbols
116
155
  ------------
117
156
 
@@ -141,18 +180,18 @@ Slop is pretty smart when it comes to building your options, for example if you
141
180
  want your option to have a flag attribute, but no `--option` attribute, you
142
181
  can do this:
143
182
 
144
- on :n, "Your name"
183
+ on :n, "Your name"
145
184
 
146
185
  and Slop will detect a description in place of an option, so you don't have to
147
186
  do this:
148
187
 
149
- on :n, nil, "Your name", true
188
+ on :n, nil, "Your name", true
150
189
 
151
190
  You can also try other variations:
152
191
 
153
- on :name, "Your name"
154
- on :n, :name
155
- on :name, true
192
+ on :name, "Your name"
193
+ on :n, :name
194
+ on :name, true
156
195
 
157
196
  Lists
158
197
  -----
@@ -169,12 +208,51 @@ You can of course also parse lists into options. Here's how:
169
208
  You can also change both the split delimiter and limit
170
209
 
171
210
  opts = Slop.parse do
172
- opt :people, true, :as => Array, :delimiter => ':', :limit => 2)
211
+ opt :people, true, :as => Array, :delimiter => ':', :limit => 2)
173
212
  end
174
213
 
175
214
  # ARGV is `--people lee:injekt:bob`
176
215
  opts[:people] #=> ["lee", "injekt:bob"]
177
216
 
217
+ Strict Mode
218
+ -----------
219
+
220
+ Passing `strict => true` to `Slop.parse` causes it to raise a `Slop::InvalidOptionError`
221
+ when an invalid option is found (`false` by default):
222
+
223
+ Slop.new(:strict => true).parse(%w/--foo/)
224
+ # => Slop::InvalidOptionError: Unknown option -- 'foo'
225
+
226
+ and it handles multiple invalid options with a sprinkling of pluralization:
227
+
228
+ Slop.new(:strict => true).parse(%w/--foo --bar -z/)
229
+ # => Slop::InvalidOptionError: Unknown options -- 'foo', 'bar', 'z'
230
+
231
+ Significantly, however, Slop will still parse the valid options:
232
+
233
+ begin
234
+ slop = Slop.new(:strict => true, :help => true) do
235
+ banner "Usage:\n\t./awesome_sauce [options]\n\nOptions:"
236
+ on :n, :name, 'Your name'
237
+ end
238
+ slop.parse(%w/--foo --bar -z/)
239
+ rescue Slop::InvalidOptionError => e
240
+ puts "\n#{e.message}\n\n"
241
+ puts slop
242
+ exit
243
+ end
244
+
245
+ yields:
246
+
247
+ Unknown options -- 'foo', 'bar', 'z'
248
+
249
+ Usage:
250
+ ./awesome_sauce [options]
251
+
252
+ Options:
253
+ -n, --name Your name
254
+ -h, --help Print this help message
255
+
178
256
  Woah woah, why you hating on OptionParser?
179
257
  ------------------------------------------
180
258
 
@@ -211,11 +289,4 @@ thing in Slop:
211
289
  on :a, :age, 'Your age', true
212
290
  end
213
291
 
214
- things = opts.to_hash
215
-
216
- Contributing
217
- ------------
218
-
219
- If you'd like to contribute to Slop (it's **really** appreciated) please fork
220
- the GitHub repository, create your feature/bugfix branch, add tests, and send
221
- me a pull request. I'd be more than happy to look at it.
292
+ things = opts.to_hash
data/lib/slop.rb CHANGED
@@ -4,9 +4,9 @@ require 'slop/version'
4
4
  class Slop
5
5
  include Enumerable
6
6
 
7
- class MissingArgumentError < ArgumentError; end
8
- class InvalidArgumentError < ArgumentError; end
9
- class InvalidOptionError < ArgumentError; end
7
+ class MissingArgumentError < RuntimeError; end
8
+ class InvalidArgumentError < RuntimeError; end
9
+ class InvalidOptionError < RuntimeError; end
10
10
 
11
11
  # Parses the items from a CLI format into a friendly object.
12
12
  #
@@ -35,7 +35,9 @@ class Slop
35
35
  initialize_and_parse(items, true, options, &block)
36
36
  end
37
37
 
38
+ # @return [Options]
38
39
  attr_reader :options
40
+
39
41
  attr_writer :banner
40
42
  attr_accessor :longest_flag
41
43
 
@@ -48,6 +50,7 @@ class Slop
48
50
  @banner = nil
49
51
  @longest_flag = 0
50
52
  @strict = options[:strict]
53
+ @invalid_options = []
51
54
 
52
55
  if block_given?
53
56
  block.arity == 1 ? yield(self) : instance_eval(&block)
@@ -210,6 +213,11 @@ private
210
213
  if !option && item =~ /^-[^-]/
211
214
  flag, argument = flag.split('', 2)
212
215
  option = @options[flag]
216
+ elsif !option && item =~ /--no-(.+)$/
217
+ if option = @options[$1]
218
+ option.force_argument_value false
219
+ next
220
+ end
213
221
  end
214
222
 
215
223
  if option
@@ -238,6 +246,7 @@ private
238
246
  end
239
247
 
240
248
  items.delete_if { |item| trash.include? item } if delete
249
+ raise_if_invalid_options
241
250
  items
242
251
  end
243
252
 
@@ -258,9 +267,7 @@ private
258
267
  end
259
268
 
260
269
  def check_invalid_option(item, flag)
261
- if item[/^--?/] && @strict
262
- raise InvalidOptionError, "Unknown option -- '#{flag}'"
263
- end
270
+ @invalid_options << flag if item[/^--?/] && @strict
264
271
  end
265
272
 
266
273
  def clean_options(args)
@@ -288,4 +295,12 @@ private
288
295
  options
289
296
  end
290
297
 
298
+ def raise_if_invalid_options
299
+ return if !@strict || @invalid_options.empty?
300
+ message = "Unknown option"
301
+ message << 's' if @invalid_options.size > 1
302
+ message << ' -- ' << @invalid_options.map { |o| "'#{o}'" }.join(', ')
303
+ raise InvalidOptionError, message
304
+ end
305
+
291
306
  end
data/lib/slop/option.rb CHANGED
@@ -80,6 +80,10 @@ class Slop
80
80
  @expects_argument = true if options[:optional] == false
81
81
  @tail = options[:tail]
82
82
  @match = options[:match]
83
+ @forced = false
84
+
85
+ @delimiter = options[:delimiter] || ','
86
+ @limit = options[:limit] || 0
83
87
 
84
88
  if @long_flag && @long_flag.size > @slop.longest_flag
85
89
  @slop.longest_flag = @long_flag.size
@@ -113,21 +117,30 @@ class Slop
113
117
  # @return [Object] the argument value after it's been case
114
118
  # according to the `:as` option
115
119
  def argument_value
120
+ return @argument_value if @forced
116
121
  value = @argument_value || default
117
- return if value.nil?
118
-
119
- case @options[:as].to_s
120
- when 'Array'
121
- value.split(@options[:delimiter] || ',', @options[:limit] || 0)
122
- when 'String'; value.to_s
123
- when 'Symbol'; value.to_s.to_sym
124
- when 'Integer'; value.to_s.to_i
125
- when 'Float'; value.to_s.to_f
122
+
123
+ case @options[:as].to_s.downcase
124
+ when 'array'
125
+ value.split @delimiter, @limit
126
+ when 'string'; value.to_s
127
+ when 'symbol'; value.to_s.to_sym
128
+ when 'integer'; value.to_s.to_i
129
+ when 'float'; value.to_s.to_f
126
130
  else
127
131
  value
128
132
  end
129
133
  end
130
134
 
135
+ # Force an argument value, used when the desired argument value
136
+ # is negative (false or nil)
137
+ #
138
+ # @param [Object] value
139
+ def force_argument_value(value)
140
+ @argument_value = value
141
+ @forced = true
142
+ end
143
+
131
144
  def to_s
132
145
  out = " "
133
146
  out += @short_flag ? "-#{@short_flag}, " : ' ' * 4
data/lib/slop/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class Slop
2
- VERSION = '1.2.0'
2
+ VERSION = '1.2.1'
3
3
  end
data/test/option_test.rb CHANGED
@@ -62,6 +62,7 @@ class OptionTest < TestCase
62
62
 
63
63
  test 'casting' do
64
64
  assert_equal :foo, option_value(%w/--name foo/, :name, true, :as => Symbol)
65
+ assert_equal :foo, option_value(%w/--name foo/, :name, true, :as => :symbol)
65
66
  assert_equal 30, option_value(%w/--age 30/, :age, true, :as => Integer)
66
67
  assert_equal "1.0", option_value(%w/--id 1/, :id, true, :as => Float).to_s
67
68
  end
data/test/slop_test.rb CHANGED
@@ -216,6 +216,14 @@ class SlopTest < TestCase
216
216
  assert totallynotstrict.parse %w/--foo/
217
217
  end
218
218
 
219
+ test 'strict mode parses options before raising Slop::InvalidOptionError' do
220
+ strict = Slop.new :strict => true
221
+ strict.opt :n, :name, true
222
+
223
+ assert_raises(Slop::InvalidOptionError, /--foo/) { strict.parse %w/--foo --name nelson/ }
224
+ assert_equal 'nelson', strict[:name]
225
+ end
226
+
219
227
  test 'short option flag with no space between flag and argument' do
220
228
  slop = Slop.new
221
229
  slop.opt :p, :password, true
@@ -225,4 +233,16 @@ class SlopTest < TestCase
225
233
  assert_equal 'foo', slop[:password]
226
234
  assert_equal 'bar', slop[:shortpass]
227
235
  end
236
+
237
+ test 'prefixing --no- onto options for a negative result' do
238
+ slop = Slop.new
239
+ slop.opt :d, :debug
240
+ slop.opt :v, :verbose, :default => true
241
+ slop.parse %w/--no-debug --no-verbose --no-nothing/
242
+
243
+ refute slop.verbose?
244
+ refute slop.debug?
245
+ refute slop[:verbose]
246
+ refute slop[:debug]
247
+ end
228
248
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: slop
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 1.2.0
5
+ version: 1.2.1
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-21 00:00:00 +00:00
13
+ date: 2011-03-24 00:00:00 +00:00
14
14
  default_executable:
15
15
  dependencies: []
16
16