slop 3.0.4 → 3.1.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/.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