slop 1.9.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES.md CHANGED
@@ -1,3 +1,22 @@
1
+ 2.0.0 (2011-07-07)
2
+ -----------
3
+
4
+ * Deprecations:
5
+ * Removed `Slop::Options#to_hash` continue using `Slop#to_hash` directly.
6
+ This method also now returns symbols by default instead of strings. If
7
+ you want strings use `opts.to_hash(false)`
8
+ * `:multiple_switches` is now enabled by default, to parse `fbar` as the
9
+ option `f` with value `bar` you must disable `:multiple_switches`
10
+ * Removed `Slop::Options#to_help` and merged its contents into `Slop#help`
11
+ * Removed `lib/slop/options.rb` and merged `Slop::Options` into slop.rb
12
+ * Removed `lib/slop/option.rb` and merged `Slop::Option` into slop.rb
13
+ * These changes make Slop much easier to vendor in libraries
14
+ * `Slop::Option` now inherits from `Struct.new`
15
+ * Added Slop::Error subclassing from StandardError which all exception
16
+ classes should inherit from
17
+ * Added Slop::MissingOptionError and `:required` option to Slop::Option.
18
+ This exception is raised when a mandatory option is not used
19
+
1
20
  1.9.1 (2011-06-16)
2
21
  ------------------
3
22
 
@@ -84,4 +103,4 @@
84
103
  * Add `Slop#present?` as alias for `Slop#<option>?`
85
104
  * Add `Option#count` for monitoring how many times an option is called
86
105
  * Add `:io` for using a custom IO object when using the `:help` option
87
- * Numerous performance tweaks
106
+ * Numerous performance tweaks
data/README.md CHANGED
@@ -39,7 +39,7 @@ wiki page.
39
39
 
40
40
  You can also return your options as a Hash
41
41
 
42
- opts.to_hash #=> {'name' => 'Lee Jarvis', 'verbose' => true, 'age' => nil, 'sex' => 'male'}
42
+ opts.to_hash #=> {:name => 'Lee Jarvis', :verbose => true, :age => nil, :sex => 'male'}
43
43
 
44
44
  If you want some pretty output for the user to see your options, you can just
45
45
  send the Slop object to `puts` or use the `help` method.
@@ -83,7 +83,7 @@ Parsing
83
83
 
84
84
  Slop's pretty good at parsing, let's take a look at what it'll extract for you
85
85
 
86
- Slop.parse do
86
+ Slop.parse(:multiple_switches => false) do
87
87
  on 's', 'server', true
88
88
  on 'p', 'port', true, :as => :integer
89
89
  on 'username', true, :matches => /[^a-zA-Z]+$/
@@ -97,10 +97,10 @@ Now throw some options at it:
97
97
  Here's what we'll get back
98
98
 
99
99
  {
100
- :server=>"ftp://foobar.com",
101
- :port=>1234,
102
- :username=>"FooBar",
103
- :password=>"hello there"
100
+ :server => "ftp://foobar.com",
101
+ :port => 1234,
102
+ :username => "FooBar",
103
+ :password => "hello there"
104
104
  }
105
105
 
106
106
  Events
@@ -160,22 +160,29 @@ Short Switches
160
160
  --------------
161
161
 
162
162
  Want to enable multiple switches at once like rsync does? By default Slop will
163
- parse `-abcd` as the option `a` with the argument `bcd`, this can be disabled
164
- by passing the `:multiple_switches` option to a new Slop object.
163
+ parse `-abc` as the options `a` `b` and `c` and set their values to true. If
164
+ you would like to disable this, you can pass `multiple_switches => false` to
165
+ a new Slop object. In which case Slop will then parse `-fbar` as the option
166
+ `f` with the argument value `bar`.
165
167
 
166
- opts = Slop.new(:strict, :multiple_switches) do
168
+ Slop.parse do
167
169
  on :a, 'First switch'
168
170
  on :b, 'Second switch'
169
171
  on :c, 'Third switch'
170
172
  end
171
173
 
172
- opts.parse
173
-
174
174
  # Using `-ac`
175
175
  opts[:a] #=> true
176
176
  opts[:b] #=> false
177
177
  opts[:c] #=> true
178
178
 
179
+ Slop.parse(:multiple_switches => false) do
180
+ on :a, 'Some switch', true
181
+ end
182
+
183
+ # Using `ahello`
184
+ opts[:a] #=> 'hello'
185
+
179
186
  Lists
180
187
  -----
181
188
 
@@ -245,4 +252,4 @@ thing in Slop:
245
252
  on :a, :age, 'Your age', true, :as => :int
246
253
  end
247
254
 
248
- opts.to_hash(true) #=> { :name => 'lee', :age => 105 }
255
+ opts.to_hash #=> { :name => 'lee', :age => 105 }
data/Rakefile CHANGED
@@ -3,8 +3,4 @@ task :test do
3
3
  Dir.glob("test/*_test.rb").each { |test| require "./#{test}" }
4
4
  end
5
5
 
6
- task :test_all do
7
- sh "rvm 1.8.7,jruby,rbx,1.9.2 exec rake test"
8
- end
9
-
10
- task :default => :test
6
+ task :default => :test
data/lib/slop.rb CHANGED
@@ -1,22 +1,240 @@
1
- require 'slop/options'
2
- require 'slop/option'
3
-
4
1
  class Slop
5
2
  include Enumerable
6
3
 
4
+ # Slops standard Error class. All exception classes should
5
+ # inherit from this class
6
+ class Error < StandardError; end
7
+
7
8
  # Raised when an option expects an argument and none is given
8
- class MissingArgumentError < RuntimeError; end
9
+ class MissingArgumentError < Error; end
10
+
11
+ # Raised when an option is required but not given
12
+ class MissingOptionError < Error; end
9
13
 
10
14
  # Raised when an option specifies the `:match` attribute and this
11
15
  # options argument does not match this regexp
12
- class InvalidArgumentError < RuntimeError; end
16
+ class InvalidArgumentError < Error; end
13
17
 
14
18
  # Raised when the `:strict` option is enabled and an unknown
15
19
  # or unspecified option is used
16
- class InvalidOptionError < RuntimeError; end
20
+ class InvalidOptionError < Error; end
21
+
22
+ # Each option specified in `Slop#opt` creates an instance of this class
23
+ class Option < Struct.new(:short_flag, :long_flag, :description,
24
+ :tail, :match, :help, :required, :forced, :count)
25
+
26
+ # @param [Slop] slop
27
+ # @param [String, #to_s] short
28
+ # @param [String, #to_s] long
29
+ # @param [String] description
30
+ # @param [Boolean] argument
31
+ # @param [Hash] options
32
+ # @option options [Boolean] :optional
33
+ # @option options [Boolean] :argument
34
+ # @option options [Object] :default
35
+ # @option options [Proc, #call] :callback
36
+ # @option options [String, #to_s] :delimiter (',')
37
+ # @option options [Integer] :limit (0)
38
+ # @option options [Boolean] :tail (false)
39
+ # @option options [Regexp] :match
40
+ # @option options [String, #to_s] :unless
41
+ # @option options [Boolean, String] :help (true)
42
+ # @option options [Boolean] :required (false)
43
+ def initialize(slop, short, long, description, argument, options, &blk)
44
+ @slop = slop
45
+
46
+ self.short_flag = short
47
+ self.long_flag = long
48
+ self.description = description
49
+
50
+ @argument = argument
51
+ @options = options
52
+
53
+ self.tail = @options[:tail]
54
+ self.match = @options[:match]
55
+ self.help = @options.fetch(:help, true)
56
+ self.required = @options[:required]
57
+
58
+ @delimiter = @options.fetch(:delimiter, ',')
59
+ @limit = @options.fetch(:limit, 0)
60
+ @argument_type = @options[:as].to_s.downcase
61
+ @argument_value = nil
62
+
63
+ self.forced = false
64
+ self.count = 0
65
+
66
+ @callback = blk if block_given?
67
+ @callback ||= @options[:callback]
68
+
69
+ build_longest_flag
70
+ end
71
+
72
+ # @return [Boolean] true if this option expects an argument
73
+ def expects_argument?
74
+ @argument || @options[:argument] || @options[:optional] == false
75
+ end
76
+
77
+ # @return [Boolean] true if this option accepts an optional argument
78
+ def accepts_optional_argument?
79
+ @options[:optional]
80
+ end
81
+
82
+ # @return [String] either the long or short flag for this option
83
+ def key
84
+ long_flag || short_flag
85
+ end
86
+
87
+ # Set this options argument value.
88
+ #
89
+ # If this options argument type is expected to be an Array, this
90
+ # method will split the value and concat elements into the original
91
+ # argument value
92
+ #
93
+ # @param [Object] value The value to set this options argument to
94
+ def argument_value=(value)
95
+ if @argument_type == 'array'
96
+ @argument_value ||= []
97
+
98
+ if value.respond_to?(:to_str)
99
+ @argument_value.concat value.split(@delimiter, @limit)
100
+ end
101
+ else
102
+ @argument_value = value
103
+ end
104
+ end
105
+
106
+ # @return [Object] the argument value after it's been cast
107
+ # according to the `:as` option
108
+ def argument_value
109
+ return @argument_value if forced
110
+ value = @argument_value || @options[:default]
111
+ return if value.nil?
112
+
113
+ case @argument_type
114
+ when 'array'; @argument_value
115
+ when 'range'; value_to_range value
116
+ when 'float'; value.to_s.to_f
117
+ when 'string', 'str'; value.to_s
118
+ when 'symbol', 'sym'; value.to_s.to_sym
119
+ when 'integer', 'int'; value.to_s.to_i
120
+ else
121
+ value
122
+ end
123
+ end
124
+
125
+ # Force an argument value, used when the desired argument value
126
+ # is negative (false or nil)
127
+ #
128
+ # @param [Object] value
129
+ def force_argument_value(value)
130
+ @argument_value = value
131
+ self.forced = true
132
+ end
133
+
134
+ # Execute the block or callback object associated with this Option
135
+ #
136
+ # @param [Object] The object to be sent to `:call`
137
+ def call(obj=nil)
138
+ @callback.call(obj) if @callback.respond_to?(:call)
139
+ end
140
+
141
+ # @param [Array] items The original array of objects passed to `Slop.new`
142
+ # @return [Boolean] true if this options `:unless` argument exists
143
+ # inside *items*
144
+ def omit_exec?(items)
145
+ string = @options[:unless].to_s.sub(/\A--?/, '')
146
+ items.any? { |i| i.to_s.sub(/\A--?/, '') == string }
147
+ end
148
+
149
+ # This option in a nice pretty string, including a short flag, long
150
+ # flag, and description (if they exist).
151
+ #
152
+ # @see Slop#help
153
+ # @return [String]
154
+ def to_s
155
+ out = " "
156
+ out += short_flag ? "-#{short_flag}, " : ' ' * 4
157
+
158
+ if long_flag
159
+ out += "--#{long_flag}"
160
+ if help.respond_to? :to_str
161
+ out += " #{help}"
162
+ size = long_flag.size + help.size + 1
163
+ else
164
+ size = long_flag.size
165
+ end
166
+ diff = @slop.longest_flag - size
167
+ out += " " * (diff + 6)
168
+ else
169
+ out += " " * (@slop.longest_flag + 8)
170
+ end
171
+
172
+ "#{out}#{description}"
173
+ end
174
+
175
+ # @return [String]
176
+ def inspect
177
+ "#<Slop::Option short_flag=#{short_flag.inspect} " +
178
+ "long_flag=#{long_flag.inspect} argument=#{@argument.inspect} " +
179
+ "description=#{description.inspect}>"
180
+ end
181
+
182
+ private
183
+
184
+ def value_to_range(value)
185
+ case value.to_s
186
+ when /\A(-?\d+?)(?:\.\.|-|,)(-?\d+)\z/
187
+ $1.to_i .. $2.to_i
188
+ when /\A(-?\d+?)\.\.\.(-?\d+)\z/
189
+ $1.to_i ... $2.to_i
190
+ when /\A-?\d+\z/
191
+ value.to_i
192
+ else
193
+ value
194
+ end
195
+ end
196
+
197
+ def build_longest_flag
198
+ if long_flag && long_flag.size > @slop.longest_flag
199
+ @slop.longest_flag = long_flag.size
200
+ @slop.longest_flag += help.size if help.respond_to? :to_str
201
+ end
202
+ end
203
+
204
+ end
205
+
206
+ # Used to hold a list of Option objects. This class inherits from Array
207
+ # and overwrites `Array#[]` so we can fetch Option objects via their
208
+ # short or long flags
209
+ class Options < Array
210
+
211
+ # Fetch an Option object. This method overrides Array#[] to provide
212
+ # a nicer interface for fetching options via their short or long flag.
213
+ # The reason we don't use a Hash here is because an option cannot be
214
+ # identified by a single label. Instead this method tests against
215
+ # a short flag first, followed by a long flag. When passing this
216
+ # method an Integer, it will work as an Array usually would, fetching
217
+ # the Slop::Option at this index.
218
+ #
219
+ # @param [Object] flag The short/long flag representing the option
220
+ # @example
221
+ # opts = Slop.parse { on :v, "Verbose mode" }
222
+ # opts.options[:v] #=> Option
223
+ # opts.options[:v].description #=> "Verbose mode"
224
+ # @return [Option] the option assoiated with this flag
225
+ def [](flag)
226
+ if flag.is_a? Integer
227
+ super
228
+ else
229
+ find do |option|
230
+ [option.short_flag, option.long_flag].include? flag.to_s
231
+ end
232
+ end
233
+ end
234
+ end
17
235
 
18
236
  # @return [String] The current version string
19
- VERSION = '1.9.1'
237
+ VERSION = '2.0.0'
20
238
 
21
239
  # Parses the items from a CLI format into a friendly object
22
240
  #
@@ -107,7 +325,7 @@ class Slop
107
325
  #
108
326
  # @option opts [Array] :aliases ([])
109
327
  # * Primary uses by commands to implement command aliases
110
-
328
+ #
111
329
  # @option opts [Boolean] :completion (true)
112
330
  # * When true, commands will be auto completed. Ie `foobar` will be
113
331
  # executed simply when `foo` `fo` or `foob` are used
@@ -126,7 +344,7 @@ class Slop
126
344
  @banner = sloptions[:banner]
127
345
  @strict = sloptions[:strict]
128
346
  @ignore_case = sloptions[:ignore_case]
129
- @multiple_switches = sloptions[:multiple_switches]
347
+ @multiple_switches = sloptions.fetch(:multiple_switches, true)
130
348
  @autocreate = sloptions[:autocreate]
131
349
  @completion = sloptions.fetch(:completion, true)
132
350
  @arguments = sloptions[:arguments]
@@ -340,13 +558,18 @@ class Slop
340
558
  # Returns the parsed list into a option/value hash
341
559
  #
342
560
  # @example
343
- # opts.to_hash #=> { 'name' => 'Emily' }
561
+ # opts.to_hash #=> { :name => 'Emily' }
344
562
  #
345
- # # symbols!
346
- # opts.to_hash(true) #=> { :name => 'Emily' }
563
+ # # strings!
564
+ # opts.to_hash(false) #=> { 'name' => 'Emily' }
347
565
  # @return [Hash]
348
- def to_hash(symbols=false)
349
- @options.to_hash symbols
566
+ def to_hash(symbols=true)
567
+ @options.reduce({}) do |hsh, option|
568
+ key = option.key
569
+ key = key.to_sym if symbols
570
+ hsh[key] = option.argument_value
571
+ hsh
572
+ end
350
573
  end
351
574
  alias :to_h :to_hash
352
575
 
@@ -398,8 +621,16 @@ class Slop
398
621
  parts << banner if banner
399
622
  parts << summary if summary
400
623
  parts << wrap_and_indent(description, 80, 4) if description
401
- parts << "options:" if options.size > 0
402
- parts << options.to_help if options.size > 0
624
+
625
+ if options.size > 0
626
+ parts << "options:"
627
+
628
+ heads = @options.reject(&:tail)
629
+ tails = @options.select(&:tail)
630
+ all = (heads + tails).select(&:help)
631
+
632
+ parts << all.map(&:to_s).join("\n")
633
+ end
403
634
 
404
635
  parts.join("\n\n")
405
636
  end
@@ -463,8 +694,9 @@ class Slop
463
694
  next if ignore_all
464
695
  autocreate(flag, index, items) if @autocreate
465
696
  option, argument = extract_option(item, flag)
466
- if @multiple_switches && !option
467
- trash << index if item[/\A-[^-]/]
697
+
698
+ if @multiple_switches && item[/\A-[^-]/] && !option
699
+ trash << index
468
700
  next
469
701
  end
470
702
 
@@ -504,6 +736,7 @@ class Slop
504
736
 
505
737
  items.reject!.with_index { |o, i| trash.include?(i) } if delete
506
738
  raise_if_invalid_options!
739
+ raise_if_missing_required_options!(items)
507
740
  items
508
741
  end
509
742
 
@@ -522,6 +755,14 @@ class Slop
522
755
  raise InvalidOptionError, message
523
756
  end
524
757
 
758
+ def raise_if_missing_required_options!(items)
759
+ @options.select(&:required).each do |o|
760
+ unless items.select {|i| i[/\A--?/] }.any? {|i| i.to_s.sub(/\A--?/, '') == o.key }
761
+ raise MissingOptionError, "Expected option `#{o.key}` is required"
762
+ end
763
+ end
764
+ end
765
+
525
766
  # if multiple_switches is enabled, this method filters through an items
526
767
  # characters and attempts to find an Option object for each flag.
527
768
  #
@@ -669,4 +910,4 @@ class Slop
669
910
  options.push @arguments ? true : (args.shift ? true : false)
670
911
  options.push extras
671
912
  end
672
- end
913
+ end
data/slop.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'slop'
3
- s.version = '1.9.1'
3
+ s.version = '2.0.0'
4
4
  s.summary = 'Option gathering made easy'
5
5
  s.description = 'A simple DSL for gathering options and parsing the command line'
6
6
  s.author = 'Lee Jarvis'
data/test/option_test.rb CHANGED
@@ -168,4 +168,13 @@ class OptionTest < TestCase
168
168
  assert_equal "1", opts[:bar]
169
169
  refute item
170
170
  end
171
+
172
+ test 'raises MissingOptionError when an option is :required' do
173
+ opts = Slop.new do
174
+ on :foo, :required => true
175
+ end
176
+
177
+ assert_raises(Slop::MissingOptionError, /foo is required/) { opts.parse %w[ --bar ] }
178
+ assert_raises(Slop::MissingOptionError, /foo is required/) { opts.parse %w[ foo ] }
179
+ end
171
180
  end
data/test/slop_test.rb CHANGED
@@ -319,7 +319,7 @@ class SlopTest < TestCase
319
319
  slop.opt :V, :verbose, :default => false
320
320
  slop.parse %w/--name lee --version/
321
321
 
322
- assert_equal({'name' => 'lee', 'version' => true, 'verbose' => false}, slop.to_hash)
322
+ assert_equal({'name' => 'lee', 'version' => true, 'verbose' => false}, slop.to_hash(false))
323
323
  assert_equal({:name => 'lee', :version => true, :verbose => false}, slop.to_hash(true))
324
324
  end
325
325
 
@@ -375,11 +375,11 @@ class SlopTest < TestCase
375
375
  assert_equal 'nelson', strict[:name]
376
376
  end
377
377
 
378
- test 'short option flag with no space between flag and argument' do
379
- slop = Slop.new
378
+ test 'short option flag with no space between flag and argument, with :multiple_switches => false' do
379
+ slop = Slop.new :multiple_switches => false
380
380
  slop.opt :p, :password, true
381
381
  slop.opt :s, :shortpass, true
382
- slop.parse %w/-p foo -sbar/
382
+ slop.parse %w/-pfoo -sbar/
383
383
 
384
384
  assert_equal 'foo', slop[:password]
385
385
  assert_equal 'bar', slop[:shortpass]
metadata CHANGED
@@ -1,33 +1,23 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: slop
3
- version: !ruby/object:Gem::Version
4
- hash: 49
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.0.0
5
5
  prerelease:
6
- segments:
7
- - 1
8
- - 9
9
- - 1
10
- version: 1.9.1
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Lee Jarvis
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2011-06-16 00:00:00 +01:00
12
+ date: 2011-07-07 00:00:00.000000000 +01:00
19
13
  default_executable:
20
14
  dependencies: []
21
-
22
15
  description: A simple DSL for gathering options and parsing the command line
23
16
  email: lee@jarvis.co
24
17
  executables: []
25
-
26
18
  extensions: []
27
-
28
19
  extra_rdoc_files: []
29
-
30
- files:
20
+ files:
31
21
  - .gemtest
32
22
  - .gitignore
33
23
  - .yardopts
@@ -36,8 +26,6 @@ files:
36
26
  - README.md
37
27
  - Rakefile
38
28
  - lib/slop.rb
39
- - lib/slop/option.rb
40
- - lib/slop/options.rb
41
29
  - slop.gemspec
42
30
  - test/commands_test.rb
43
31
  - test/helper.rb
@@ -46,38 +34,29 @@ files:
46
34
  has_rdoc: true
47
35
  homepage: http://github.com/injekt/slop
48
36
  licenses: []
49
-
50
37
  post_install_message:
51
38
  rdoc_options: []
52
-
53
- require_paths:
39
+ require_paths:
54
40
  - lib
55
- required_ruby_version: !ruby/object:Gem::Requirement
41
+ required_ruby_version: !ruby/object:Gem::Requirement
56
42
  none: false
57
- requirements:
58
- - - ">="
59
- - !ruby/object:Gem::Version
60
- hash: 3
61
- segments:
62
- - 0
63
- version: "0"
64
- required_rubygems_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
48
  none: false
66
- requirements:
67
- - - ">="
68
- - !ruby/object:Gem::Version
69
- hash: 3
70
- segments:
71
- - 0
72
- version: "0"
49
+ requirements:
50
+ - - ! '>='
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
73
53
  requirements: []
74
-
75
54
  rubyforge_project:
76
55
  rubygems_version: 1.6.2
77
56
  signing_key:
78
57
  specification_version: 3
79
58
  summary: Option gathering made easy
80
- test_files:
59
+ test_files:
81
60
  - test/commands_test.rb
82
61
  - test/helper.rb
83
62
  - test/option_test.rb
data/lib/slop/option.rb DELETED
@@ -1,205 +0,0 @@
1
- class Slop
2
- class Option
3
-
4
- # @return [String, #to_s] The short flag used for this option
5
- attr_reader :short_flag
6
-
7
- # @return [String, #to_s] The long flag used for this option
8
- attr_reader :long_flag
9
-
10
- # @return [String] This options description
11
- attr_reader :description
12
-
13
- # @return [Boolean] True if the option should be grouped at the
14
- # tail of the help list
15
- attr_reader :tail
16
-
17
- # @return [Regexp] If provided, an options argument **must** match this
18
- # regexp, otherwise Slop will raise an InvalidArgumentError
19
- attr_reader :match
20
-
21
- # @return [Object] true/false, or an optional help string to append
22
- attr_reader :help
23
-
24
- # @return [Boolean] true if this options argument value has been forced
25
- attr_accessor :forced
26
-
27
- # @return [Integer] The amount of times this option has been invoked
28
- attr_accessor :count
29
-
30
- # @param [Slop] slop
31
- # @param [String, #to_s] short
32
- # @param [String, #to_s] long
33
- # @param [String] description
34
- # @param [Boolean] argument
35
- # @param [Hash] options
36
- # @option options [Boolean] :optional
37
- # @option options [Boolean] :argument
38
- # @option options [Object] :default
39
- # @option options [Proc, #call] :callback
40
- # @option options [String, #to_s] :delimiter (',')
41
- # @option options [Integer] :limit (0)
42
- # @option options [Boolean] :tail (false)
43
- # @option options [Regexp] :match
44
- # @option options [String, #to_s] :unless
45
- # @option options [Boolean, String] :help (true)
46
- def initialize(slop, short, long, description, argument, options, &blk)
47
- @slop = slop
48
- @short_flag = short
49
- @long_flag = long
50
- @description = description
51
- @argument = argument
52
- @options = options
53
-
54
- @tail = options[:tail]
55
- @match = options[:match]
56
- @delimiter = options.fetch(:delimiter, ',')
57
- @limit = options.fetch(:limit, 0)
58
- @help = options.fetch(:help, true)
59
- @argument_type = options[:as].to_s.downcase
60
-
61
- @forced = false
62
- @argument_value = nil
63
- @count = 0
64
-
65
- @callback = blk if block_given?
66
- @callback ||= options[:callback]
67
-
68
- build_longest_flag
69
- end
70
-
71
- # @return [Boolean] true if this option expects an argument
72
- def expects_argument?
73
- @argument || @options[:argument] || @options[:optional] == false
74
- end
75
-
76
- # @return [Boolean] true if this option accepts an optional argument
77
- def accepts_optional_argument?
78
- @options[:optional]
79
- end
80
-
81
- # @return [String] either the long or short flag for this option
82
- def key
83
- @long_flag || @short_flag
84
- end
85
-
86
- # Set this options argument value.
87
- #
88
- # If this options argument type is expected to be an Array, this
89
- # method will split the value and concat elements into the original
90
- # argument value
91
- #
92
- # @param [Object] value The value to set this options argument to
93
- def argument_value=(value)
94
- if @argument_type == 'array'
95
- @argument_value ||= []
96
- if value.respond_to?(:to_str)
97
- @argument_value.concat value.split(@delimiter, @limit)
98
- end
99
- else
100
- @argument_value = value
101
- end
102
- end
103
-
104
- # @return [Object] the argument value after it's been cast
105
- # according to the `:as` option
106
- def argument_value
107
- return @argument_value if @forced
108
- value = @argument_value || @options[:default]
109
- return if value.nil?
110
-
111
- case @argument_type
112
- when 'array'; @argument_value
113
- when 'range'; value_to_range value
114
- when 'float'; value.to_s.to_f
115
- when 'string', 'str'; value.to_s
116
- when 'symbol', 'sym'; value.to_s.to_sym
117
- when 'integer', 'int'; value.to_s.to_i
118
- else
119
- value
120
- end
121
- end
122
-
123
- # Force an argument value, used when the desired argument value
124
- # is negative (false or nil)
125
- #
126
- # @param [Object] value
127
- def force_argument_value(value)
128
- @argument_value = value
129
- @forced = true
130
- end
131
-
132
- # Execute the block or callback object associated with this Option
133
- #
134
- # @param [Object] The object to be sent to `:call`
135
- def call(obj=nil)
136
- @callback.call(obj) if @callback.respond_to?(:call)
137
- end
138
-
139
- # @param [Array] items The original array of objects passed to `Slop.new`
140
- # @return [Boolean] true if this options `:unless` argument exists
141
- # inside *items*
142
- def omit_exec?(items)
143
- string = @options[:unless].to_s.sub(/\A--?/, '')
144
- items.any? { |i| i.to_s.sub(/\A--?/, '') == string }
145
- end
146
-
147
- # This option in a nice pretty string, including a short flag, long
148
- # flag, and description (if they exist).
149
- #
150
- # @see Slop#help
151
- # @return [String]
152
- def to_s
153
- out = " "
154
- out += @short_flag ? "-#{@short_flag}, " : ' ' * 4
155
-
156
- if @long_flag
157
- out += "--#{@long_flag}"
158
- if @help.respond_to? :to_str
159
- out += " #{@help}"
160
- size = @long_flag.size + @help.size + 1
161
- else
162
- size = @long_flag.size
163
- end
164
- diff = @slop.longest_flag - size
165
- out += " " * (diff + 6)
166
- else
167
- out += " " * (@slop.longest_flag + 8)
168
- end
169
-
170
- "#{out}#{@description}"
171
- end
172
-
173
- # @return [String]
174
- def inspect
175
- "#<Slop::Option short_flag=#{@short_flag.inspect} " +
176
- "long_flag=#{@long_flag.inspect} argument=#{@argument.inspect} " +
177
- "description=#{@description.inspect}>"
178
- end
179
-
180
- private
181
-
182
- def value_to_range(value)
183
- case value.to_s
184
- when /\A(-?\d+?)(?:\.\.|-|,)(-?\d+)\z/
185
- $1.to_i .. $2.to_i
186
- when /\A(-?\d+?)\.\.\.(-?\d+)\z/
187
- $1.to_i ... $2.to_i
188
- when /\A-?\d+\z/
189
- value.to_i
190
- else
191
- value
192
- end
193
- end
194
-
195
- def build_longest_flag
196
- if @long_flag && @long_flag.size > @slop.longest_flag
197
- if @help.respond_to? :to_str
198
- @slop.longest_flag = @long_flag.size + @help.size
199
- else
200
- @slop.longest_flag = @long_flag.size
201
- end
202
- end
203
- end
204
- end
205
- end
data/lib/slop/options.rb DELETED
@@ -1,49 +0,0 @@
1
- class Slop
2
- class Options < Array
3
-
4
- # @param [Boolean] symbols true to cast hash keys to symbols
5
- # @see Slop#to_hash
6
- # @return [Hash]
7
- def to_hash(symbols)
8
- reduce({}) do |hsh, option|
9
- key = option.key
10
- key = key.to_sym if symbols
11
- hsh[key] = option.argument_value
12
- hsh
13
- end
14
- end
15
-
16
- # Fetch an Option object. This method overrides Array#[] to provide
17
- # a nicer interface for fetching options via their short or long flag.
18
- # The reason we don't use a Hash here is because an option cannot be
19
- # identified by a single label. Instead this method tests against
20
- # a short flag first, followed by a long flag. When passing this
21
- # method an Integer, it will work as an Array usually would, fetching
22
- # the Slop::Option at this index.
23
- #
24
- # @param [Object] flag The short/long flag representing the option
25
- # @example
26
- # opts = Slop.parse { on :v, "Verbose mode" }
27
- # opts.options[:v] #=> Option
28
- # opts.options[:v].description #=> "Verbose mode"
29
- # @return [Option] the option assoiated with this flag
30
- def [](flag)
31
- if flag.is_a? Integer
32
- super
33
- else
34
- find do |option|
35
- [option.short_flag, option.long_flag].include? flag.to_s
36
- end
37
- end
38
- end
39
-
40
- # @see Slop#help
41
- # @return [String] All options in a pretty help string
42
- def to_help
43
- heads = reject(&:tail)
44
- tails = select(&:tail)
45
- all = (heads + tails).select(&:help)
46
- all.map(&:to_s).join("\n")
47
- end
48
- end
49
- end