consoler 1.0.1 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/workflows/tests.yml +34 -0
- data/.rubocop.yml +45 -0
- data/.yardopts +2 -0
- data/README.md +264 -11
- data/consoler.gemspec +4 -3
- data/lib/consoler/application.rb +112 -27
- data/lib/consoler/arguments.rb +0 -1
- data/lib/consoler/command.rb +0 -1
- data/lib/consoler/matcher.rb +157 -63
- data/lib/consoler/option.rb +113 -27
- data/lib/consoler/options.rb +40 -17
- data/lib/consoler/version.rb +1 -2
- metadata +21 -20
- data/.travis.yml +0 -11
data/lib/consoler/arguments.rb
CHANGED
data/lib/consoler/command.rb
CHANGED
data/lib/consoler/matcher.rb
CHANGED
@@ -1,12 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Consoler
|
4
|
-
|
5
4
|
# Argument/Options matcher
|
6
5
|
#
|
7
6
|
# Given a list of arguments and a list option try to match them
|
8
7
|
class Matcher
|
9
|
-
|
10
8
|
# Create a matcher
|
11
9
|
#
|
12
10
|
# @param [Consoler::Arguments] arguments List of arguments
|
@@ -26,13 +24,15 @@ module Consoler
|
|
26
24
|
def match
|
27
25
|
parse_options = true
|
28
26
|
|
29
|
-
|
30
|
-
unless parse_options
|
27
|
+
_loop_args do |arg|
|
28
|
+
unless parse_options
|
31
29
|
@argument_values.push arg
|
32
30
|
next
|
33
31
|
end
|
34
32
|
|
35
|
-
|
33
|
+
# when "argument" is --, then stop parsing the rest of the arguments
|
34
|
+
# and treat the rest as regular arguments
|
35
|
+
if arg == '--'
|
36
36
|
parse_options = false
|
37
37
|
next
|
38
38
|
end
|
@@ -47,126 +47,189 @@ module Consoler
|
|
47
47
|
remaining = _match_arguments
|
48
48
|
_fill_defaults
|
49
49
|
|
50
|
-
if @matched_options.size == @options.size
|
50
|
+
if @matched_options.size == @options.size
|
51
51
|
@matched_options['remaining'] = remaining
|
52
|
+
|
53
|
+
# make sure all aliases are also filled
|
54
|
+
@options.each do |option|
|
55
|
+
option.aliases.each do |alias_|
|
56
|
+
@matched_options[alias_.name] = @matched_options[option.name]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
52
60
|
return @matched_options
|
53
61
|
end
|
54
62
|
|
55
|
-
|
63
|
+
nil
|
56
64
|
end
|
57
65
|
|
58
66
|
private
|
59
67
|
|
68
|
+
# Analyze a single argument
|
69
|
+
#
|
70
|
+
# @param [String] arg Single argument
|
71
|
+
# @return [true, nil] true on success, nil on failure
|
60
72
|
def _analyze(arg)
|
61
73
|
is_long = false
|
62
74
|
is_short = false
|
63
75
|
name = nil
|
64
76
|
|
65
|
-
if arg[0..1] == '--'
|
77
|
+
if arg[0..1] == '--'
|
66
78
|
is_long = true
|
67
79
|
name = arg[2..-1]
|
68
|
-
elsif arg[0] == '-'
|
80
|
+
elsif arg[0] == '-'
|
69
81
|
is_short = true
|
70
82
|
name = arg[1..-1]
|
71
83
|
end
|
72
84
|
|
73
|
-
|
85
|
+
# arg is not a long/short option, add to arguments values
|
86
|
+
unless is_long || is_short
|
74
87
|
@argument_values.push arg
|
75
88
|
return true
|
76
89
|
end
|
77
90
|
|
78
|
-
unless name.nil?
|
79
|
-
|
91
|
+
unless name.nil?
|
92
|
+
# get the name of the option, short options use the first character
|
93
|
+
option_name = if is_short
|
80
94
|
name[0]
|
81
95
|
else
|
82
96
|
name
|
83
97
|
end
|
84
98
|
|
85
|
-
option = @options.
|
99
|
+
option, matched = @options.get_with_alias option_name
|
86
100
|
|
101
|
+
# no option by this name in options
|
87
102
|
return nil if option.nil?
|
88
103
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
if needs_long and not is_long then
|
104
|
+
# see if the type if right, short or long
|
105
|
+
if matched.is_long && !is_long
|
93
106
|
return nil
|
94
|
-
elsif
|
107
|
+
elsif matched.is_short && !is_short
|
95
108
|
return nil
|
96
109
|
end
|
97
110
|
|
98
|
-
if is_long
|
99
|
-
if option.is_value
|
100
|
-
|
101
|
-
|
102
|
-
|
111
|
+
if is_long
|
112
|
+
if option.is_value
|
113
|
+
# is_value needs a next argument for its value
|
114
|
+
return nil if _peek_next.nil?
|
115
|
+
|
116
|
+
@matched_options[option.name] = _peek_next
|
117
|
+
_skip_next
|
103
118
|
else
|
104
|
-
|
119
|
+
option_value! option
|
105
120
|
end
|
106
121
|
end
|
107
122
|
|
108
|
-
if is_short
|
109
|
-
if name.size == 1
|
110
|
-
|
111
|
-
|
112
|
-
|
123
|
+
if is_short
|
124
|
+
if name.size == 1 && option.is_value
|
125
|
+
# is_value needs a next argument for its value
|
126
|
+
return nil if _peek_next.nil?
|
127
|
+
|
128
|
+
@matched_options[option.name] = _peek_next
|
129
|
+
_skip_next
|
113
130
|
else
|
131
|
+
# for every character (short option) increment the option value
|
114
132
|
name.split('').each do |n|
|
115
|
-
|
116
|
-
|
117
|
-
end
|
133
|
+
short_option = @options.get n
|
134
|
+
return nil if short_option.nil?
|
118
135
|
|
119
|
-
|
136
|
+
option_value! short_option
|
120
137
|
end
|
121
138
|
end
|
122
139
|
end
|
123
140
|
end
|
124
141
|
|
125
|
-
|
142
|
+
true
|
126
143
|
end
|
127
144
|
|
128
|
-
|
129
|
-
|
130
|
-
|
145
|
+
# Set the value of an option
|
146
|
+
#
|
147
|
+
# Long or short option needed
|
148
|
+
#
|
149
|
+
# @param [Consoler::Option]
|
150
|
+
def option_value!(option)
|
151
|
+
if option.is_short
|
152
|
+
if @matched_options[option.name].nil?
|
153
|
+
@matched_options[option.name] = 0
|
154
|
+
end
|
131
155
|
|
132
|
-
|
133
|
-
|
156
|
+
@matched_options[option.name] += 1
|
157
|
+
else
|
158
|
+
@matched_options[option.name] = true
|
159
|
+
end
|
134
160
|
end
|
135
161
|
|
136
|
-
|
162
|
+
# Loop through the arguments
|
163
|
+
#
|
164
|
+
# @yield [String] An argument
|
165
|
+
# @return [Consoler::Matcher]
|
166
|
+
def _loop_args
|
137
167
|
@index = 0
|
138
168
|
size = @arguments.args.size
|
139
169
|
|
140
|
-
|
141
|
-
|
170
|
+
# use an incrementing index, to be able to peek to the next in the list
|
171
|
+
# and to skip an item
|
172
|
+
while @index < size
|
173
|
+
yield @arguments.args[@index]
|
142
174
|
|
143
|
-
|
175
|
+
_skip_next
|
144
176
|
end
|
177
|
+
|
178
|
+
self
|
179
|
+
end
|
180
|
+
|
181
|
+
# Peek at the next argument
|
182
|
+
#
|
183
|
+
# Only useful inside {Consoler::Matcher#_loop_args}
|
184
|
+
#
|
185
|
+
# @return [String, nil]
|
186
|
+
def _peek_next
|
187
|
+
@arguments.args[@index + 1]
|
145
188
|
end
|
146
189
|
|
147
|
-
|
190
|
+
# Skip to the next argument
|
191
|
+
#
|
192
|
+
# Useful if you use a peeked argument
|
193
|
+
#
|
194
|
+
# @return [nil]
|
195
|
+
# @return [Consoler::Matcher]
|
196
|
+
def _skip_next
|
148
197
|
@index += 1
|
198
|
+
|
199
|
+
self
|
149
200
|
end
|
150
201
|
|
202
|
+
# Match arguments to defined option arguments
|
203
|
+
#
|
204
|
+
# @return [Array<String>, nil] The remaining args,
|
205
|
+
# or <tt>nil</tt> if there are not enough arguments
|
151
206
|
def _match_arguments
|
152
207
|
@optionals_before = {}
|
153
208
|
@optionals_before_has_remaining = false
|
154
209
|
|
210
|
+
total_argument_values = @argument_values.size
|
155
211
|
argument_values_index = 0
|
156
212
|
|
157
213
|
_match_arguments_optionals_before
|
158
214
|
|
159
215
|
@optionals_before.each do |mandatory_arg_name, optionals|
|
216
|
+
# fill the optional argument option with a value if there are enough
|
217
|
+
# arguments supplied (info available from optionals map)
|
160
218
|
optionals.each do |_, optional|
|
161
219
|
optional.each do |before|
|
162
|
-
if before[:included]
|
220
|
+
if before[:included]
|
221
|
+
return nil if argument_values_index >= total_argument_values
|
222
|
+
|
163
223
|
@matched_options[before[:name]] = @argument_values[argument_values_index]
|
164
224
|
argument_values_index += 1
|
165
225
|
end
|
166
226
|
end
|
167
227
|
end
|
168
228
|
|
169
|
-
if
|
229
|
+
# only fill mandatory argument if its not the :REMAINING key
|
230
|
+
if mandatory_arg_name != :REMAINING
|
231
|
+
return nil if argument_values_index >= total_argument_values
|
232
|
+
|
170
233
|
@matched_options[mandatory_arg_name] = @argument_values[argument_values_index]
|
171
234
|
argument_values_index += 1
|
172
235
|
end
|
@@ -174,7 +237,8 @@ module Consoler
|
|
174
237
|
|
175
238
|
remaining = []
|
176
239
|
|
177
|
-
|
240
|
+
# left over arguments
|
241
|
+
while argument_values_index < @argument_values.size
|
178
242
|
remaining.push @argument_values[argument_values_index]
|
179
243
|
argument_values_index += 1
|
180
244
|
end
|
@@ -182,78 +246,108 @@ module Consoler
|
|
182
246
|
remaining
|
183
247
|
end
|
184
248
|
|
249
|
+
# Create a map of all optionals and before which mandatory argument they appear
|
250
|
+
#
|
251
|
+
# @return [Consoler::Matcher]
|
185
252
|
def _match_arguments_optionals_before
|
186
253
|
@optionals_before = {}
|
187
254
|
tracker = {}
|
188
255
|
|
189
|
-
@options.each do |option,
|
256
|
+
@options.each do |option, _key|
|
190
257
|
next unless option.is_argument
|
191
258
|
|
192
|
-
if option.is_optional
|
259
|
+
if option.is_optional
|
260
|
+
# setup tracker for optional group
|
193
261
|
tracker[option.is_optional] = [] if tracker[option.is_optional].nil?
|
194
262
|
|
195
|
-
|
263
|
+
# mark all optionals as not-included
|
264
|
+
tracker[option.is_optional].push(
|
196
265
|
included: false,
|
197
266
|
name: option.name,
|
198
|
-
|
267
|
+
)
|
199
268
|
else
|
200
269
|
@optionals_before[option.name] = tracker
|
201
270
|
tracker = {}
|
202
271
|
end
|
203
272
|
end
|
204
273
|
|
205
|
-
|
274
|
+
# make sure all optionals are accounted for in the map
|
275
|
+
if tracker != {}
|
276
|
+
# use a special key so we can handle it differently in the filling process
|
206
277
|
@optionals_before[:REMAINING] = tracker
|
207
278
|
@optionals_before_has_remaining = true
|
208
279
|
end
|
209
280
|
|
210
|
-
|
281
|
+
_match_arguments_options_before_matcher
|
282
|
+
|
283
|
+
self
|
211
284
|
end
|
212
285
|
|
213
|
-
|
286
|
+
# Match remaining args against the optionals map
|
287
|
+
#
|
288
|
+
# @return [Consoler::Matcher]
|
289
|
+
def _match_arguments_options_before_matcher
|
290
|
+
# number of arguments that are needed to fill our mandatory argument options
|
214
291
|
mandatories_matched = @optionals_before.size
|
215
292
|
|
216
|
-
|
293
|
+
# there are optionals at the end of the options, don't match the void
|
294
|
+
if @optionals_before_has_remaining
|
217
295
|
mandatories_matched -= 1
|
218
296
|
end
|
219
297
|
|
220
298
|
total = 0
|
221
299
|
|
300
|
+
# loop through optional map
|
222
301
|
_each_optional_before_sorted do |before|
|
223
|
-
|
302
|
+
# are there enough arguments left to fill this optional group
|
303
|
+
if (total + before.size + mandatories_matched) <= @argument_values.size
|
224
304
|
total += before.size
|
225
305
|
|
226
306
|
before.each do |val|
|
227
|
-
val[:included] = true
|
307
|
+
val[:included] = true
|
228
308
|
end
|
229
309
|
end
|
230
310
|
end
|
311
|
+
|
312
|
+
self
|
231
313
|
end
|
232
314
|
|
315
|
+
# Give all unmatched optional options there default value
|
316
|
+
#
|
317
|
+
# @return [Consoler::Matcher]
|
233
318
|
def _fill_defaults
|
234
319
|
@options.each do |option|
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
320
|
+
next unless option.is_optional
|
321
|
+
|
322
|
+
unless @matched_options.key? option.name
|
323
|
+
@matched_options[option.name] = option.default_value
|
239
324
|
end
|
240
325
|
end
|
326
|
+
|
327
|
+
self
|
241
328
|
end
|
242
329
|
|
330
|
+
# Loop through the optionals before map
|
331
|
+
#
|
332
|
+
# Sorted by number of optionals in a group
|
333
|
+
#
|
334
|
+
# @return [Consoler::Matcher]
|
243
335
|
def _each_optional_before_sorted
|
244
336
|
@optionals_before.each do |_, optionals|
|
245
337
|
tmp = []
|
246
338
|
optionals.each do |optional_index, before|
|
247
|
-
tmp.push(
|
339
|
+
tmp.push(
|
248
340
|
count: before.size,
|
249
341
|
index: optional_index,
|
250
|
-
|
342
|
+
)
|
251
343
|
end
|
252
344
|
|
253
345
|
tmp.sort! { |a, b| b[:count] - a[:count] }.each do |item|
|
254
346
|
yield optionals[item[:index]]
|
255
347
|
end
|
256
348
|
end
|
349
|
+
|
350
|
+
self
|
257
351
|
end
|
258
352
|
end
|
259
353
|
end
|
data/lib/consoler/option.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Consoler
|
4
|
-
|
5
4
|
# Represents an option
|
6
5
|
#
|
7
6
|
# @attr_reader [String] name Name of the options
|
@@ -10,6 +9,7 @@ module Consoler
|
|
10
9
|
# @attr_reader [Boolean] is_argument Is the option an argument
|
11
10
|
# @attr_reader [Boolean] is_value Does the option need a value (<tt>--option=</tt>)
|
12
11
|
# @attr_reader [Integer] is_optional Is the option optional (> 0) (<tt>[option]</tt>)
|
12
|
+
# @attr_reader [Array] aliases List of aliases of option (<tt>-v|--verbose</tt>)
|
13
13
|
class Option
|
14
14
|
attr_reader :name
|
15
15
|
attr_reader :is_long
|
@@ -17,6 +17,7 @@ module Consoler
|
|
17
17
|
attr_reader :is_argument
|
18
18
|
attr_reader :is_value
|
19
19
|
attr_reader :is_optional
|
20
|
+
attr_reader :aliases
|
20
21
|
|
21
22
|
# Create a option
|
22
23
|
#
|
@@ -27,11 +28,14 @@ module Consoler
|
|
27
28
|
def self.create(option_def, tracker)
|
28
29
|
option = Option.new option_def, tracker
|
29
30
|
|
30
|
-
|
31
|
+
# split short options with more than 1 char in multiple options
|
32
|
+
if option.is_short && option.name.size > 1
|
33
|
+
# remember state
|
31
34
|
old_tracking = tracker.is_tracking
|
32
35
|
old_is_value = option.is_value
|
33
36
|
|
34
|
-
if option
|
37
|
+
# if the complete option is optional, fake the tracker
|
38
|
+
if option.is_optional
|
35
39
|
tracker.is_tracking = true
|
36
40
|
end
|
37
41
|
|
@@ -40,13 +44,15 @@ module Consoler
|
|
40
44
|
names.each_with_index do |name, i|
|
41
45
|
new_name = "-#{name}"
|
42
46
|
|
43
|
-
if
|
47
|
+
# if the short option should have a value, this only counts for the last option
|
48
|
+
if old_is_value && i == names.count - 1
|
44
49
|
new_name = "#{new_name}="
|
45
50
|
end
|
46
51
|
|
47
52
|
yield Option.new new_name, tracker
|
48
53
|
end
|
49
54
|
|
55
|
+
# reset to saved state
|
50
56
|
tracker.is_tracking = old_tracking
|
51
57
|
else
|
52
58
|
yield option
|
@@ -62,14 +68,20 @@ module Consoler
|
|
62
68
|
def to_definition
|
63
69
|
definition = name
|
64
70
|
|
65
|
-
if is_long
|
71
|
+
if is_long
|
66
72
|
definition = "--#{definition}"
|
67
|
-
elsif is_short
|
73
|
+
elsif is_short
|
68
74
|
definition = "-#{definition}"
|
69
75
|
end
|
70
76
|
|
71
|
-
if is_value
|
77
|
+
if is_value
|
72
78
|
definition = "#{definition}="
|
79
|
+
elsif is_argument
|
80
|
+
definition = "<#{definition}>"
|
81
|
+
end
|
82
|
+
|
83
|
+
aliases.each do |alias_|
|
84
|
+
definition = "#{definition}|#{alias_.to_definition}"
|
73
85
|
end
|
74
86
|
|
75
87
|
definition
|
@@ -83,7 +95,7 @@ module Consoler
|
|
83
95
|
return 0 if is_short
|
84
96
|
return false if is_long
|
85
97
|
|
86
|
-
|
98
|
+
nil
|
87
99
|
end
|
88
100
|
|
89
101
|
protected
|
@@ -92,29 +104,61 @@ module Consoler
|
|
92
104
|
#
|
93
105
|
# @param [String] option_def Definition of the option
|
94
106
|
# @param [Consoler::Tracker] tracker tracker
|
107
|
+
# @raise [RuntimeError] if the option name is empty
|
108
|
+
# @raise [RuntimeError] if the option is long _and_ short
|
95
109
|
def initialize(option_def, tracker)
|
96
|
-
option
|
110
|
+
# Check for multiple attributes in the option definition till we got the
|
111
|
+
# final name and all of its attributes
|
112
|
+
|
113
|
+
# make sure we don't wrongly process any alias
|
114
|
+
alias_defs = option_def.split '|'
|
115
|
+
option = alias_defs.shift || ''
|
116
|
+
|
117
|
+
option, @is_optional = _is_optional option, tracker
|
97
118
|
option, @is_long = _is_long option
|
98
119
|
option, @is_short = _is_short option
|
99
|
-
@is_argument = (
|
120
|
+
@is_argument = (!@is_long && !@is_short)
|
100
121
|
option, @is_value = _value option, @is_argument
|
122
|
+
option, @aliases = _aliases option, alias_defs, tracker
|
123
|
+
|
124
|
+
if option[0] == '<'
|
125
|
+
raise 'Invalid <, missing >' if option[-1] != '>'
|
126
|
+
raise 'Only arguments support <, > around name' unless @is_argument
|
127
|
+
|
128
|
+
option = option[1..-2]
|
129
|
+
end
|
130
|
+
|
131
|
+
raise 'Missing starting <' if option[-1] == '>'
|
101
132
|
|
102
133
|
@name = option
|
103
134
|
|
104
|
-
if @name.empty?
|
135
|
+
if @name.empty?
|
105
136
|
raise 'Option must have a name'
|
106
137
|
end
|
107
138
|
|
108
|
-
if @is_long
|
139
|
+
if @is_long && @is_short
|
109
140
|
raise 'Option can not be a long and a short option'
|
110
141
|
end
|
111
142
|
end
|
112
143
|
|
113
144
|
private
|
114
145
|
|
146
|
+
# Check optional definition
|
147
|
+
#
|
148
|
+
# Does it open an optional group
|
149
|
+
# Does it close an optional group (can be both)
|
150
|
+
# Updates the tracker
|
151
|
+
# Removes leading [ and trailing ]
|
152
|
+
#
|
153
|
+
# @param [String] option Option definition
|
154
|
+
# @param [Consoler::Tracker] tracker Optional tracker
|
155
|
+
# @raise [RuntimeError] if you try to nest optional groups
|
156
|
+
# @raise [RuntimeError] if you try to close an unopened optional
|
157
|
+
# @return [(String, Integer|nil)] Remaining option definition, and, optional group if available
|
115
158
|
def _is_optional(option, tracker)
|
116
|
-
if option[0] == '['
|
117
|
-
if !tracker.is_tracking
|
159
|
+
if option[0] == '['
|
160
|
+
if !tracker.is_tracking
|
161
|
+
# mark tracker as tracking
|
118
162
|
tracker.is_tracking = true
|
119
163
|
tracker.index += 1
|
120
164
|
option = option[1..-1]
|
@@ -123,14 +167,14 @@ module Consoler
|
|
123
167
|
end
|
124
168
|
end
|
125
169
|
|
126
|
-
optional
|
170
|
+
# get optional group index from tracking, if tracking
|
171
|
+
optional = if tracker.is_tracking
|
127
172
|
tracker.index
|
128
|
-
else
|
129
|
-
nil
|
130
173
|
end
|
131
174
|
|
132
|
-
if option[-1] == ']'
|
133
|
-
if tracker.is_tracking
|
175
|
+
if option[-1] == ']'
|
176
|
+
if tracker.is_tracking
|
177
|
+
# mark tracker as non-tracking
|
134
178
|
tracker.is_tracking = false
|
135
179
|
option = option[0..-2]
|
136
180
|
else
|
@@ -138,34 +182,47 @@ module Consoler
|
|
138
182
|
end
|
139
183
|
end
|
140
184
|
|
141
|
-
|
185
|
+
[option, optional]
|
142
186
|
end
|
143
187
|
|
188
|
+
# Check long definition
|
189
|
+
#
|
190
|
+
# @param [String] option Option definition
|
191
|
+
# @return [(String, Boolean)]
|
144
192
|
def _is_long(option)
|
145
|
-
if option[0..1] == '--'
|
193
|
+
if option[0..1] == '--'
|
146
194
|
long = true
|
147
195
|
option = option[2..-1]
|
148
196
|
else
|
149
197
|
long = false
|
150
198
|
end
|
151
199
|
|
152
|
-
|
200
|
+
[option, long]
|
153
201
|
end
|
154
202
|
|
203
|
+
# Check short definition
|
204
|
+
#
|
205
|
+
# @param [String] option Option definition
|
206
|
+
# @return [(String, Boolean)]
|
155
207
|
def _is_short(option)
|
156
|
-
if option[0] == '-'
|
208
|
+
if option[0] == '-'
|
157
209
|
short = true
|
158
210
|
option = option[1..-1]
|
159
211
|
else
|
160
212
|
short = false
|
161
213
|
end
|
162
214
|
|
163
|
-
|
215
|
+
[option, short]
|
164
216
|
end
|
165
217
|
|
218
|
+
# Check value definition
|
219
|
+
#
|
220
|
+
# @param [String] option Option definition
|
221
|
+
# @raise [RuntimeError] if you try to assign a value to an argument
|
222
|
+
# @return [(String, Boolean)]
|
166
223
|
def _value(option, argument)
|
167
|
-
if option[-1] == '='
|
168
|
-
if argument
|
224
|
+
if option[-1] == '='
|
225
|
+
if argument
|
169
226
|
raise 'Arguments can\'t have a value'
|
170
227
|
end
|
171
228
|
|
@@ -175,7 +232,36 @@ module Consoler
|
|
175
232
|
value = false
|
176
233
|
end
|
177
234
|
|
178
|
-
|
235
|
+
[option, value]
|
236
|
+
end
|
237
|
+
|
238
|
+
# Parse all possible aliases
|
239
|
+
#
|
240
|
+
# @param [String] option Option definition
|
241
|
+
# @param [Consoler::Tracker] tracker Optional tracker
|
242
|
+
# @raise [RuntimeError] On all kinds of occasions
|
243
|
+
# @return [(String, Array)] Remaining option definition, and, aliases if available
|
244
|
+
def _aliases(option, alias_defs, tracker)
|
245
|
+
return option, [] if alias_defs.empty?
|
246
|
+
|
247
|
+
raise 'Argument can\'t have aliases' if is_argument
|
248
|
+
raise 'Aliases are not allowed for multiple short options' if is_short && option.size > 1
|
249
|
+
|
250
|
+
aliases_ = []
|
251
|
+
alias_names = []
|
252
|
+
|
253
|
+
while (alias_def = alias_defs.shift)
|
254
|
+
Consoler::Option.create alias_def, tracker do |alias_|
|
255
|
+
raise "Duplicate alias name: #{alias_.name}" if alias_names.include? alias_.name
|
256
|
+
raise "Alias must have a value: #{alias_.name}" if is_value && !alias_.is_value
|
257
|
+
raise "Alias can't have a value: #{alias_.name}" if !is_value && alias_.is_value
|
258
|
+
|
259
|
+
aliases_.push alias_
|
260
|
+
alias_names.push alias_.name
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
[option, aliases_]
|
179
265
|
end
|
180
266
|
end
|
181
267
|
end
|