slop 3.0.4 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -4,3 +4,4 @@ doc
4
4
  *.swp
5
5
  *.gem
6
6
  *.rbc
7
+ Gemfile.lock
@@ -0,0 +1,12 @@
1
+ rvm:
2
+ - 1.8.7
3
+ - 1.9.2
4
+ - 1.9.3
5
+ - ruby-head
6
+ - jruby-18mode
7
+ - jruby-19mode
8
+ - rbx-18mode
9
+ notifications:
10
+ email:
11
+ on_success: change
12
+ on_failure: always
data/CHANGES.md CHANGED
@@ -1,3 +1,12 @@
1
+ 3.1.0
2
+ -----
3
+
4
+ * Allow options to be fetched via underscores instead of dashes
5
+ (as a fallback) (Eric Anderson, #51)
6
+ * Added `Slop#strict?` method.
7
+ * Added strict checks for Integer/Float type casting. (Amon Sha)
8
+ * Ensure separators are not replacing existing separators (#61)
9
+
1
10
  3.0.4 (2012-01-31)
2
11
  ------------------
3
12
 
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/README.md CHANGED
@@ -5,6 +5,8 @@ Slop is a simple option parser with an easy to remember syntax and friendly API.
5
5
 
6
6
  This README is targeted at Slop v3.
7
7
 
8
+ [![Build Status](https://secure.travis-ci.org/injekt/slop.png)](http://travis-ci.org/injekt/slop)
9
+
8
10
  Installation
9
11
  ------------
10
12
 
@@ -27,7 +29,7 @@ opts = Slop.parse do
27
29
  banner "ruby foo.rb [options]\n"
28
30
  on :name=, 'Your name'
29
31
  on :p, :password, 'Your password', :argument => :optional
30
- on :v :verbose, 'Enable verbose mode'
32
+ on :v, :verbose, 'Enable verbose mode'
31
33
  end
32
34
 
33
35
  # if ARGV is `--name Lee -v`
@@ -130,4 +132,4 @@ opts = Slop.parse do
130
132
  end
131
133
 
132
134
  opts.to_hash #=> { :name => 'lee', :age => 105 }
133
- ```
135
+ ```
@@ -4,7 +4,7 @@ require 'slop/commands'
4
4
  class Slop
5
5
  include Enumerable
6
6
 
7
- VERSION = '3.0.4'
7
+ VERSION = '3.1.0'
8
8
 
9
9
  # The main Error class, all Exception classes inherit from this class.
10
10
  class Error < StandardError; end
@@ -89,7 +89,7 @@ class Slop
89
89
  # Returns a new instance of Slop.
90
90
  def optspec(string, config = {})
91
91
  config[:banner], optspec = string.split(/^--+$/, 2) if string[/^--+$/]
92
- lines = string.split("\n").reject(&:empty?)
92
+ lines = optspec.split("\n").reject(&:empty?)
93
93
  opts = Slop.new(config)
94
94
 
95
95
  lines.each do |line|
@@ -97,7 +97,7 @@ class Slop
97
97
  short, long = opt.split(',').map { |s| s.sub(/\A--?/, '') }
98
98
  opt = opts.on(short, long, description)
99
99
 
100
- if long && long[-1] == ?$
100
+ if long && long.end_with?('=')
101
101
  long.sub!(/\=$/, '')
102
102
  opt.config[:argument] = true
103
103
  end
@@ -154,6 +154,13 @@ class Slop
154
154
  end
155
155
  end
156
156
 
157
+ # Is strict mode enabled?
158
+ #
159
+ # Returns true if strict mode is enabled, false otherwise.
160
+ def strict?
161
+ config[:strict]
162
+ end
163
+
157
164
  # Set the banner.
158
165
  #
159
166
  # banner - The String to set the banner.
@@ -260,7 +267,7 @@ class Slop
260
267
  # with a ? character it will instead call super().
261
268
  def method_missing(method, *args, &block)
262
269
  meth = method.to_s
263
- if meth[-1] == ??
270
+ if meth.end_with?('?')
264
271
  present?(meth.chop)
265
272
  else
266
273
  super
@@ -272,7 +279,7 @@ class Slop
272
279
  # Returns true if this option key exists in our list of options.
273
280
  def respond_to?(method)
274
281
  method = method.to_s
275
- if method[-1] == ?? && options.any? { |o| o.key == method.chop }
282
+ if method.end_with?('?') && options.any? { |o| o.key == method.chop }
276
283
  true
277
284
  else
278
285
  super
@@ -325,7 +332,11 @@ class Slop
325
332
  #
326
333
  # text - The String text to print.
327
334
  def separator(text)
328
- @separators[options.size] = text
335
+ if @separators[options.size]
336
+ @separators[options.size] << "\n#{text}"
337
+ else
338
+ @separators[options.size] = text
339
+ end
329
340
  end
330
341
 
331
342
  # Print a handy Slop help string.
@@ -363,17 +374,17 @@ class Slop
363
374
  return items
364
375
  end
365
376
 
366
- items.each_with_index { |item, index|
377
+ items.each_with_index do |item, index|
367
378
  @trash << index && break if item == '--'
368
379
  autocreate(items, index) if config[:autocreate]
369
380
  process_item(items, index, &block) unless @trash.include?(index)
370
- }
371
- items.reject!.with_index { |item, index| delete && @trash.include?(index) }
381
+ end
382
+ items.reject!.with_index { |item, index| @trash.include?(index) } if delete
372
383
 
373
- required_options = options.select { |opt| opt.required? && opt.count < 1 }
374
- if required_options.any?
384
+ missing_options = options.select { |opt| opt.required? && opt.count < 1 }
385
+ if missing_options.any?
375
386
  raise MissingOptionError,
376
- "Missing required option(s): #{required_options.map(&:key).join(', ')}"
387
+ "Missing required option(s): #{missing_options.map(&:key).join(', ')}"
377
388
  end
378
389
 
379
390
  if @unknown_options.any?
@@ -397,10 +408,10 @@ class Slop
397
408
  # Returns nothing.
398
409
  def process_item(items, index, &block)
399
410
  item = items[index]
400
- option, argument = extract_option(item) if item[0, 1] == '-'
411
+ option, argument = extract_option(item) if item.start_with?('-')
401
412
 
402
413
  if option
403
- option.count += 1 unless item[0, 5] == '--no-'
414
+ option.count += 1 unless item.start_with?('--no-')
404
415
  @trash << index
405
416
  @triggered_options << option
406
417
 
@@ -426,7 +437,7 @@ class Slop
426
437
  option.call(nil)
427
438
  end
428
439
  else
429
- @unknown_options << item if config[:strict] && item =~ /\A--?/
440
+ @unknown_options << item if strict? && item =~ /\A--?/
430
441
  block.call(item) if block && !@trash.include?(index)
431
442
  end
432
443
  end
@@ -441,7 +452,7 @@ class Slop
441
452
  # Returns nothing.
442
453
  def execute_option(option, argument, index, item = nil)
443
454
  if !option
444
- if config[:multiple_switches] && config[:strict]
455
+ if config[:multiple_switches] && strict?
445
456
  raise InvalidOptionError, "Unknown option -#{item}"
446
457
  end
447
458
  return
@@ -482,6 +493,7 @@ class Slop
482
493
  def extract_option(flag)
483
494
  option = fetch_option(flag)
484
495
  option ||= fetch_option(flag.downcase) if config[:ignore_case]
496
+ option ||= fetch_option(flag.gsub(/([^-])-/, '\1_'))
485
497
 
486
498
  unless option
487
499
  case flag
@@ -506,7 +518,7 @@ class Slop
506
518
  argument = items[index + 1]
507
519
  option.config[:argument] = (argument && argument !~ /\A--?/)
508
520
  option.config[:autocreated] = true
509
- @options << option
521
+ options << option
510
522
  end
511
523
  end
512
524
 
@@ -538,7 +550,7 @@ class Slop
538
550
  def extract_short_flag(objects, config)
539
551
  flag = clean(objects.first)
540
552
 
541
- if flag.size == 2 && flag[-1, 1] == '='
553
+ if flag.size == 2 && flag.end_with?('=')
542
554
  config[:argument] ||= true
543
555
  flag.chop!
544
556
  end
@@ -556,8 +568,8 @@ class Slop
556
568
  def extract_long_flag(objects, config)
557
569
  flag = objects.first.to_s
558
570
  if flag =~ /\A(?:--?)?[a-zA-Z][a-zA-Z0-9_-]+\=?\??\z/
559
- config[:argument] ||= true if flag[-1, 1] == '='
560
- config[:optional_argument] = true if flag[-2, 2] == '=?'
571
+ config[:argument] ||= true if flag.end_with?('=')
572
+ config[:optional_argument] = true if flag.end_with?('=?')
561
573
  objects.shift
562
574
  clean(flag).sub(/\=\??\z/, '')
563
575
  end
@@ -12,6 +12,27 @@ class Slop
12
12
  #
13
13
  # config - An optional configuration Hash.
14
14
  # block - Optional block used to define commands.
15
+ #
16
+ # Examples:
17
+ #
18
+ # commands = Slop::Commands.new do
19
+ # on :new do
20
+ # on '-o', '--outdir=', 'The output directory'
21
+ # on '-v', '--verbose', 'Enable verbose mode'
22
+ # end
23
+ #
24
+ # on :generate do
25
+ # on '--assets', 'Generate assets', :default => true
26
+ # end
27
+ #
28
+ # global do
29
+ # on '-D', '--debug', 'Enable debug mode', :default => false
30
+ # end
31
+ # end
32
+ #
33
+ # commands[:new].class #=> Slop
34
+ # commands.parse
35
+ #
15
36
  def initialize(config = {}, &block)
16
37
  @config = config
17
38
  @commands = {}
@@ -39,13 +39,12 @@ class Slop
39
39
  @config = DEFAULT_OPTIONS.merge(config)
40
40
  @count = 0
41
41
  @callback = block_given? ? block : config[:callback]
42
- @value = nil
43
42
 
44
43
  @types = {
45
44
  :string => proc { |v| v.to_s },
46
45
  :symbol => proc { |v| v.to_sym },
47
- :integer => proc { |v| v.to_s.to_i },
48
- :float => proc { |v| v.to_f },
46
+ :integer => proc { |v| value_to_integer(v) },
47
+ :float => proc { |v| value_to_float(v) },
49
48
  :array => proc { |v| v.split(@config[:delimiter], @config[:limit]) },
50
49
  :range => proc { |v| value_to_range(v) }
51
50
  }
@@ -129,6 +128,40 @@ class Slop
129
128
 
130
129
  private
131
130
 
131
+ # Convert an object to an Integer if possible.
132
+ #
133
+ # value - The Object we want to convert to an integer.
134
+ #
135
+ # Returns the Integer value if possible to convert, else a zero.
136
+ def value_to_integer(value)
137
+ if @slop.strict?
138
+ begin
139
+ Integer(value.to_s, 10)
140
+ rescue ArgumentError
141
+ raise InvalidArgumentError, "#{value} could not be coerced into Integer"
142
+ end
143
+ else
144
+ value.to_s.to_i
145
+ end
146
+ end
147
+
148
+ # Convert an object to a Float if possible.
149
+ #
150
+ # value - The Object we want to convert to a float.
151
+ #
152
+ # Returns the Float value if possible to convert, else a zero.
153
+ def value_to_float(value)
154
+ if @slop.strict?
155
+ begin
156
+ Float(value.to_s)
157
+ rescue ArgumentError
158
+ raise InvalidArgumentError, "#{value} could not be coerced into Float"
159
+ end
160
+ else
161
+ value.to_s.to_f
162
+ end
163
+ end
164
+
132
165
  # Convert an object to a Range if possible.
133
166
  #
134
167
  # value - The Object we want to convert to a range.
@@ -141,7 +174,7 @@ class Slop
141
174
  when /\A(-?\d+?)(\.\.\.?|-|,)(-?\d+)\z/
142
175
  Range.new($1.to_i, $3.to_i, $2 == '...')
143
176
  else
144
- if @slop.config[:strict]
177
+ if @slop.strict?
145
178
  raise InvalidArgumentError, "#{value} could not be coerced into Range"
146
179
  else
147
180
  value
@@ -150,4 +183,4 @@ class Slop
150
183
  end
151
184
 
152
185
  end
153
- end
186
+ end
@@ -1,11 +1,14 @@
1
1
  Gem::Specification.new do |s|
2
- s.name = 'slop'
3
- s.version = '3.0.4'
4
- s.summary = 'Option gathering made easy'
2
+ s.name = 'slop'
3
+ s.version = '3.1.0'
4
+ s.summary = 'Option gathering made easy'
5
5
  s.description = 'A simple DSL for gathering options and parsing the command line'
6
- s.author = 'Lee Jarvis'
7
- s.email = 'lee@jarvis.co'
8
- s.homepage = 'http://github.com/injekt/slop'
9
- s.files = `git ls-files`.split("\n")
10
- s.test_files = `git ls-files -- test/*`.split("\n")
6
+ s.author = 'Lee Jarvis'
7
+ s.email = 'lee@jarvis.co'
8
+ s.homepage = 'http://github.com/injekt/slop'
9
+ s.files = `git ls-files`.split("\n")
10
+ s.test_files = `git ls-files -- test/*`.split("\n")
11
+
12
+ s.add_development_dependency 'rake'
13
+ s.add_development_dependency 'minitest'
11
14
  end
@@ -56,6 +56,14 @@ class OptionTest < TestCase
56
56
  opts.on :f=, :as => Integer
57
57
  opts.parse %w'-f 1'
58
58
  assert_equal 1, opts[:f]
59
+
60
+ opts = Slop.new(:strict => true) { on :r=, :as => Integer }
61
+ assert_raises(Slop::InvalidArgumentError) { opts.parse %w/-r abc/ }
62
+ end
63
+
64
+ test "float type cast" do
65
+ opts = Slop.new(:strict => true) { on :r=, :as => Float }
66
+ assert_raises(Slop::InvalidArgumentError) { opts.parse %w/-r abc/ }
59
67
  end
60
68
 
61
69
  test "symbol type cast" do
@@ -115,4 +123,4 @@ class OptionTest < TestCase
115
123
  slop.on :foo, :help => ' -f, --foo SOMETHING FOOEY'
116
124
  assert_equal ' -f, --foo SOMETHING FOOEY', slop.fetch_option(:foo).help
117
125
  end
118
- end
126
+ end
@@ -256,6 +256,13 @@ class SlopTest < TestCase
256
256
  assert_equal 'bar', opts[:foo]
257
257
  end
258
258
 
259
+ test "supporting dash" do
260
+ opts = Slop.new { on :foo_bar= }
261
+ opts.parse %w' --foo-bar baz '
262
+ assert_equal 'baz', opts[:foo_bar]
263
+ assert opts.foo_bar?
264
+ end
265
+
259
266
  test "parsing an optspec and building options" do
260
267
  optspec = <<-SPEC
261
268
  ruby foo.rb [options]
@@ -284,9 +291,10 @@ class SlopTest < TestCase
284
291
  opts = Slop.new do
285
292
  on :foo
286
293
  separator "hello"
294
+ separator "world"
287
295
  on :bar
288
296
  end
289
- assert_equal " --foo \nhello\n --bar ", opts.help
297
+ assert_equal " --foo \nhello\nworld\n --bar ", opts.help
290
298
  end
291
299
 
292
300
  test "printing help with :help => true" 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.0.4
4
+ version: 3.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,8 +9,30 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-01-31 00:00:00.000000000 Z
13
- dependencies: []
12
+ date: 2012-04-23 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: &70221805243820 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70221805243820
25
+ - !ruby/object:Gem::Dependency
26
+ name: minitest
27
+ requirement: &70221805243060 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70221805243060
14
36
  description: A simple DSL for gathering options and parsing the command line
15
37
  email: lee@jarvis.co
16
38
  executables: []
@@ -18,7 +40,9 @@ extensions: []
18
40
  extra_rdoc_files: []
19
41
  files:
20
42
  - .gitignore
43
+ - .travis.yml
21
44
  - CHANGES.md
45
+ - Gemfile
22
46
  - LICENSE
23
47
  - README.md
24
48
  - Rakefile
@@ -42,12 +66,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
42
66
  - - ! '>='
43
67
  - !ruby/object:Gem::Version
44
68
  version: '0'
69
+ segments:
70
+ - 0
71
+ hash: -2177478579712084864
45
72
  required_rubygems_version: !ruby/object:Gem::Requirement
46
73
  none: false
47
74
  requirements:
48
75
  - - ! '>='
49
76
  - !ruby/object:Gem::Version
50
77
  version: '0'
78
+ segments:
79
+ - 0
80
+ hash: -2177478579712084864
51
81
  requirements: []
52
82
  rubyforge_project:
53
83
  rubygems_version: 1.8.11