rake-commander 0.4.0 → 0.4.2
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/CHANGELOG.md +21 -1
- 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/class_inheritable.rb +9 -2
- data/lib/rake-commander/base/custom_error.rb +3 -3
- data/lib/rake-commander/base/object_helpers.rb +6 -1
- data/lib/rake-commander/base.rb +2 -1
- data/lib/rake-commander/option.rb +81 -36
- 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
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5593c671006f7e7e95feee9f6b173e0d9df9ce37e39c965b12a9c4c8970d7a06
|
4
|
+
data.tar.gz: f64990b6d2ef3eef976ca3b77cf712b5dfaa038677ca796ef59267c522c3a878
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4e6e9f6f3a57344ffa8d730d0025977f541a38881559899b0944f1c7658fd306b03f8e5942eb84a114368075597c4c813fc82def9e692ffba56070d844146bd4
|
7
|
+
data.tar.gz: 911d733c2665c9cf708fe1f65c11131973b1693321b3404cf1cf403f79a120ef6f6bbb9db79089d0b7bcaa4e9b1d6bfdc628762c0670334273e8f5d918dd636c
|
data/CHANGELOG.md
CHANGED
@@ -31,7 +31,7 @@ All notable changes to this project will be documented in this file.
|
|
31
31
|
- Example: `on_options(:t, :s, present: true) {|options| do-stuff}` <- block to be called only when the option `:t` and `:s` are both present in the parsed `options` result.
|
32
32
|
- Once this has been done, think about it being a hash-alike object with methods for the option names (i.e. `options.debug?`)
|
33
33
|
|
34
|
-
## [0.4.
|
34
|
+
## [0.4.3] - 2025-02-xx
|
35
35
|
|
36
36
|
### Added
|
37
37
|
|
@@ -39,6 +39,26 @@ All notable changes to this project will be documented in this file.
|
|
39
39
|
|
40
40
|
### Changed
|
41
41
|
|
42
|
+
## [0.4.2] - 2025-02-25
|
43
|
+
|
44
|
+
### Fixed
|
45
|
+
|
46
|
+
- `Option#type_coercion` should be dupped on inheritance.
|
47
|
+
|
48
|
+
## [0.4.1] - 2025-02-20
|
49
|
+
|
50
|
+
### Added
|
51
|
+
|
52
|
+
- Predefined values cohertion (i.e. `Enum`)
|
53
|
+
|
54
|
+
### Fixed
|
55
|
+
|
56
|
+
- Description: break lines should be respected.
|
57
|
+
|
58
|
+
### Changed
|
59
|
+
|
60
|
+
- Allow multiple `desc` declarations to be aligned with `OptsParser` behaviour.
|
61
|
+
|
42
62
|
## [0.4.0] - 2023-08-01
|
43
63
|
|
44
64
|
### Changed
|
@@ -8,11 +8,13 @@ class RakeCommander::Custom::BasicExample < RakeCommander
|
|
8
8
|
option '-w', :show_time, TrueClass, desc: 'Displays the local time'
|
9
9
|
option :z, '--timezone', TrueClass, default: false, required: true
|
10
10
|
option :o, '--hello NAME', String, desc: 'It greets.'
|
11
|
-
option '-s', '--say [SOMETHING]', "It says 'something'",
|
11
|
+
option '-s', '--say [SOMETHING]', "It says 'something'", 'But it comes with default',
|
12
|
+
default: %q(I don't know what to "say"...)
|
12
13
|
option :d, '--folder NAME', default: '.', desc: 'Source local folder', required: true
|
13
14
|
option '-e', :'--enviro ENV', 'The target environment to run this task', required: true
|
14
15
|
option :v, :debug, TrueClass, 'Shows the parsed options'
|
15
16
|
option :V, '[no-]verbose', 'Verbosity', TrueClass
|
17
|
+
option :l, '--colour COLOUR', "Choose a colour", type: %i[red yellow green blue]
|
16
18
|
#option :f, :folder, required: false, reopen: true
|
17
19
|
|
18
20
|
def task(*_args)
|
@@ -10,8 +10,9 @@ class RakeCommander::Custom::ChainerPlus < RakeCommander::Custom::Chainer
|
|
10
10
|
# Update option description
|
11
11
|
option_reopen :chain, desc: "Calls: '< rake|raked > #{TARGET_TASK} task'"
|
12
12
|
# Extend with new options
|
13
|
-
option
|
14
|
-
|
13
|
+
option \
|
14
|
+
:e, '--exit-on-error', TrueClass,
|
15
|
+
desc: "Whether #{TARGET_TASK} should just exit on 'missing argument' error (or raise an exception)"
|
15
16
|
option :o, '--hello NAME', String, desc: 'It greets.'
|
16
17
|
|
17
18
|
# Make it default to `exit 1` when there are errors
|
@@ -50,17 +50,20 @@ class RakeCommander
|
|
50
50
|
# @return [Boolean] determines if a given namespace is entitled for autoloading
|
51
51
|
def autoload_class?(constant)
|
52
52
|
constants = constant.to_s.split("::").compact
|
53
|
-
autoload
|
53
|
+
autoload = true
|
54
|
+
|
54
55
|
unless autoloaded_namespaces(:include).empty?
|
55
56
|
autoload = autoloaded_namespaces(:include).any? do |ns|
|
56
57
|
ns.to_s.split("::").compact.zip(constants).all? {|(r, c)| r == c}
|
57
58
|
end
|
58
59
|
end
|
60
|
+
|
59
61
|
unless autoloaded_namespaces(:ignore).empty?
|
60
62
|
autoload &&= autoloaded_namespaces(:ignore).none? do |ns|
|
61
63
|
ns.to_s.split("::").compact.zip(constants).all? {|(r, c)| r == c}
|
62
64
|
end
|
63
65
|
end
|
66
|
+
|
64
67
|
autoload
|
65
68
|
end
|
66
69
|
|
@@ -90,8 +93,10 @@ class RakeCommander
|
|
90
93
|
# Children classes of `autoloader_class` that have not been created an instance of.
|
91
94
|
def unloaded_children
|
92
95
|
return [] unless autoloaded_class
|
96
|
+
|
93
97
|
new_detected = new_classes
|
94
98
|
known_class!(*new_detected)
|
99
|
+
|
95
100
|
descendants(parent_class: autoloaded_class, scope: new_detected).select do |child_class|
|
96
101
|
!autoloaded_children.include?(child_class) && \
|
97
102
|
!excluded_children.include?(child_class) && \
|
@@ -105,9 +110,12 @@ class RakeCommander
|
|
105
110
|
# @return [Boolean] `true` if there were children loaded, `false` otherwise.
|
106
111
|
def autoload_children(object = nil)
|
107
112
|
return false if !autoloaded_class || @loading_children
|
113
|
+
|
108
114
|
pending_children = unloaded_children
|
109
115
|
return false if pending_children.empty?
|
116
|
+
|
110
117
|
@loading_children = true
|
118
|
+
|
111
119
|
pending_children.each do |klass|
|
112
120
|
exclude = false
|
113
121
|
child = object ? klass.new(object) : klass.new
|
@@ -119,6 +127,7 @@ class RakeCommander
|
|
119
127
|
ensure
|
120
128
|
autoloaded_children.push(klass) unless exclude
|
121
129
|
end
|
130
|
+
|
122
131
|
@loading_children = false
|
123
132
|
true
|
124
133
|
end
|
@@ -15,11 +15,14 @@ class RakeCommander
|
|
15
15
|
attrs = attrs.map(&:to_sym)
|
16
16
|
inheritable_class_var(*attrs, deep_dup: deep_dup, &block)
|
17
17
|
return unless add_accessors
|
18
|
+
|
18
19
|
attrs.each do |attr|
|
19
20
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
20
|
-
class << self; attr_accessor
|
21
|
+
# class << self; attr_accessor :class_var; end
|
22
|
+
class << self; attr_accessor :#{attr}; end
|
21
23
|
RUBY
|
22
24
|
end
|
25
|
+
|
23
26
|
self
|
24
27
|
end
|
25
28
|
|
@@ -35,7 +38,8 @@ class RakeCommander
|
|
35
38
|
# that should NOT be inheritable.
|
36
39
|
def attr_not_inheritable(*attrs)
|
37
40
|
attrs.each do |attr|
|
38
|
-
next unless method = inheritable_class_var_method(attr)
|
41
|
+
next unless (method = inheritable_class_var_method(attr))
|
42
|
+
|
39
43
|
inheritable_class_var[method].delete(attr)
|
40
44
|
end
|
41
45
|
self
|
@@ -86,6 +90,7 @@ class RakeCommander
|
|
86
90
|
}.tap do |hash|
|
87
91
|
hash[:deep_dup][:inheritable_class_var] = :default
|
88
92
|
end
|
93
|
+
|
89
94
|
@inheritable_class_var.tap do |_methods|
|
90
95
|
vars.each {|var| inheritable_class_var_add(var, deep_dup: deep_dup, &block)}
|
91
96
|
end
|
@@ -97,7 +102,9 @@ class RakeCommander
|
|
97
102
|
# Remove previous definition if present
|
98
103
|
attr_not_inheritable(var)
|
99
104
|
method = deep_dup || block ? :deep_dup : :mirror
|
105
|
+
|
100
106
|
inheritable_class_var[method][var] = block || :default
|
107
|
+
|
101
108
|
self
|
102
109
|
end
|
103
110
|
|
@@ -11,6 +11,7 @@ class RakeCommander
|
|
11
11
|
# just return @message
|
12
12
|
def to_s
|
13
13
|
return @message if @message
|
14
|
+
|
14
15
|
unclassed(super)
|
15
16
|
end
|
16
17
|
|
@@ -18,6 +19,7 @@ class RakeCommander
|
|
18
19
|
# just return @message
|
19
20
|
def message
|
20
21
|
return @message if @message
|
22
|
+
|
21
23
|
to_message(unclassed(super))
|
22
24
|
end
|
23
25
|
|
@@ -30,9 +32,7 @@ class RakeCommander
|
|
30
32
|
case value
|
31
33
|
when StandardError
|
32
34
|
to_message(value.message)
|
33
|
-
when String
|
34
|
-
value
|
35
|
-
when NilClass
|
35
|
+
when String, NilClass
|
36
36
|
value
|
37
37
|
else
|
38
38
|
raise ArgumentError, "Expecting String, StandardError or NilClass. Given: #{value.class}"
|
@@ -20,21 +20,26 @@ class RakeCommander
|
|
20
20
|
return yield(value) if block_given?
|
21
21
|
return value unless dup_objects
|
22
22
|
return value.deep_dup if value.respond_to?(:deep_dup)
|
23
|
+
|
23
24
|
value.dup
|
24
25
|
end
|
25
26
|
|
26
27
|
# Custom Hash#deep_dup for rake commander
|
27
28
|
def custom_hash_deep_dup(original, dup_objects: true, &dup_block)
|
28
29
|
raise ArgumentError, "Expecting Hash. Given: #{original.class}" unless original.is_a?(Hash)
|
30
|
+
|
29
31
|
hash = original.dup
|
32
|
+
|
30
33
|
original.each_pair do |key, value|
|
31
34
|
unless key.frozen? && key.is_a?(::String)
|
32
35
|
hash.delete(key)
|
33
36
|
key = custom_deep_dup(key, dup_objects: dup_objects, &dup_block) if dup_objects
|
34
37
|
end
|
35
|
-
|
38
|
+
|
39
|
+
value = custom_deep_dup(value, dup_objects: dup_objects, &dup_block) if dup_objects
|
36
40
|
hash[key] = value
|
37
41
|
end
|
42
|
+
|
38
43
|
hash
|
39
44
|
end
|
40
45
|
end
|
data/lib/rake-commander/base.rb
CHANGED
@@ -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|
|
132
|
-
|
133
|
-
|
134
|
-
kargs.merge!(
|
135
|
-
kargs.merge!(
|
136
|
-
kargs.merge!(
|
153
|
+
configure_other
|
154
|
+
|
155
|
+
kargs.merge!(short: short.dup.freeze) if short
|
156
|
+
kargs.merge!(name: name_full.dup.freeze) if name_full
|
157
|
+
kargs.merge!(desc: @desc.dup) if @desc
|
158
|
+
kargs.merge!(default: @default.dup) if default?
|
159
|
+
kargs.merge!(type: dupped_type) 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,52 @@ 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
|
280
|
+
end
|
281
|
+
|
282
|
+
def fetch_desc_from_other(original = nil)
|
283
|
+
joined_lines(original, fetch_desc!(other_args))
|
243
284
|
end
|
244
285
|
|
245
|
-
def
|
246
|
-
return
|
247
|
-
|
248
|
-
|
286
|
+
def dupped_type
|
287
|
+
return @type_coercion if @type_coercion.is_a?(Class)
|
288
|
+
return @type_coercion unless @type_coercion.is_a?(Array)
|
289
|
+
|
290
|
+
@type_coercion.map do |value|
|
291
|
+
next value if value.is_a?(Class)
|
292
|
+
next value unless value.respond_to?(:dup)
|
293
|
+
|
294
|
+
value.dup
|
249
295
|
end
|
250
|
-
value
|
251
296
|
end
|
252
297
|
end
|
253
298
|
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])
|