slop 1.9.1 → 2.0.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/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