cri 2.11.0 → 2.12.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -71,8 +71,7 @@ module Cri
71
71
  end
72
72
 
73
73
  def message
74
- name = @definition[:long] ? '--' + @definition[:long] : '-' + @definition[:short]
75
- "invalid value #{value.inspect} for #{name} option"
74
+ "invalid value #{value.inspect} for #{@definition.formatted_name} option"
76
75
  end
77
76
  end
78
77
 
@@ -99,38 +98,26 @@ module Cri
99
98
  # @return [Hash] The already parsed options.
100
99
  attr_reader :options
101
100
 
102
- # @return [Array] The arguments that have already been parsed, including
103
- # the -- separator.
104
- attr_reader :raw_arguments
105
-
106
101
  # The options and arguments that have not yet been processed. If the
107
102
  # parser wasn’t stopped (using {#stop}), this list will be empty.
108
103
  #
109
104
  # @return [Array] The not yet parsed options and arguments.
110
105
  attr_reader :unprocessed_arguments_and_options
111
106
 
112
- # Parses the command-line arguments. See the instance `parse` method for
113
- # details.
114
- #
115
- # @param [Array<String>] arguments_and_options An array containing the
116
- # command-line arguments (will probably be `ARGS` for a root command)
117
- #
118
- # @param [Array<Hash>] definitions An array of option definitions
119
- #
120
- # @return [Cri::OptionParser] The option parser self
121
- def self.parse(arguments_and_options, definitions)
122
- new(arguments_and_options, definitions).run
123
- end
124
-
125
107
  # Creates a new parser with the given options/arguments and definitions.
126
108
  #
127
109
  # @param [Array<String>] arguments_and_options An array containing the
128
110
  # command-line arguments (will probably be `ARGS` for a root command)
129
111
  #
130
- # @param [Array<Hash>] definitions An array of option definitions
131
- def initialize(arguments_and_options, definitions)
112
+ # @param [Array<Cri::OptionDefinition>] option_defns An array of option
113
+ # definitions
114
+ #
115
+ # @param [Array<Cri::ParamDefinition>] param_defns An array of parameter
116
+ # definitions
117
+ def initialize(arguments_and_options, option_defns, param_defns)
132
118
  @unprocessed_arguments_and_options = arguments_and_options.dup
133
- @definitions = definitions
119
+ @option_defns = option_defns
120
+ @param_defns = param_defns
134
121
 
135
122
  @options = {}
136
123
  @raw_arguments = []
@@ -139,17 +126,6 @@ module Cri
139
126
  @no_more_options = false
140
127
  end
141
128
 
142
- # Returns the arguments that have already been parsed.
143
- #
144
- # If the parser was stopped before it finished, this will not contain all
145
- # options and `unprocessed_arguments_and_options` will contain what is
146
- # left to be processed.
147
- #
148
- # @return [Array] The already parsed arguments.
149
- def arguments
150
- @raw_arguments.reject { |a| a == '--' }.freeze
151
- end
152
-
153
129
  # @return [Boolean] true if the parser is running, false otherwise.
154
130
  def running?
155
131
  @running
@@ -200,10 +176,16 @@ module Cri
200
176
  @running = false
201
177
  end
202
178
 
179
+ # @return [Cri::ArgumentList] The list of arguments that have already been
180
+ # parsed, excluding the -- separator.
181
+ def arguments
182
+ ArgumentList.new(@raw_arguments, @param_defns)
183
+ end
184
+
203
185
  private
204
186
 
205
187
  def add_defaults
206
- @definitions.each { |d| add_default_option(d) }
188
+ @option_defns.each { |d| add_default_option(d) }
207
189
  end
208
190
 
209
191
  def handle_dashdash(elem)
@@ -222,20 +204,20 @@ module Cri
222
204
  end
223
205
 
224
206
  # Find definition
225
- definition = @definitions.find { |d| d[:long] == option_key }
226
- raise IllegalOptionError.new(option_key) if definition.nil?
207
+ option_defn = @option_defns.find { |d| d.long == option_key }
208
+ raise IllegalOptionError.new(option_key) if option_defn.nil?
227
209
 
228
- if %i[required optional].include?(definition[:argument])
210
+ if %i[required optional].include?(option_defn.argument)
229
211
  # Get option value if necessary
230
212
  if option_value.nil?
231
- option_value = find_option_value(definition, option_key)
213
+ option_value = find_option_value(option_defn, option_key)
232
214
  end
233
215
 
234
216
  # Store option
235
- add_option(definition, option_value)
217
+ add_option(option_defn, option_value)
236
218
  else
237
219
  # Store option
238
- add_option(definition, true)
220
+ add_option(option_defn, true)
239
221
  end
240
222
  end
241
223
 
@@ -246,28 +228,28 @@ module Cri
246
228
  # For each key
247
229
  option_keys.each do |option_key|
248
230
  # Find definition
249
- definition = @definitions.find { |d| d[:short] == option_key }
250
- raise IllegalOptionError.new(option_key) if definition.nil?
231
+ option_defn = @option_defns.find { |d| d.short == option_key }
232
+ raise IllegalOptionError.new(option_key) if option_defn.nil?
251
233
 
252
- if %i[required optional].include?(definition[:argument])
234
+ if %i[required optional].include?(option_defn.argument)
253
235
  # Get option value
254
- option_value = find_option_value(definition, option_key)
236
+ option_value = find_option_value(option_defn, option_key)
255
237
 
256
238
  # Store option
257
- add_option(definition, option_value)
239
+ add_option(option_defn, option_value)
258
240
  else
259
241
  # Store option
260
- add_option(definition, true)
242
+ add_option(option_defn, true)
261
243
  end
262
244
  end
263
245
  end
264
246
 
265
- def find_option_value(definition, option_key)
247
+ def find_option_value(option_defn, option_key)
266
248
  option_value = @unprocessed_arguments_and_options.shift
267
249
  if option_value.nil? || option_value =~ /^-/
268
- if definition[:argument] == :optional && definition[:default]
269
- option_value = definition[:default]
270
- elsif definition[:argument] == :required
250
+ if option_defn.argument == :optional && option_defn.default
251
+ option_value = option_defn.default
252
+ elsif option_defn.argument == :required
271
253
  raise OptionRequiresAnArgumentError.new(option_key)
272
254
  else
273
255
  @unprocessed_arguments_and_options.unshift(option_value)
@@ -277,12 +259,12 @@ module Cri
277
259
  option_value
278
260
  end
279
261
 
280
- def add_option(definition, value, transform: true)
281
- key = key_for(definition)
262
+ def add_option(option_defn, value, transform: true)
263
+ key = key_for(option_defn)
282
264
 
283
- value = transform ? transform_value(definition, value) : value
265
+ value = transform ? transform_value(option_defn, value) : value
284
266
 
285
- if definition[:multiple]
267
+ if option_defn.multiple
286
268
  options[key] ||= []
287
269
  options[key] << value
288
270
  else
@@ -292,32 +274,32 @@ module Cri
292
274
  delegate&.option_added(key, value, self)
293
275
  end
294
276
 
295
- def add_default_option(definition)
296
- key = key_for(definition)
277
+ def add_default_option(option_defn)
278
+ key = key_for(option_defn)
297
279
  return if options.key?(key)
298
280
 
299
- value = definition[:default]
281
+ value = option_defn.default
300
282
  return unless value
301
283
 
302
- add_option(definition, value, transform: false)
284
+ add_option(option_defn, value, transform: false)
303
285
  end
304
286
 
305
- def transform_value(definition, value)
306
- transformer = definition[:transform]
287
+ def transform_value(option_defn, value)
288
+ transformer = option_defn.transform
307
289
 
308
290
  if transformer
309
291
  begin
310
292
  transformer.call(value)
311
293
  rescue StandardError
312
- raise IllegalOptionValueError.new(definition, value)
294
+ raise IllegalOptionValueError.new(option_defn, value)
313
295
  end
314
296
  else
315
297
  value
316
298
  end
317
299
  end
318
300
 
319
- def key_for(definition)
320
- (definition[:long] || definition[:short]).to_sym
301
+ def key_for(option_defn)
302
+ (option_defn.long || option_defn.short).to_sym
321
303
  end
322
304
 
323
305
  def add_argument(value)
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cri
4
+ # The definition of a parameter.
5
+ class ParamDefinition
6
+ attr_reader :name
7
+
8
+ def initialize(name:)
9
+ @name = name
10
+ end
11
+ end
12
+ end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Cri
4
4
  # The current Cri version.
5
- VERSION = '2.11.0'
5
+ VERSION = '2.12.0'
6
6
  end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'helper'
4
+
5
+ module Cri
6
+ class ArgumentListTestCase < Cri::TestCase
7
+ def test_empty
8
+ args = Cri::ArgumentList.new([], [])
9
+
10
+ assert_equal([], args.to_a)
11
+ assert(args.empty?)
12
+ assert_equal(0, args.size)
13
+ assert_equal(nil, args[0])
14
+ assert_equal(nil, args[:abc])
15
+ end
16
+
17
+ def test_no_param_defns
18
+ args = Cri::ArgumentList.new(%w[a b c], [])
19
+
20
+ assert_equal(%w[a b c], args.to_a)
21
+ refute(args.empty?)
22
+ assert_equal(3, args.size)
23
+ assert_equal('a', args[0])
24
+ assert_equal('b', args[1])
25
+ assert_equal('c', args[2])
26
+ assert_equal(nil, args[3])
27
+ assert_equal(nil, args[:abc])
28
+ end
29
+
30
+ def test_enum
31
+ args = Cri::ArgumentList.new(%w[a b c], [])
32
+
33
+ assert_equal(%w[A B C], args.map(&:upcase))
34
+ end
35
+
36
+ def test_no_method_error
37
+ args = Cri::ArgumentList.new(%w[a b c], [])
38
+
39
+ refute args.respond_to?(:oink)
40
+ assert_raises(NoMethodError, 'x') do
41
+ args.oink
42
+ end
43
+ end
44
+
45
+ def test_dash_dash
46
+ args = Cri::ArgumentList.new(%w[a -- b -- c], [])
47
+
48
+ assert_equal(%w[a b c], args.to_a)
49
+ end
50
+
51
+ def test_one_param_defn_matched
52
+ param_defns = [Cri::ParamDefinition.new(name: 'filename')]
53
+ args = Cri::ArgumentList.new(%w[notbad.jpg], param_defns)
54
+
55
+ assert_equal(['notbad.jpg'], args.to_a)
56
+ assert_equal(1, args.size)
57
+ assert_equal('notbad.jpg', args[0])
58
+ assert_equal('notbad.jpg', args[:filename])
59
+ end
60
+
61
+ def test_one_param_defn_too_many
62
+ param_defns = [Cri::ParamDefinition.new(name: 'filename')]
63
+
64
+ exception = assert_raises(Cri::ArgumentList::ArgumentCountMismatchError) do
65
+ Cri::ArgumentList.new(%w[notbad.jpg verybad.jpg], param_defns)
66
+ end
67
+ assert_equal('incorrect number of arguments given: expected 1, but got 2', exception.message)
68
+ end
69
+
70
+ def test_one_param_defn_too_few
71
+ param_defns = [Cri::ParamDefinition.new(name: 'filename')]
72
+
73
+ exception = assert_raises(Cri::ArgumentList::ArgumentCountMismatchError) do
74
+ Cri::ArgumentList.new(%w[], param_defns)
75
+ end
76
+ assert_equal('incorrect number of arguments given: expected 1, but got 0', exception.message)
77
+ end
78
+ end
79
+ end
@@ -479,8 +479,8 @@ module Cri
479
479
 
480
480
  # Check option definitions
481
481
  assert_equal 1, cmd.option_definitions.size
482
- opt_def = cmd.option_definitions.to_a[0]
483
- assert_equal 'help', opt_def[:long]
482
+ opt_defn = cmd.option_definitions.to_a[0]
483
+ assert_equal 'help', opt_defn.long
484
484
 
485
485
  # Check subcommand
486
486
  assert_equal 1, cmd.subcommands.size
@@ -697,5 +697,22 @@ module Cri
697
697
 
698
698
  assert_equal "opts={:aaa=>\"test\"} args=--test,value\n", out
699
699
  end
700
+
701
+ def test_wrong_number_of_args
702
+ cmd = Cri::Command.define do
703
+ name 'publish'
704
+ param :filename
705
+ end
706
+
707
+ out, err = capture_io_while do
708
+ err = assert_raises SystemExit do
709
+ cmd.run([])
710
+ end
711
+ assert_equal 1, err.status
712
+ end
713
+
714
+ assert_equal [], lines(out)
715
+ assert_equal ['publish: incorrect number of arguments given: expected 1, but got 0'], lines(err)
716
+ end
700
717
  end
701
718
  end
@@ -49,7 +49,7 @@ module Cri
49
49
  { short: 'f', long: 'fff', desc: 'opt f', argument: :forbidden, multiple: false, hidden: true, block: nil, default: nil, transform: nil },
50
50
  ],
51
51
  )
52
- actual_option_definitions = Set.new(command.option_definitions)
52
+ actual_option_definitions = Set.new(command.option_definitions.map(&:to_h))
53
53
  assert_equal expected_option_definitions, actual_option_definitions
54
54
  end
55
55
 
@@ -84,7 +84,7 @@ module Cri
84
84
  { short: nil, long: 'long', desc: 'long', argument: :forbidden, multiple: false, hidden: false, block: nil, default: nil, transform: nil },
85
85
  ],
86
86
  )
87
- actual_option_definitions = Set.new(command.option_definitions)
87
+ actual_option_definitions = Set.new(command.option_definitions.map(&:to_h))
88
88
  assert_equal expected_option_definitions, actual_option_definitions
89
89
  end
90
90
 
@@ -109,7 +109,7 @@ module Cri
109
109
  { short: 'o', long: 'optional', desc: 'opt', argument: :optional, multiple: true, hidden: false, block: nil, default: nil, transform: nil },
110
110
  ],
111
111
  )
112
- actual_option_definitions = Set.new(command.option_definitions)
112
+ actual_option_definitions = Set.new(command.option_definitions.map(&:to_h))
113
113
  assert_equal expected_option_definitions, actual_option_definitions
114
114
  end
115
115
 
@@ -134,7 +134,7 @@ module Cri
134
134
  { short: 'o', long: 'optional', desc: 'opt', argument: :optional, multiple: false, hidden: true, block: nil, default: nil, transform: nil },
135
135
  ],
136
136
  )
137
- actual_option_definitions = Set.new(command.option_definitions)
137
+ actual_option_definitions = Set.new(command.option_definitions.map(&:to_h))
138
138
  assert_equal expected_option_definitions, actual_option_definitions
139
139
  end
140
140
 
@@ -240,5 +240,33 @@ module Cri
240
240
  command.run(%w[certainly])
241
241
  assert_equal 'certainly', $did_it_work
242
242
  end
243
+
244
+ def test_params
245
+ # Define
246
+ dsl = Cri::CommandDSL.new
247
+ dsl.instance_eval do
248
+ name 'moo'
249
+ usage 'dunno whatever'
250
+ summary 'does stuff'
251
+ description 'This command does a lot of stuff.'
252
+
253
+ param :foo
254
+ param :bar
255
+ param :qux
256
+
257
+ run do |_opts, args|
258
+ $args_num = { foo: args[0], bar: args[1], qux: args[2] }
259
+ $args_sym = { foo: args[:foo], bar: args[:bar], qux: args[:qux] }
260
+ end
261
+ end
262
+ command = dsl.command
263
+
264
+ # Run
265
+ $args_num = '???'
266
+ $args_sym = '???'
267
+ command.run(%w[a b c])
268
+ assert_equal({ foo: 'a', bar: 'b', qux: 'c' }, $args_num)
269
+ assert_equal({ foo: 'a', bar: 'b', qux: 'c' }, $args_sym)
270
+ end
243
271
  end
244
272
  end
@@ -5,431 +5,432 @@ require 'helper'
5
5
  module Cri
6
6
  class OptionParserTestCase < Cri::TestCase
7
7
  def test_parse_without_options
8
- input = %w[foo bar baz]
9
- definitions = []
8
+ input = %w[foo bar baz]
9
+ opt_defns = []
10
10
 
11
- parser = Cri::OptionParser.parse(input, definitions)
11
+ parser = Cri::OptionParser.new(input, opt_defns, []).run
12
12
 
13
13
  assert_equal({}, parser.options)
14
- assert_equal(%w[foo bar baz], parser.arguments)
14
+ assert_equal(%w[foo bar baz], parser.arguments.to_a)
15
15
  end
16
16
 
17
17
  def test_parse_with_invalid_option
18
- input = %w[foo -x]
19
- definitions = []
18
+ input = %w[foo -x]
19
+ opt_defns = []
20
20
 
21
21
  assert_raises(Cri::OptionParser::IllegalOptionError) do
22
- Cri::OptionParser.parse(input, definitions)
22
+ Cri::OptionParser.new(input, opt_defns, []).run
23
23
  end
24
24
  end
25
25
 
26
26
  def test_parse_with_unused_options
27
- input = %w[foo]
28
- definitions = [
27
+ input = %w[foo]
28
+ opt_defns = [
29
29
  { long: 'aaa', short: 'a', argument: :forbidden },
30
- ]
30
+ ].map { |hash| make_opt_defn(hash) }
31
31
 
32
- parser = Cri::OptionParser.parse(input, definitions)
32
+ parser = Cri::OptionParser.new(input, opt_defns, []).run
33
33
 
34
34
  assert(!parser.options[:aaa])
35
35
  end
36
36
 
37
37
  def test_parse_with_long_valueless_option
38
- input = %w[foo --aaa bar]
39
- definitions = [
38
+ input = %w[foo --aaa bar]
39
+ opt_defns = [
40
40
  { long: 'aaa', short: 'a', argument: :forbidden },
41
- ]
41
+ ].map { |hash| make_opt_defn(hash) }
42
42
 
43
- parser = Cri::OptionParser.parse(input, definitions)
43
+ parser = Cri::OptionParser.new(input, opt_defns, []).run
44
44
 
45
45
  assert(parser.options[:aaa])
46
- assert_equal(%w[foo bar], parser.arguments)
46
+ assert_equal(%w[foo bar], parser.arguments.to_a)
47
47
  end
48
48
 
49
49
  def test_parse_with_long_valueful_option
50
- input = %w[foo --aaa xxx bar]
51
- definitions = [
50
+ input = %w[foo --aaa xxx bar]
51
+ opt_defns = [
52
52
  { long: 'aaa', short: 'a', argument: :required },
53
- ]
53
+ ].map { |hash| make_opt_defn(hash) }
54
54
 
55
- parser = Cri::OptionParser.parse(input, definitions)
55
+ parser = Cri::OptionParser.new(input, opt_defns, []).run
56
56
 
57
57
  assert_equal({ aaa: 'xxx' }, parser.options)
58
- assert_equal(%w[foo bar], parser.arguments)
58
+ assert_equal(%w[foo bar], parser.arguments.to_a)
59
59
  end
60
60
 
61
61
  def test_parse_with_long_valueful_equalsign_option
62
- input = %w[foo --aaa=xxx bar]
63
- definitions = [
62
+ input = %w[foo --aaa=xxx bar]
63
+ opt_defns = [
64
64
  { long: 'aaa', short: 'a', argument: :required },
65
- ]
65
+ ].map { |hash| make_opt_defn(hash) }
66
66
 
67
- parser = Cri::OptionParser.parse(input, definitions)
67
+ parser = Cri::OptionParser.new(input, opt_defns, []).run
68
68
 
69
69
  assert_equal({ aaa: 'xxx' }, parser.options)
70
- assert_equal(%w[foo bar], parser.arguments)
70
+ assert_equal(%w[foo bar], parser.arguments.to_a)
71
71
  end
72
72
 
73
73
  def test_parse_with_long_valueful_option_with_missing_value
74
- input = %w[foo --aaa]
75
- definitions = [
74
+ input = %w[foo --aaa]
75
+ opt_defns = [
76
76
  { long: 'aaa', short: 'a', argument: :required },
77
- ]
77
+ ].map { |hash| make_opt_defn(hash) }
78
78
 
79
79
  assert_raises(Cri::OptionParser::OptionRequiresAnArgumentError) do
80
- Cri::OptionParser.parse(input, definitions)
80
+ Cri::OptionParser.new(input, opt_defns, []).run
81
81
  end
82
82
  end
83
83
 
84
84
  def test_parse_with_two_long_valueful_options
85
- input = %w[foo --all --port 2]
86
- definitions = [
85
+ input = %w[foo --all --port 2]
86
+ opt_defns = [
87
87
  { long: 'all', short: 'a', argument: :required },
88
88
  { long: 'port', short: 'p', argument: :required },
89
- ]
89
+ ].map { |hash| make_opt_defn(hash) }
90
90
 
91
91
  assert_raises(Cri::OptionParser::OptionRequiresAnArgumentError) do
92
- Cri::OptionParser.parse(input, definitions)
92
+ Cri::OptionParser.new(input, opt_defns, []).run
93
93
  end
94
94
  end
95
95
 
96
96
  def test_parse_with_long_valueless_option_with_optional_value
97
- input = %w[foo --aaa]
98
- definitions = [
97
+ input = %w[foo --aaa]
98
+ opt_defns = [
99
99
  { long: 'aaa', short: 'a', argument: :optional },
100
- ]
100
+ ].map { |hash| make_opt_defn(hash) }
101
101
 
102
- parser = Cri::OptionParser.parse(input, definitions)
102
+ parser = Cri::OptionParser.new(input, opt_defns, []).run
103
103
 
104
104
  assert(parser.options[:aaa])
105
- assert_equal(['foo'], parser.arguments)
105
+ assert_equal(['foo'], parser.arguments.to_a)
106
106
  end
107
107
 
108
108
  def test_parse_with_long_valueful_option_with_optional_value
109
- input = %w[foo --aaa xxx]
110
- definitions = [
109
+ input = %w[foo --aaa xxx]
110
+ opt_defns = [
111
111
  { long: 'aaa', short: 'a', argument: :optional },
112
- ]
112
+ ].map { |hash| make_opt_defn(hash) }
113
113
 
114
- parser = Cri::OptionParser.parse(input, definitions)
114
+ parser = Cri::OptionParser.new(input, opt_defns, []).run
115
115
 
116
116
  assert_equal({ aaa: 'xxx' }, parser.options)
117
- assert_equal(['foo'], parser.arguments)
117
+ assert_equal(['foo'], parser.arguments.to_a)
118
118
  end
119
119
 
120
120
  def test_parse_with_long_valueless_option_with_optional_value_and_more_options
121
- input = %w[foo --aaa -b -c]
122
- definitions = [
121
+ input = %w[foo --aaa -b -c]
122
+ opt_defns = [
123
123
  { long: 'aaa', short: 'a', argument: :optional },
124
124
  { long: 'bbb', short: 'b', argument: :forbidden },
125
125
  { long: 'ccc', short: 'c', argument: :forbidden },
126
- ]
126
+ ].map { |hash| make_opt_defn(hash) }
127
127
 
128
- parser = Cri::OptionParser.parse(input, definitions)
128
+ parser = Cri::OptionParser.new(input, opt_defns, []).run
129
129
 
130
130
  assert(parser.options[:aaa])
131
131
  assert(parser.options[:bbb])
132
132
  assert(parser.options[:ccc])
133
- assert_equal(['foo'], parser.arguments)
133
+ assert_equal(['foo'], parser.arguments.to_a)
134
134
  end
135
135
 
136
136
  def test_parse_with_short_valueless_options
137
- input = %w[foo -a bar]
138
- definitions = [
137
+ input = %w[foo -a bar]
138
+ opt_defns = [
139
139
  { long: 'aaa', short: 'a', argument: :forbidden },
140
- ]
140
+ ].map { |hash| make_opt_defn(hash) }
141
141
 
142
- parser = Cri::OptionParser.parse(input, definitions)
142
+ parser = Cri::OptionParser.new(input, opt_defns, []).run
143
143
 
144
144
  assert(parser.options[:aaa])
145
- assert_equal(%w[foo bar], parser.arguments)
145
+ assert_equal(%w[foo bar], parser.arguments.to_a)
146
146
  end
147
147
 
148
148
  def test_parse_with_short_valueful_option_with_missing_value
149
- input = %w[foo -a]
150
- definitions = [
149
+ input = %w[foo -a]
150
+ opt_defns = [
151
151
  { long: 'aaa', short: 'a', argument: :required },
152
- ]
152
+ ].map { |hash| make_opt_defn(hash) }
153
153
 
154
154
  assert_raises(Cri::OptionParser::OptionRequiresAnArgumentError) do
155
- Cri::OptionParser.parse(input, definitions)
155
+ Cri::OptionParser.new(input, opt_defns, []).run
156
156
  end
157
157
  end
158
158
 
159
159
  def test_parse_with_short_combined_valueless_options
160
- input = %w[foo -abc bar]
161
- definitions = [
160
+ input = %w[foo -abc bar]
161
+ opt_defns = [
162
162
  { long: 'aaa', short: 'a', argument: :forbidden },
163
163
  { long: 'bbb', short: 'b', argument: :forbidden },
164
164
  { long: 'ccc', short: 'c', argument: :forbidden },
165
- ]
165
+ ].map { |hash| make_opt_defn(hash) }
166
166
 
167
- parser = Cri::OptionParser.parse(input, definitions)
167
+ parser = Cri::OptionParser.new(input, opt_defns, []).run
168
168
 
169
169
  assert(parser.options[:aaa])
170
170
  assert(parser.options[:bbb])
171
171
  assert(parser.options[:ccc])
172
- assert_equal(%w[foo bar], parser.arguments)
172
+ assert_equal(%w[foo bar], parser.arguments.to_a)
173
173
  end
174
174
 
175
175
  def test_parse_with_short_combined_valueful_options_with_missing_value
176
- input = %w[foo -abc bar qux]
177
- definitions = [
176
+ input = %w[foo -abc bar qux]
177
+ opt_defns = [
178
178
  { long: 'aaa', short: 'a', argument: :required },
179
179
  { long: 'bbb', short: 'b', argument: :forbidden },
180
180
  { long: 'ccc', short: 'c', argument: :forbidden },
181
- ]
181
+ ].map { |hash| make_opt_defn(hash) }
182
182
 
183
- parser = Cri::OptionParser.parse(input, definitions)
183
+ parser = Cri::OptionParser.new(input, opt_defns, []).run
184
184
 
185
185
  assert_equal('bar', parser.options[:aaa])
186
186
  assert(parser.options[:bbb])
187
187
  assert(parser.options[:ccc])
188
- assert_equal(%w[foo qux], parser.arguments)
188
+ assert_equal(%w[foo qux], parser.arguments.to_a)
189
189
  end
190
190
 
191
191
  def test_parse_with_two_short_valueful_options
192
- input = %w[foo -a -p 2]
193
- definitions = [
192
+ input = %w[foo -a -p 2]
193
+ opt_defns = [
194
194
  { long: 'all', short: 'a', argument: :required },
195
195
  { long: 'port', short: 'p', argument: :required },
196
- ]
196
+ ].map { |hash| make_opt_defn(hash) }
197
197
 
198
198
  assert_raises(Cri::OptionParser::OptionRequiresAnArgumentError) do
199
- Cri::OptionParser.parse(input, definitions)
199
+ Cri::OptionParser.new(input, opt_defns, []).run
200
200
  end
201
201
  end
202
202
 
203
203
  def test_parse_with_short_valueless_option_with_optional_value
204
- input = %w[foo -a]
205
- definitions = [
204
+ input = %w[foo -a]
205
+ opt_defns = [
206
206
  { long: 'aaa', short: 'a', argument: :optional },
207
- ]
207
+ ].map { |hash| make_opt_defn(hash) }
208
208
 
209
- parser = Cri::OptionParser.parse(input, definitions)
209
+ parser = Cri::OptionParser.new(input, opt_defns, []).run
210
210
 
211
211
  assert(parser.options[:aaa])
212
- assert_equal(['foo'], parser.arguments)
212
+ assert_equal(['foo'], parser.arguments.to_a)
213
213
  end
214
214
 
215
215
  def test_parse_with_short_valueful_option_with_optional_value
216
- input = %w[foo -a xxx]
217
- definitions = [
216
+ input = %w[foo -a xxx]
217
+ opt_defns = [
218
218
  { long: 'aaa', short: 'a', argument: :optional },
219
- ]
219
+ ].map { |hash| make_opt_defn(hash) }
220
220
 
221
- parser = Cri::OptionParser.parse(input, definitions)
221
+ parser = Cri::OptionParser.new(input, opt_defns, []).run
222
222
 
223
223
  assert_equal({ aaa: 'xxx' }, parser.options)
224
- assert_equal(['foo'], parser.arguments)
224
+ assert_equal(['foo'], parser.arguments.to_a)
225
225
  end
226
226
 
227
227
  def test_parse_with_short_valueless_option_with_optional_value_and_more_options
228
- input = %w[foo -a -b -c]
229
- definitions = [
228
+ input = %w[foo -a -b -c]
229
+ opt_defns = [
230
230
  { long: 'aaa', short: 'a', argument: :optional },
231
231
  { long: 'bbb', short: 'b', argument: :forbidden },
232
232
  { long: 'ccc', short: 'c', argument: :forbidden },
233
- ]
233
+ ].map { |hash| make_opt_defn(hash) }
234
234
 
235
- parser = Cri::OptionParser.parse(input, definitions)
235
+ parser = Cri::OptionParser.new(input, opt_defns, []).run
236
236
 
237
237
  assert(parser.options[:aaa])
238
238
  assert(parser.options[:bbb])
239
239
  assert(parser.options[:ccc])
240
- assert_equal(['foo'], parser.arguments)
240
+ assert_equal(['foo'], parser.arguments.to_a)
241
241
  end
242
242
 
243
243
  def test_parse_with_single_hyphen
244
- input = %w[foo - bar]
245
- definitions = []
244
+ input = %w[foo - bar]
245
+ opt_defns = []
246
246
 
247
- parser = Cri::OptionParser.parse(input, definitions)
247
+ parser = Cri::OptionParser.new(input, opt_defns, []).run
248
248
 
249
249
  assert_equal({}, parser.options)
250
- assert_equal(['foo', '-', 'bar'], parser.arguments)
250
+ assert_equal(['foo', '-', 'bar'], parser.arguments.to_a)
251
251
  end
252
252
 
253
253
  def test_parse_with_end_marker
254
- input = %w[foo bar -- -x --yyy -abc]
255
- definitions = []
254
+ input = %w[foo bar -- -x --yyy -abc]
255
+ opt_defns = []
256
256
 
257
- parser = Cri::OptionParser.parse(input, definitions)
257
+ parser = Cri::OptionParser.new(input, opt_defns, []).run
258
258
 
259
259
  assert_equal({}, parser.options)
260
- assert_equal(['foo', 'bar', '-x', '--yyy', '-abc'], parser.arguments)
260
+ assert_equal(['foo', 'bar', '-x', '--yyy', '-abc'], parser.arguments.to_a)
261
261
  end
262
262
 
263
263
  def test_parse_with_end_marker_between_option_key_and_value
264
- input = %w[foo --aaa -- zzz]
265
- definitions = [
264
+ input = %w[foo --aaa -- zzz]
265
+ opt_defns = [
266
266
  { long: 'aaa', short: 'a', argument: :required },
267
- ]
267
+ ].map { |hash| make_opt_defn(hash) }
268
268
 
269
269
  assert_raises(Cri::OptionParser::OptionRequiresAnArgumentError) do
270
- Cri::OptionParser.parse(input, definitions)
270
+ Cri::OptionParser.new(input, opt_defns, []).run
271
271
  end
272
272
  end
273
273
 
274
274
  def test_parse_with_multiple_options
275
275
  input = %w[foo -o test -o test2 -v -v -v]
276
- definitions = [
276
+ opt_defns = [
277
277
  { long: 'long', short: 'o', argument: :required, multiple: true },
278
278
  { long: 'verbose', short: 'v', multiple: true },
279
- ]
280
- parser = Cri::OptionParser.parse(input, definitions)
279
+ ].map { |hash| make_opt_defn(hash) }
280
+
281
+ parser = Cri::OptionParser.new(input, opt_defns, []).run
281
282
 
282
283
  assert_equal(%w[test test2], parser.options[:long])
283
284
  assert_equal(3, parser.options[:verbose].size)
284
285
  end
285
286
 
286
287
  def test_parse_with_default_required_unspecified
287
- input = %w[foo]
288
- definitions = [
288
+ input = %w[foo]
289
+ opt_defns = [
289
290
  { long: 'animal', short: 'a', argument: :required, default: 'donkey' },
290
- ]
291
+ ].map { |hash| make_opt_defn(hash) }
291
292
 
292
- parser = Cri::OptionParser.parse(input, definitions)
293
+ parser = Cri::OptionParser.new(input, opt_defns, []).run
293
294
 
294
295
  assert_equal({ animal: 'donkey' }, parser.options)
295
- assert_equal(['foo'], parser.arguments)
296
+ assert_equal(['foo'], parser.arguments.to_a)
296
297
  end
297
298
 
298
299
  def test_parse_with_default_required_no_value
299
- input = %w[foo -a]
300
- definitions = [
300
+ input = %w[foo -a]
301
+ opt_defns = [
301
302
  { long: 'animal', short: 'a', argument: :required, default: 'donkey' },
302
- ]
303
+ ].map { |hash| make_opt_defn(hash) }
303
304
 
304
305
  assert_raises(Cri::OptionParser::OptionRequiresAnArgumentError) do
305
- Cri::OptionParser.parse(input, definitions)
306
+ Cri::OptionParser.new(input, opt_defns, []).run
306
307
  end
307
308
  end
308
309
 
309
310
  def test_parse_with_default_required_value
310
- input = %w[foo -a giraffe]
311
- definitions = [
311
+ input = %w[foo -a giraffe]
312
+ opt_defns = [
312
313
  { long: 'animal', short: 'a', argument: :required, default: 'donkey' },
313
- ]
314
+ ].map { |hash| make_opt_defn(hash) }
314
315
 
315
- parser = Cri::OptionParser.parse(input, definitions)
316
+ parser = Cri::OptionParser.new(input, opt_defns, []).run
316
317
 
317
318
  assert_equal({ animal: 'giraffe' }, parser.options)
318
- assert_equal(['foo'], parser.arguments)
319
+ assert_equal(['foo'], parser.arguments.to_a)
319
320
  end
320
321
 
321
322
  def test_parse_with_default_optional_unspecified
322
- input = %w[foo]
323
- definitions = [
323
+ input = %w[foo]
324
+ opt_defns = [
324
325
  { long: 'animal', short: 'a', argument: :optional, default: 'donkey' },
325
- ]
326
+ ].map { |hash| make_opt_defn(hash) }
326
327
 
327
- parser = Cri::OptionParser.parse(input, definitions)
328
+ parser = Cri::OptionParser.new(input, opt_defns, []).run
328
329
 
329
330
  assert_equal({ animal: 'donkey' }, parser.options)
330
- assert_equal(['foo'], parser.arguments)
331
+ assert_equal(['foo'], parser.arguments.to_a)
331
332
  end
332
333
 
333
334
  def test_parse_with_default_optional_no_value
334
- input = %w[foo -a]
335
- definitions = [
335
+ input = %w[foo -a]
336
+ opt_defns = [
336
337
  { long: 'animal', short: 'a', argument: :optional, default: 'donkey' },
337
- ]
338
+ ].map { |hash| make_opt_defn(hash) }
338
339
 
339
- parser = Cri::OptionParser.parse(input, definitions)
340
+ parser = Cri::OptionParser.new(input, opt_defns, []).run
340
341
 
341
342
  assert_equal({ animal: 'donkey' }, parser.options)
342
- assert_equal(['foo'], parser.arguments)
343
+ assert_equal(['foo'], parser.arguments.to_a)
343
344
  end
344
345
 
345
346
  def test_parse_with_default_optional_value
346
- input = %w[foo -a giraffe]
347
- definitions = [
347
+ input = %w[foo -a giraffe]
348
+ opt_defns = [
348
349
  { long: 'animal', short: 'a', argument: :optional, default: 'donkey' },
349
- ]
350
+ ].map { |hash| make_opt_defn(hash) }
350
351
 
351
- parser = Cri::OptionParser.parse(input, definitions)
352
+ parser = Cri::OptionParser.new(input, opt_defns, []).run
352
353
 
353
354
  assert_equal({ animal: 'giraffe' }, parser.options)
354
- assert_equal(['foo'], parser.arguments)
355
+ assert_equal(['foo'], parser.arguments.to_a)
355
356
  end
356
357
 
357
358
  def test_parse_with_default_optional_value_and_arg
358
- input = %w[foo -a gi raffe]
359
- definitions = [
359
+ input = %w[foo -a gi raffe]
360
+ opt_defns = [
360
361
  { long: 'animal', short: 'a', argument: :optional, default: 'donkey' },
361
- ]
362
+ ].map { |hash| make_opt_defn(hash) }
362
363
 
363
- parser = Cri::OptionParser.parse(input, definitions)
364
+ parser = Cri::OptionParser.new(input, opt_defns, []).run
364
365
 
365
366
  assert_equal({ animal: 'gi' }, parser.options)
366
- assert_equal(%w[foo raffe], parser.arguments)
367
+ assert_equal(%w[foo raffe], parser.arguments.to_a)
367
368
  end
368
369
 
369
370
  def test_parse_with_combined_required_options
370
- input = %w[foo -abc xxx yyy zzz]
371
- definitions = [
371
+ input = %w[foo -abc xxx yyy zzz]
372
+ opt_defns = [
372
373
  { long: 'aaa', short: 'a', argument: :forbidden },
373
374
  { long: 'bbb', short: 'b', argument: :required },
374
375
  { long: 'ccc', short: 'c', argument: :required },
375
- ]
376
+ ].map { |hash| make_opt_defn(hash) }
376
377
 
377
- parser = Cri::OptionParser.parse(input, definitions)
378
+ parser = Cri::OptionParser.new(input, opt_defns, []).run
378
379
 
379
380
  assert_equal({ aaa: true, bbb: 'xxx', ccc: 'yyy' }, parser.options)
380
- assert_equal(%w[foo zzz], parser.arguments)
381
+ assert_equal(%w[foo zzz], parser.arguments.to_a)
381
382
  end
382
383
 
383
384
  def test_parse_with_combined_optional_options
384
- input = %w[foo -abc xxx yyy zzz]
385
- definitions = [
385
+ input = %w[foo -abc xxx yyy zzz]
386
+ opt_defns = [
386
387
  { long: 'aaa', short: 'a', argument: :forbidden },
387
388
  { long: 'bbb', short: 'b', argument: :optional },
388
389
  { long: 'ccc', short: 'c', argument: :required },
389
- ]
390
+ ].map { |hash| make_opt_defn(hash) }
390
391
 
391
- parser = Cri::OptionParser.parse(input, definitions)
392
+ parser = Cri::OptionParser.new(input, opt_defns, []).run
392
393
 
393
394
  assert_equal({ aaa: true, bbb: 'xxx', ccc: 'yyy' }, parser.options)
394
- assert_equal(%w[foo zzz], parser.arguments)
395
+ assert_equal(%w[foo zzz], parser.arguments.to_a)
395
396
  end
396
397
 
397
398
  def test_parse_with_combined_optional_options_with_missing_value
398
- input = %w[foo -abc xxx]
399
- definitions = [
399
+ input = %w[foo -abc xxx]
400
+ opt_defns = [
400
401
  { long: 'aaa', short: 'a', argument: :forbidden },
401
402
  { long: 'bbb', short: 'b', argument: :required },
402
403
  { long: 'ccc', short: 'c', argument: :optional, default: 'c default' },
403
- ]
404
+ ].map { |hash| make_opt_defn(hash) }
404
405
 
405
- parser = Cri::OptionParser.parse(input, definitions)
406
+ parser = Cri::OptionParser.new(input, opt_defns, []).run
406
407
 
407
408
  assert_equal({ aaa: true, bbb: 'xxx', ccc: 'c default' }, parser.options)
408
- assert_equal(%w[foo], parser.arguments)
409
+ assert_equal(%w[foo], parser.arguments.to_a)
409
410
  end
410
411
 
411
412
  def test_parse_with_transform_proc
412
- input = %w[--port 123]
413
- definitions = [
413
+ input = %w[--port 123]
414
+ opt_defns = [
414
415
  { long: 'port', short: 'p', argument: :required, transform: ->(x) { Integer(x) } },
415
- ]
416
+ ].map { |hash| make_opt_defn(hash) }
416
417
 
417
- parser = Cri::OptionParser.parse(input, definitions)
418
+ parser = Cri::OptionParser.new(input, opt_defns, []).run
418
419
 
419
420
  assert_equal({ port: 123 }, parser.options)
420
- assert_equal([], parser.arguments)
421
+ assert_equal([], parser.arguments.to_a)
421
422
  end
422
423
 
423
424
  def test_parse_with_transform_method
424
- input = %w[--port 123]
425
- definitions = [
425
+ input = %w[--port 123]
426
+ opt_defns = [
426
427
  { long: 'port', short: 'p', argument: :required, transform: method(:Integer) },
427
- ]
428
+ ].map { |hash| make_opt_defn(hash) }
428
429
 
429
- parser = Cri::OptionParser.parse(input, definitions)
430
+ parser = Cri::OptionParser.new(input, opt_defns, []).run
430
431
 
431
432
  assert_equal({ port: 123 }, parser.options)
432
- assert_equal([], parser.arguments)
433
+ assert_equal([], parser.arguments.to_a)
433
434
  end
434
435
 
435
436
  def test_parse_with_transform_object
@@ -439,15 +440,15 @@ module Cri
439
440
  end
440
441
  end.new
441
442
 
442
- input = %w[--port 123]
443
- definitions = [
443
+ input = %w[--port 123]
444
+ opt_defns = [
444
445
  { long: 'port', short: 'p', argument: :required, transform: port },
445
- ]
446
+ ].map { |hash| make_opt_defn(hash) }
446
447
 
447
- parser = Cri::OptionParser.parse(input, definitions)
448
+ parser = Cri::OptionParser.new(input, opt_defns, []).run
448
449
 
449
450
  assert_equal({ port: 123 }, parser.options)
450
- assert_equal([], parser.arguments)
451
+ assert_equal([], parser.arguments.to_a)
451
452
  end
452
453
 
453
454
  def test_parse_with_transform_default
@@ -458,27 +459,108 @@ module Cri
458
459
  end
459
460
  end.new
460
461
 
461
- input = %w[]
462
- definitions = [
462
+ input = %w[]
463
+ opt_defns = [
463
464
  { long: 'port', short: 'p', argument: :required, default: 8080, transform: port },
464
- ]
465
+ ].map { |hash| make_opt_defn(hash) }
465
466
 
466
- parser = Cri::OptionParser.parse(input, definitions)
467
+ parser = Cri::OptionParser.new(input, opt_defns, []).run
467
468
 
468
469
  assert_equal({ port: 8080 }, parser.options)
469
- assert_equal([], parser.arguments)
470
+ assert_equal([], parser.arguments.to_a)
470
471
  end
471
472
 
472
473
  def test_parse_with_transform_exception
473
- input = %w[--port one_hundred_and_twenty_three]
474
- definitions = [
474
+ input = %w[--port one_hundred_and_twenty_three]
475
+ opt_defns = [
475
476
  { long: 'port', short: 'p', argument: :required, transform: method(:Integer) },
476
- ]
477
+ ].map { |hash| make_opt_defn(hash) }
477
478
 
478
479
  exception = assert_raises(Cri::OptionParser::IllegalOptionValueError) do
479
- Cri::OptionParser.parse(input, definitions)
480
+ Cri::OptionParser.new(input, opt_defns, []).run
480
481
  end
481
482
  assert_equal('invalid value "one_hundred_and_twenty_three" for --port option', exception.message)
482
483
  end
484
+
485
+ def test_parse_with_param_defns
486
+ input = %w[localhost]
487
+ param_defns = [
488
+ { name: 'host' },
489
+ ].map { |hash| Cri::ParamDefinition.new(hash) }
490
+
491
+ parser = Cri::OptionParser.new(input, [], param_defns).run
492
+ assert_equal({}, parser.options)
493
+ assert_equal('localhost', parser.arguments[0])
494
+ assert_equal('localhost', parser.arguments[:host])
495
+ end
496
+
497
+ def test_parse_with_param_defns_too_few_args
498
+ input = []
499
+ param_defns = [
500
+ { name: 'host' },
501
+ ].map { |hash| Cri::ParamDefinition.new(hash) }
502
+
503
+ parser = Cri::OptionParser.new(input, [], param_defns).run
504
+ exception = assert_raises(Cri::ArgumentList::ArgumentCountMismatchError) do
505
+ parser.arguments
506
+ end
507
+ assert_equal('incorrect number of arguments given: expected 1, but got 0', exception.message)
508
+ end
509
+
510
+ def test_parse_with_param_defns_too_many_args
511
+ input = %w[localhost oink]
512
+ param_defns = [
513
+ { name: 'host' },
514
+ ].map { |hash| Cri::ParamDefinition.new(hash) }
515
+
516
+ parser = Cri::OptionParser.new(input, [], param_defns).run
517
+ exception = assert_raises(Cri::ArgumentList::ArgumentCountMismatchError) do
518
+ parser.arguments
519
+ end
520
+ assert_equal('incorrect number of arguments given: expected 1, but got 2', exception.message)
521
+ end
522
+
523
+ def test_parse_with_param_defns_invalid_key
524
+ input = %w[localhost]
525
+ param_defns = [
526
+ { name: 'host' },
527
+ ].map { |hash| Cri::ParamDefinition.new(hash) }
528
+
529
+ parser = Cri::OptionParser.new(input, [], param_defns).run
530
+
531
+ exception = assert_raises(ArgumentError) do
532
+ parser.arguments['oink']
533
+ end
534
+ assert_equal('argument lists can be indexed using a Symbol or an Integer, but not a String', exception.message)
535
+ end
536
+
537
+ def test_parse_with_param_defns_two_params
538
+ input = %w[localhost example.com]
539
+ param_defns = [
540
+ { name: 'source' },
541
+ { name: 'target' },
542
+ ].map { |hash| Cri::ParamDefinition.new(hash) }
543
+
544
+ parser = Cri::OptionParser.new(input, [], param_defns).run
545
+ assert_equal({}, parser.options)
546
+ assert_equal('localhost', parser.arguments[0])
547
+ assert_equal('localhost', parser.arguments[:source])
548
+ assert_equal('example.com', parser.arguments[1])
549
+ assert_equal('example.com', parser.arguments[:target])
550
+ end
551
+
552
+ def make_opt_defn(hash)
553
+ Cri::OptionDefinition.new(
554
+ short: hash.fetch(:short, nil),
555
+ long: hash.fetch(:long, nil),
556
+ desc: hash.fetch(:desc, nil),
557
+ argument: hash.fetch(:argument, nil),
558
+ multiple: hash.fetch(:multiple, nil),
559
+ block: hash.fetch(:block, nil),
560
+ hidden: hash.fetch(:hidden, nil),
561
+ default: hash.fetch(:default, nil),
562
+ transform: hash.fetch(:transform, nil),
563
+ )
564
+ end
483
565
  end
484
566
  end