rake-commander 0.3.6 → 0.4.1
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.
- checksums.yaml +4 -4
- data/.markdownlint.json +4 -0
- data/.rubocop.yml +56 -43
- data/.ruby-version +1 -0
- data/CHANGELOG.md +118 -84
- data/README.md +4 -0
- data/examples/01_basic_example.rb +3 -1
- data/examples/03_a_chainer_plus_example.rb +3 -2
- data/lib/rake-commander/base/class_auto_loader.rb +10 -1
- data/lib/rake-commander/base/custom_error.rb +3 -3
- data/lib/rake-commander/base.rb +2 -1
- data/lib/rake-commander/option.rb +66 -33
- data/lib/rake-commander/options/arguments.rb +55 -29
- data/lib/rake-commander/options/description.rb +28 -1
- data/lib/rake-commander/options/error/base.rb +6 -2
- data/lib/rake-commander/options/error/handling.rb +12 -3
- data/lib/rake-commander/options/error/invalid_argument.rb +3 -2
- data/lib/rake-commander/options/error/invalid_option.rb +1 -1
- data/lib/rake-commander/options/error/missing_argument.rb +1 -1
- data/lib/rake-commander/options/error.rb +19 -7
- data/lib/rake-commander/options/name.rb +41 -18
- data/lib/rake-commander/options/result.rb +15 -4
- data/lib/rake-commander/options/set.rb +2 -0
- data/lib/rake-commander/options/type.rb +28 -0
- data/lib/rake-commander/options.rb +31 -12
- data/lib/rake-commander/patcher/application/top_level_resume.rb +2 -0
- data/lib/rake-commander/patcher/debug.rb +5 -0
- data/lib/rake-commander/rake_task.rb +13 -4
- data/lib/rake-commander/version.rb +1 -1
- data/rake-commander.gemspec +6 -5
- metadata +11 -33
@@ -4,6 +4,7 @@ class RakeCommander
|
|
4
4
|
extend RakeCommander::Base::ClassHelpers
|
5
5
|
extend RakeCommander::Options::Name
|
6
6
|
include RakeCommander::Options::Description
|
7
|
+
include RakeCommander::Options::Type
|
7
8
|
|
8
9
|
attr_reader :name_full, :desc, :default
|
9
10
|
|
@@ -13,12 +14,14 @@ class RakeCommander
|
|
13
14
|
|
14
15
|
@name_full = name.freeze
|
15
16
|
super(short.freeze, @name_full)
|
17
|
+
|
16
18
|
@default = kargs[:default] if kargs.key?(:default)
|
17
19
|
@desc = kargs[:desc] if kargs.key?(:desc)
|
18
20
|
@required = kargs[:required] if kargs.key?(:required)
|
19
21
|
@type_coercion = kargs[:type] if kargs.key?(:type)
|
20
22
|
@other_args = args
|
21
23
|
@original_block = block
|
24
|
+
|
22
25
|
configure_other
|
23
26
|
end
|
24
27
|
|
@@ -33,7 +36,9 @@ class RakeCommander
|
|
33
36
|
# Creates a new option, result of merging this `opt` with this option,
|
34
37
|
# @return [RakeCommander::Option] where opt has been merged
|
35
38
|
def merge(opt, **kargs)
|
36
|
-
|
39
|
+
msg = "Expecting RakeCommander::Option. Given: #{opt.class}"
|
40
|
+
raise msg unless opt.is_a?(RakeCommander::Option)
|
41
|
+
|
37
42
|
dup(**opt.dup_key_arguments.merge(kargs), &opt.original_block)
|
38
43
|
end
|
39
44
|
|
@@ -81,7 +86,8 @@ class RakeCommander
|
|
81
86
|
|
82
87
|
# @param [String, Nil] the argument, may it exist
|
83
88
|
def argument
|
84
|
-
return
|
89
|
+
return unless argument?
|
90
|
+
|
85
91
|
self.class.name_argument(name_full)
|
86
92
|
end
|
87
93
|
|
@@ -93,10 +99,23 @@ class RakeCommander
|
|
93
99
|
# @return [Class, NilClass]
|
94
100
|
def type_coercion
|
95
101
|
value = @type_coercion || (default? && default.class)
|
96
|
-
return
|
102
|
+
return unless allowed_type?(value)
|
103
|
+
|
97
104
|
value
|
98
105
|
end
|
99
106
|
|
107
|
+
# @return [Boolean] whether the option is an enum with fixed values.
|
108
|
+
def enum?
|
109
|
+
type_coercion.is_a?(Array)
|
110
|
+
end
|
111
|
+
|
112
|
+
# @return [Array, NilClass] the valid options when is `enum?`
|
113
|
+
def enum_options
|
114
|
+
return unless enum?
|
115
|
+
|
116
|
+
type_coercion
|
117
|
+
end
|
118
|
+
|
100
119
|
# @return [Boolean]
|
101
120
|
def default?
|
102
121
|
instance_variable_defined?(:@default)
|
@@ -107,9 +126,12 @@ class RakeCommander
|
|
107
126
|
# @param opt_parser [OptionParser] the option parser to add this option's switch.
|
108
127
|
# @param implicit_short [Boolean] whether the implicit short of this option is active in the opts_parser.
|
109
128
|
def add_switch(opts_parser, where: :base, implicit_short: false, &middleware)
|
110
|
-
|
129
|
+
msg = "Expecting OptionParser. Given: #{opts_parser.class}"
|
130
|
+
raise msg unless opts_parser.is_a?(OptionParser)
|
131
|
+
|
111
132
|
args = switch_args(implicit_short: implicit_short)
|
112
133
|
block = option_block(&middleware)
|
134
|
+
|
113
135
|
case where
|
114
136
|
when :head, :top
|
115
137
|
opts_parser.on_head(*args, &block)
|
@@ -127,13 +149,14 @@ class RakeCommander
|
|
127
149
|
|
128
150
|
# @return [Hash] keyed arguments to create a new object
|
129
151
|
def dup_key_arguments
|
130
|
-
configure_other
|
131
152
|
{}.tap do |kargs|
|
153
|
+
configure_other
|
154
|
+
|
132
155
|
kargs.merge!(short: short.dup.freeze) if short
|
133
156
|
kargs.merge!(name: name_full.dup.freeze) if name_full
|
134
157
|
kargs.merge!(desc: @desc.dup) if @desc
|
135
158
|
kargs.merge!(default: @default.dup) if default?
|
136
|
-
kargs.merge!(type: @type_coercion) if @type_coercion
|
159
|
+
kargs.merge!(type: @type_coercion) if allowed_type?(@type_coercion)
|
137
160
|
kargs.merge!(required: required?)
|
138
161
|
end
|
139
162
|
end
|
@@ -141,6 +164,7 @@ class RakeCommander
|
|
141
164
|
# @return [Array<Variant>]
|
142
165
|
def switch_args(implicit_short: false)
|
143
166
|
configure_other
|
167
|
+
|
144
168
|
args = [short_hyphen, name_hyphen]
|
145
169
|
args.push(*switch_desc(implicit_short: implicit_short))
|
146
170
|
args << type_coercion if type_coercion
|
@@ -152,10 +176,13 @@ class RakeCommander
|
|
152
176
|
# Called on parse runtime
|
153
177
|
def option_block(&middleware)
|
154
178
|
block_extra_args = [default, short, name, self]
|
179
|
+
|
155
180
|
proc do |value|
|
156
181
|
value = !value if type_coercion == FalseClass
|
157
182
|
args = block_extra_args.dup.unshift(value)
|
183
|
+
|
158
184
|
original_block&.call(*args)
|
185
|
+
|
159
186
|
middleware&.call(*args)
|
160
187
|
end
|
161
188
|
end
|
@@ -165,8 +192,9 @@ class RakeCommander
|
|
165
192
|
# @return [Array<String>]
|
166
193
|
def switch_desc(implicit_short: false, line_width: DESC_MAX_LENGTH)
|
167
194
|
ishort = implicit_short ? "( -#{short_implicit} ) " : ''
|
168
|
-
str = "#{required_desc}#{ishort}#{desc}#{default_desc}"
|
195
|
+
str = "#{required_desc}#{ishort}#{desc}#{enum_desc}#{default_desc}"
|
169
196
|
return [] if str.empty?
|
197
|
+
|
170
198
|
string_to_lines(str, max: line_width)
|
171
199
|
end
|
172
200
|
|
@@ -175,12 +203,15 @@ class RakeCommander
|
|
175
203
|
end
|
176
204
|
|
177
205
|
def default_desc
|
178
|
-
return
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
206
|
+
return unless default?
|
207
|
+
|
208
|
+
" { Default: '#{default}' }"
|
209
|
+
end
|
210
|
+
|
211
|
+
def enum_desc
|
212
|
+
return unless enum?
|
213
|
+
|
214
|
+
" Options: [ #{enum_options.join(' | ')} ]."
|
184
215
|
end
|
185
216
|
|
186
217
|
# Helper to simplify `short` and `name` capture from arguments and keyed arguments.
|
@@ -191,8 +222,11 @@ class RakeCommander
|
|
191
222
|
name ||= capture_arguments_name!(args, sample_n_short: sample && short)
|
192
223
|
|
193
224
|
unless sample
|
194
|
-
|
195
|
-
raise ArgumentError,
|
225
|
+
msg = "A short of one letter should be provided. Given: #{short}"
|
226
|
+
raise ArgumentError, msg unless self.class.valid_short?(short)
|
227
|
+
|
228
|
+
msg = "A name should be provided. Given: #{name}"
|
229
|
+
raise ArgumentError, msg unless self.class.valid_name?(name)
|
196
230
|
end
|
197
231
|
|
198
232
|
[short, name]
|
@@ -213,41 +247,40 @@ class RakeCommander
|
|
213
247
|
# @note if found it removes it from args.
|
214
248
|
# @return [String, Symbol, NilClass]
|
215
249
|
def capture_arguments_name!(args, sample_n_short: false)
|
216
|
-
name
|
250
|
+
name = nil
|
217
251
|
name ||= self.class.capture_arguments_name!(args, symbol: true)
|
218
252
|
name ||= self.class.capture_arguments_name!(args, symbol: true, strict: false)
|
219
253
|
name ||= self.class.capture_arguments_name!(args)
|
220
|
-
name
|
254
|
+
name ||= self.class.capture_arguments_name!(args, strict: false) unless sample_n_short
|
255
|
+
name
|
221
256
|
end
|
222
257
|
|
223
258
|
# The remaining `args` received in the initialization
|
224
259
|
def other_args(*args)
|
225
260
|
@other_args ||= []
|
226
|
-
if args.empty?
|
227
|
-
|
228
|
-
|
229
|
-
@other_args.push(*args)
|
230
|
-
end
|
261
|
+
return @other_args if args.empty?
|
262
|
+
|
263
|
+
@other_args.push(*args)
|
231
264
|
end
|
232
265
|
|
233
266
|
# It consumes `other_args`, to prevent direct overrides to be overriden by it.
|
267
|
+
# @note at the end we will pass the switch arguments to OptsParser.
|
234
268
|
def configure_other
|
235
|
-
@type_coercion
|
236
|
-
@desc
|
269
|
+
@type_coercion = fetch_type_from_other(@type_coercion)
|
270
|
+
@desc = fetch_desc_from_other(@desc)
|
237
271
|
nil
|
238
272
|
end
|
239
273
|
|
240
|
-
def fetch_type_from_other
|
241
|
-
|
242
|
-
|
274
|
+
def fetch_type_from_other(original = nil)
|
275
|
+
other_type = fetch_type!(other_args)
|
276
|
+
|
277
|
+
return original if original
|
278
|
+
|
279
|
+
other_type
|
243
280
|
end
|
244
281
|
|
245
|
-
def fetch_desc_from_other
|
246
|
-
|
247
|
-
other_args.dup.each do |val|
|
248
|
-
other_args.delete(val) if val.is_a?(String)
|
249
|
-
end
|
250
|
-
value
|
282
|
+
def fetch_desc_from_other(original = nil)
|
283
|
+
joined_lines(original, fetch_desc!(other_args))
|
251
284
|
end
|
252
285
|
end
|
253
286
|
end
|
@@ -3,12 +3,12 @@ class RakeCommander
|
|
3
3
|
# Offers helpers to treat `ARGV`
|
4
4
|
module Arguments
|
5
5
|
RAKE_COMMAND_EXTENDED_OPTIONS_START = '--'.freeze
|
6
|
-
NAME_ARGUMENT = /^--(?<option>[\w_-]*)
|
7
|
-
BOOLEAN_ARGUMENT = /(?:^|--)no-(?<option>[\w_-]*)
|
6
|
+
NAME_ARGUMENT = /^--(?<option>[\w_-]*).*?$/
|
7
|
+
BOOLEAN_ARGUMENT = /(?:^|--)no-(?<option>[\w_-]*).*?$/
|
8
8
|
|
9
9
|
class << self
|
10
10
|
def included(base)
|
11
|
-
super
|
11
|
+
super
|
12
12
|
base.extend ClassMethods
|
13
13
|
end
|
14
14
|
end
|
@@ -20,6 +20,7 @@ class RakeCommander
|
|
20
20
|
# @return [Boolean] whether enhanced parsing should be switched on or off.
|
21
21
|
def argv_with_enhanced_syntax?(argv = ARGV)
|
22
22
|
return false unless argv.is_a?(Array)
|
23
|
+
|
23
24
|
argv.include?(RAKE_COMMAND_EXTENDED_OPTIONS_START)
|
24
25
|
end
|
25
26
|
|
@@ -41,6 +42,7 @@ class RakeCommander
|
|
41
42
|
def argv_cropping_for_rake(value = :not_used)
|
42
43
|
@argv_cropping_for_rake = true if @argv_cropping_for_rake.nil?
|
43
44
|
return @argv_cropping_for_rake if value == :not_used
|
45
|
+
|
44
46
|
@argv_cropping_for_rake = !!value
|
45
47
|
end
|
46
48
|
|
@@ -51,8 +53,8 @@ class RakeCommander
|
|
51
53
|
# @param argv [Array<String>] the command line arguments array.
|
52
54
|
# @return [Array<String>] the target arguments to be parsed by `RakeCommander::Options`
|
53
55
|
def argv_extended_options(argv = ARGV.dup)
|
54
|
-
if idx = argv.index(RAKE_COMMAND_EXTENDED_OPTIONS_START)
|
55
|
-
argv[idx+1
|
56
|
+
if (idx = argv.index(RAKE_COMMAND_EXTENDED_OPTIONS_START))
|
57
|
+
argv[idx + 1..]
|
56
58
|
else
|
57
59
|
[]
|
58
60
|
end
|
@@ -63,9 +65,11 @@ class RakeCommander
|
|
63
65
|
# @return [Array<String>] the argv without the extended options of this gem.
|
64
66
|
def argv_rake_native_arguments(argv = ARGV.dup)
|
65
67
|
return argv unless argv_cropping_for_rake
|
66
|
-
|
68
|
+
|
69
|
+
if (idx = argv.index(RAKE_COMMAND_EXTENDED_OPTIONS_START))
|
67
70
|
argv = argv[0..idx]
|
68
71
|
end
|
72
|
+
|
69
73
|
argv
|
70
74
|
end
|
71
75
|
|
@@ -77,10 +81,10 @@ class RakeCommander
|
|
77
81
|
# - So some tidy up is necessary and the head of the command (i.e. `rake some:task --`)
|
78
82
|
# should be excluded from arguments to input to the options parser.
|
79
83
|
# @see `RakeCommander::Options#parse_options`
|
80
|
-
def parse_options(argv = ARGV, *
|
84
|
+
def parse_options(argv = ARGV, *_args, **_kargs)
|
81
85
|
argv = argv_extended_options(argv)
|
82
86
|
argv = argv_pre_parsed(argv, options: options_hash(with_implicit: true))
|
83
|
-
super
|
87
|
+
super
|
84
88
|
end
|
85
89
|
|
86
90
|
# Options with arguments should not take another option as value.
|
@@ -95,22 +99,31 @@ class RakeCommander
|
|
95
99
|
# 2. To overcome this limitation, you may enclose in double quotes and argument with
|
96
100
|
# that start (i,e, `"--argument"`).
|
97
101
|
# @example
|
98
|
-
# 1. `-abc ARGUMENT` where only `c` receives the argument
|
99
|
-
#
|
100
|
-
# 2. `-
|
101
|
-
#
|
102
|
-
#
|
103
|
-
#
|
102
|
+
# 1. `-abc ARGUMENT` where only `c` receives the argument
|
103
|
+
# becomes `-ab -c ARGUMENT`
|
104
|
+
# 2. `-abc ARGUMENT` where `b` and `c` are argument receivers
|
105
|
+
# becomes `-a -b nil -c ARGUMENT`
|
106
|
+
# 3. `-acb ARGUMENT` where only `c` receives the argument
|
107
|
+
# becomes `-a -c nil -b ARGUMENT`
|
108
|
+
# 4. `-c --some-option ARGUMENT` where both options receive argument,
|
109
|
+
# becomes `-c nil --some-option ARGUMENT`
|
110
|
+
# 5. `-c --some-option -d ARGUMENT` where both options receive argument,
|
111
|
+
# becomes `-c nil --some-option nil -d ARGUMENT`
|
112
|
+
# 6. `-cd ARGUMENT` where `c` default is `"yeah"`,
|
113
|
+
# becomes `-c yeah -d ARGUMENT`
|
104
114
|
# @param argv [Array<String>]
|
105
115
|
# @param options [Hash] the defined `RakeCommander::Option` to re-arrange `argv` with.
|
106
116
|
# @return [Array<String>] the re-arranged `argv`
|
107
117
|
def argv_pre_parsed(argv = ARGV, options:)
|
108
|
-
pre_parsed
|
118
|
+
pre_parsed = explicit_argument_options(argv, options)
|
109
119
|
compact_short = ''
|
120
|
+
|
110
121
|
pre_parsed.each_with_object([]) do |(opt_ref, args), out|
|
111
122
|
next out.push(*args) unless opt_ref.is_a?(Symbol)
|
123
|
+
|
112
124
|
is_short = opt_ref.to_s.length == 1
|
113
125
|
next compact_short << opt_ref.to_s if is_short && args.empty?
|
126
|
+
|
114
127
|
out.push("-#{compact_short}") unless compact_short.empty?
|
115
128
|
compact_short = ''
|
116
129
|
opt_str = is_short ? "-#{opt_ref}" : name_hyphen(opt_ref)
|
@@ -139,17 +152,24 @@ class RakeCommander
|
|
139
152
|
private
|
140
153
|
|
141
154
|
# @example the output is actually a Hash, keyed by the Symbol of the option (short or name)
|
142
|
-
# 1. `-abc ARGUMENT` where only `c` receives the argument
|
143
|
-
#
|
144
|
-
# 2. `-
|
145
|
-
#
|
146
|
-
#
|
147
|
-
#
|
155
|
+
# 1. `-abc ARGUMENT` where only `c` receives the argument
|
156
|
+
# becomes `:a :b :c ARGUMENT`
|
157
|
+
# 2. `-abc ARGUMENT` where `b` and `c` are argument receivers
|
158
|
+
# becomes `:a :b nil :c ARGUMENT`
|
159
|
+
# 3. `-acb ARGUMENT` where only `c` receives the argument
|
160
|
+
# becomes `:a :c nil :b ARGUMENT`
|
161
|
+
# 4. `-c --some-option ARGUMENT` where both options receive argument,
|
162
|
+
# becomes `:c nil :some_option ARGUMENT`
|
163
|
+
# 5. `-c --some-option -d ARGUMENT` where first two options receive argument,
|
164
|
+
# becomes `:c nil :some_option nil :d ARGUMENT`
|
165
|
+
# 6. `-cd ARGUMENT` where `c` default is `"yeah"`,
|
166
|
+
# becomes `:c yeah :d ARGUMENT`
|
148
167
|
# @return [Hash<Symbol, Array>]
|
149
168
|
def explicit_argument_options(argv, options)
|
150
169
|
decoupled = decluster_shorts_n_names_to_sym(argv)
|
151
170
|
grouped = group_symbols_with_strings(decoupled)
|
152
171
|
normalized = insert_missing_argument_to_groups(grouped, options)
|
172
|
+
|
153
173
|
normalized.each_with_object({}) do |group, pre_parsed|
|
154
174
|
opt_ref = group.first.is_a?(Symbol)? group.shift : nil
|
155
175
|
pre_parsed[opt_ref] = group
|
@@ -163,14 +183,17 @@ class RakeCommander
|
|
163
183
|
# @param groups [@see #pair_symbols_with_strings]
|
164
184
|
def insert_missing_argument_to_groups(groups, options)
|
165
185
|
groups.each do |group|
|
166
|
-
args
|
186
|
+
args = group.dup
|
167
187
|
opt_ref = args.shift
|
188
|
+
|
168
189
|
next unless args.empty?
|
169
190
|
next unless opt_ref.is_a?(Symbol)
|
170
|
-
next unless opt = _retrieve_option_ref(opt_ref, options)
|
191
|
+
next unless (opt = _retrieve_option_ref(opt_ref, options))
|
171
192
|
next unless opt.argument?
|
193
|
+
|
172
194
|
next group.push(opt.default) if opt.default?
|
173
|
-
next
|
195
|
+
next unless opt.argument_required?
|
196
|
+
|
174
197
|
group.push(nil)
|
175
198
|
end
|
176
199
|
end
|
@@ -180,11 +203,13 @@ class RakeCommander
|
|
180
203
|
# @return [RakeCommander::Option, NilClass]
|
181
204
|
def _retrieve_option_ref(opt_ref, options)
|
182
205
|
opt = options[opt_ref]
|
183
|
-
|
184
|
-
return
|
185
|
-
return
|
186
|
-
return
|
187
|
-
return
|
206
|
+
|
207
|
+
return opt if opt
|
208
|
+
return unless (match = opt_ref.to_s.match(BOOLEAN_ARGUMENT))
|
209
|
+
return unless (opt_ref = match[:option])
|
210
|
+
return unless (opt = options[opt_ref.to_sym])
|
211
|
+
return unless opt.boolean_name?
|
212
|
+
|
188
213
|
opt
|
189
214
|
end
|
190
215
|
|
@@ -193,6 +218,7 @@ class RakeCommander
|
|
193
218
|
def group_symbols_with_strings(argv)
|
194
219
|
[].tap do |out|
|
195
220
|
curr_ary = nil
|
221
|
+
|
196
222
|
argv.each do |arg|
|
197
223
|
if arg.is_a?(Symbol)
|
198
224
|
out << (curr_ary = [arg])
|
@@ -5,12 +5,39 @@ class RakeCommander
|
|
5
5
|
|
6
6
|
private
|
7
7
|
|
8
|
+
def fetch_desc!(args)
|
9
|
+
descs = args.dup.select do |arg|
|
10
|
+
arg.is_a?(String).tap do |is_string|
|
11
|
+
next unless is_string
|
12
|
+
|
13
|
+
args.delete(arg)
|
14
|
+
end
|
15
|
+
end.uniq
|
16
|
+
|
17
|
+
joined_lines(*descs)
|
18
|
+
end
|
19
|
+
|
8
20
|
def string_to_lines(str, max: DESC_MAX_LENGTH)
|
9
21
|
str.scan(liner_regex(max)).map(&:strip)
|
10
22
|
end
|
11
23
|
|
12
24
|
def liner_regex(len = DESC_MAX_LENGTH)
|
13
|
-
|
25
|
+
/[^\n\r]{0,#{len}}[^ ](?:\s|$)/mi
|
26
|
+
end
|
27
|
+
|
28
|
+
def joined_lines(*lines, join: "\n")
|
29
|
+
lines = lines.compact.map(&:strip).reject(&:empty?)
|
30
|
+
return unless lines.count.positive?
|
31
|
+
|
32
|
+
first = lines.first
|
33
|
+
first = "#{first}." unless first.end_with?('.')
|
34
|
+
|
35
|
+
(lines[1..] || []).reduce(first) do |mem, line|
|
36
|
+
mem = "#{mem}." unless mem.end_with?('.')
|
37
|
+
line = "#{line}." unless line.end_with?('.')
|
38
|
+
|
39
|
+
"#{mem}#{join}#{line}"
|
40
|
+
end
|
14
41
|
end
|
15
42
|
end
|
16
43
|
end
|
@@ -4,7 +4,7 @@ class RakeCommander
|
|
4
4
|
# Base error class that does a rely between OptionParser and RakeCommander errors
|
5
5
|
class Base < RakeCommander::Base::CustomError
|
6
6
|
extend RakeCommander::Options::Name
|
7
|
-
OPTION_REGEX = /(?:argument|option): (?<option>.+)/i
|
7
|
+
OPTION_REGEX = /(?:argument|option): (?<option>.+)/i
|
8
8
|
|
9
9
|
class << self
|
10
10
|
# Helper to check if `error` is this class or any children class
|
@@ -20,14 +20,17 @@ class RakeCommander
|
|
20
20
|
def option_regex(value = :not_used)
|
21
21
|
@option_regex ||= OPTION_REGEX
|
22
22
|
return @option_regex if value == :not_used
|
23
|
+
|
23
24
|
@option_regex = value
|
24
25
|
end
|
25
26
|
|
26
27
|
# Identifies the option `Symbol` (short or name) for a given message
|
27
28
|
def option_sym(message)
|
28
|
-
return
|
29
|
+
return unless (match = message.match(option_regex))
|
30
|
+
|
29
31
|
option = match[:option]
|
30
32
|
return name_word_sym(option) if option.length > 1
|
33
|
+
|
31
34
|
short_sym(option)
|
32
35
|
end
|
33
36
|
end
|
@@ -59,6 +62,7 @@ class RakeCommander
|
|
59
62
|
|
60
63
|
def from_desc
|
61
64
|
return '' unless from
|
65
|
+
|
62
66
|
if from.respond_to?(:name)
|
63
67
|
"(#{from.name}) "
|
64
68
|
elsif from.respond_to?(:to_s)
|
@@ -4,7 +4,8 @@ class RakeCommander
|
|
4
4
|
module Handling
|
5
5
|
class << self
|
6
6
|
def included(base)
|
7
|
-
super
|
7
|
+
super
|
8
|
+
|
8
9
|
base.extend RakeCommander::Base::ClassHelpers
|
9
10
|
base.extend RakeCommander::Base::ClassInheritable
|
10
11
|
base.extend ClassMethods
|
@@ -40,6 +41,7 @@ class RakeCommander
|
|
40
41
|
# @return [Boolean] whether this error is enabled.
|
41
42
|
def error_on_options(action = :not_used, error: RakeCommander::Options::Error::Base, &handler)
|
42
43
|
RakeCommander::Options::Error::Base.require_argument!(error, :error, accept_children: true)
|
44
|
+
|
43
45
|
@options_latest_error = nil
|
44
46
|
@error_on_options ||= {}
|
45
47
|
@error_on_options[error] = action if action != :not_used
|
@@ -82,9 +84,10 @@ class RakeCommander
|
|
82
84
|
action = error_on_options(error: eklass)
|
83
85
|
|
84
86
|
# here is where we ignore the handler (when !action == `true`)
|
85
|
-
raise unless !action || handler = error_on_options_handler(eklass)
|
87
|
+
raise unless !action || (handler = error_on_options_handler(eklass))
|
86
88
|
raise if handler&.call(e, argv, results, leftovers)
|
87
89
|
return leftovers if action == :continue
|
90
|
+
|
88
91
|
puts e.message
|
89
92
|
# https://stackoverflow.com/a/23340693/4352306
|
90
93
|
exit 1
|
@@ -95,7 +98,13 @@ class RakeCommander
|
|
95
98
|
def error_on_options_handler(error = :not_used, &handler)
|
96
99
|
@error_on_options_handler ||= {}
|
97
100
|
return @error_on_options_handler if error == :not_used
|
98
|
-
|
101
|
+
|
102
|
+
RakeCommander::Options::Error::Base.require_argument!(
|
103
|
+
error,
|
104
|
+
:error,
|
105
|
+
accept_children: true
|
106
|
+
)
|
107
|
+
|
99
108
|
@error_on_options_handler[error] = handler if block_given?
|
100
109
|
@error_on_options_handler[error]
|
101
110
|
end
|
@@ -2,12 +2,13 @@ class RakeCommander
|
|
2
2
|
module Options
|
3
3
|
module Error
|
4
4
|
class InvalidArgument < RakeCommander::Options::Error::Base
|
5
|
-
option_regex(/invalid argument: (?<option>.+)/i
|
5
|
+
option_regex(/invalid argument: (?<option>.+)/i)
|
6
6
|
|
7
7
|
private
|
8
8
|
|
9
9
|
def to_message(value)
|
10
|
-
return super unless opt = option
|
10
|
+
return super unless (opt = option)
|
11
|
+
|
11
12
|
case value
|
12
13
|
when OptionParser::InvalidArgument
|
13
14
|
super("invalid option argument: #{opt.name_hyphen} (#{opt.short_hyphen})")
|
@@ -3,7 +3,7 @@ class RakeCommander
|
|
3
3
|
module Error
|
4
4
|
# Relates to options with missing required argument (when there's no `default` value)
|
5
5
|
class MissingArgument < RakeCommander::Options::Error::Base
|
6
|
-
option_regex(/missing(?: required|) argument: (?<option>.+)/i
|
6
|
+
option_regex(/missing(?: required|) argument: (?<option>.+)/i)
|
7
7
|
end
|
8
8
|
end
|
9
9
|
end
|
@@ -11,7 +11,7 @@ class RakeCommander
|
|
11
11
|
module Error
|
12
12
|
class << self
|
13
13
|
def included(base)
|
14
|
-
super
|
14
|
+
super
|
15
15
|
base.send :include, RakeCommander::Options::Error::Handling
|
16
16
|
base.extend ClassMethods
|
17
17
|
end
|
@@ -22,7 +22,7 @@ class RakeCommander
|
|
22
22
|
# @see RakeCommander::Options::Result
|
23
23
|
def parse_options(argv = ARGV, results: {}, leftovers: [], &block)
|
24
24
|
with_error_handling(argv, results, leftovers) do
|
25
|
-
super.tap do
|
25
|
+
super.tap do
|
26
26
|
check_on_leftovers(leftovers)
|
27
27
|
check_required_presence(results)
|
28
28
|
end
|
@@ -37,11 +37,21 @@ class RakeCommander
|
|
37
37
|
raise eklass.new(from: self, option: opt), msg, cause: nil
|
38
38
|
rescue OptionParser::InvalidArgument => e
|
39
39
|
eklass = RakeCommander::Options::Error::InvalidArgument
|
40
|
+
src_e = nil
|
41
|
+
msg = nil
|
40
42
|
opt = error_option(e, eklass)
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
43
|
+
|
44
|
+
if opt&.enum?
|
45
|
+
msg = "argument in option #{opt.name_hyphen} (#{opt.short_hyphen}) "
|
46
|
+
msg << "should be any of [#{opt.enum_options.join(' | ')}]"
|
47
|
+
elsif opt&.argument_required?
|
48
|
+
eklass = RakeCommander::Options::Error::MissingArgument
|
49
|
+
msg = "missing required argument in option: #{opt.name_hyphen} (#{opt.short_hyphen})"
|
50
|
+
else
|
51
|
+
src_e = e
|
52
|
+
end
|
53
|
+
|
54
|
+
raise eklass.new(src_e, from: self, option: opt), msg, cause: nil
|
45
55
|
end
|
46
56
|
end
|
47
57
|
|
@@ -53,7 +63,8 @@ class RakeCommander
|
|
53
63
|
# @param eklass [RakeCommander::Options::Error:Base::Class] the error class to retrive the option key
|
54
64
|
# @return [RakeCommander::Option, NilClass]
|
55
65
|
def error_option(err, eklass)
|
56
|
-
return false unless option_sym = eklass.option_sym(err.message)
|
66
|
+
return false unless (option_sym = eklass.option_sym(err.message))
|
67
|
+
|
57
68
|
options_hash(with_implicit: true)[option_sym]
|
58
69
|
end
|
59
70
|
|
@@ -65,6 +76,7 @@ class RakeCommander
|
|
65
76
|
# @return [Hash] the results (same object)
|
66
77
|
def check_on_leftovers(leftovers)
|
67
78
|
return if leftovers.empty?
|
79
|
+
|
68
80
|
eklass = RakeCommander::Options::Error::UnknownArgument
|
69
81
|
raise eklass.new(leftovers, from: self)
|
70
82
|
end
|