consoler 1.0.1 → 1.2.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 +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
|