atli 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,12 +1,40 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Thor
2
- class Options < Arguments #:nodoc: # rubocop:disable ClassLength
4
+ class Options < Arguments # rubocop:disable ClassLength
5
+
6
+ # Constants
7
+ # ========================================================================
8
+
3
9
  LONG_RE = /^(--\w+(?:-\w+)*)$/
4
10
  SHORT_RE = /^(-[a-z])$/i
5
11
  EQ_RE = /^(--\w+(?:-\w+)*|-[a-z])=(.*)$/i
6
- SHORT_SQ_RE = /^-([a-z]{2,})$/i # Allow either -x -v or -xv style for single char args
7
- SHORT_NUM = /^(-[a-z])#{NUMERIC}$/i
8
- OPTS_END = "--".freeze
9
-
12
+
13
+ # Matches "multiple short switches", like `-xv`.
14
+ #
15
+ # @return [Regexp]
16
+ #
17
+ SHORT_SQ_RE = /^-([a-z]{2,})$/i
18
+
19
+
20
+ # Matches things like `'-x123'`.
21
+ #
22
+ # @return [Regexp]
23
+ #
24
+ SHORT_NUM = /^(-[a-z])#{ Thor::Arguments::NUMERIC }$/i
25
+
26
+
27
+ # The "bare double-dash" used to indicate that following arguments
28
+ # should not be parsed for options.
29
+ #
30
+ # @return [String]
31
+ #
32
+ OPTS_END = "--"
33
+
34
+
35
+ # Class Methods
36
+ # ========================================================================
37
+
10
38
  # Receives a hash and makes it switches.
11
39
  def self.to_switches(options)
12
40
  options.map do |key, value|
@@ -24,12 +52,23 @@ class Thor
24
52
  end
25
53
  end.compact.join(" ")
26
54
  end
27
-
55
+
56
+
57
+ # Constructor
58
+ # ========================================================================
59
+
28
60
  # Takes a hash of Thor::Option and a hash with defaults.
29
61
  #
30
62
  # If +stop_on_unknown+ is true, #parse will stop as soon as it encounters
31
63
  # an unknown option or a regular argument.
32
- def initialize(hash_options = {}, defaults = {}, stop_on_unknown = false, disable_required_check = false)
64
+ #
65
+ # @param [Hash<Symbol, Thor::Option>] hash_options
66
+ #
67
+ #
68
+ def initialize hash_options = {},
69
+ defaults = {},
70
+ stop_on_unknown = false,
71
+ disable_required_check = false
33
72
  @stop_on_unknown = stop_on_unknown
34
73
  @disable_required_check = disable_required_check
35
74
  options = hash_options.values
@@ -54,25 +93,56 @@ class Thor
54
93
  end
55
94
  end
56
95
  end
57
-
96
+
97
+
98
+ # Instance Methods
99
+ # ========================================================================
100
+
58
101
  def remaining
59
102
  @extra
60
103
  end
61
-
104
+
105
+
106
+ # What's next?! I think.
107
+ #
108
+ # @note
109
+ # This *used to* remove `--` separators (what {OPTS_END} is),
110
+ # but that was problematic with multiple nested subcommands
111
+ # 'cause Thor classes further down the chain wouldn't know that
112
+ # it was there and would parse options that had been after it.
113
+ #
114
+ # Maybe that's how Thor was supposed to work (???), but it didn't really
115
+ # jive with me... I've always felt like stuff after `--` meant
116
+ # **_stop parsing options - these are always args_** since I usually
117
+ # see it used when passing shell commands to other shell commands -
118
+ # which is how I was using it when I came across the issues.
119
+ #
120
+ # And it ain't like Thor has any documentation to straiten it out. Hell,
121
+ # this method had no doc when I showed up. The line that dropped the `--`
122
+ # has no comment. The {Thor::Options} class itself had no doc.
123
+ #
124
+ # So, now it *does* mean that... `--` means "no option parsing after
125
+ # here". For real.
126
+ #
62
127
  def peek
63
128
  return super unless @parsing_options
64
129
 
65
130
  result = super
66
131
  if result == OPTS_END
67
- shift
132
+ # Removed, see note above:
133
+ # shift
68
134
  @parsing_options = false
69
135
  super
70
136
  else
71
137
  result
72
138
  end
73
139
  end
74
-
75
- def parse(args) # rubocop:disable MethodLength
140
+
141
+
142
+ def parse args # rubocop:disable MethodLength
143
+ logger.debug __method__.to_s,
144
+ args: args
145
+
76
146
  @pile = args.dup
77
147
  @parsing_options = true
78
148
 
@@ -87,15 +157,15 @@ class Thor
87
157
  unshift($1.split("").map { |f| "-#{f}" })
88
158
  next
89
159
  when EQ_RE, SHORT_NUM
90
- unshift($2)
91
- switch = $1
160
+ unshift $2
161
+ raw_switch_arg = $1
92
162
  when LONG_RE, SHORT_RE
93
- switch = $1
163
+ raw_switch_arg = $1
94
164
  end
95
165
 
96
- switch = normalize_switch(switch)
97
- option = switch_option(switch)
98
- @assigns[option.human_name] = parse_peek(switch, option)
166
+ switch = normalize_switch raw_switch_arg
167
+ option = switch_option switch
168
+ @assigns[option.human_name] = parse_peek switch, option
99
169
  elsif @stop_on_unknown
100
170
  @parsing_options = false
101
171
  @extra << shifted
@@ -116,106 +186,152 @@ class Thor
116
186
 
117
187
  assigns = Thor::CoreExt::HashWithIndifferentAccess.new(@assigns)
118
188
  assigns.freeze
189
+
190
+ logger.debug "#{ __method__ } done",
191
+ assigns: assigns,
192
+ remaining: remaining
193
+
119
194
  assigns
120
195
  end
121
-
196
+
197
+
122
198
  def check_unknown!
123
199
  # an unknown option starts with - or -- and has no more --'s afterward.
124
200
  unknown = @extra.select { |str| str =~ /^--?(?:(?!--).)*$/ }
125
- raise UnknownArgumentError, "Unknown switches '#{unknown.join(', ')}'" unless unknown.empty?
126
- end
127
-
128
- protected
129
-
130
- # Check if the current value in peek is a registered switch.
131
- #
132
- # Two booleans are returned. The first is true if the current value
133
- # starts with a hyphen; the second is true if it is a registered switch.
134
- def current_is_switch?
135
- case peek
136
- when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM
137
- [true, switch?($1)]
138
- when SHORT_SQ_RE
139
- [true, $1.split("").any? { |f| switch?("-#{f}") }]
140
- else
141
- [false, false]
201
+ unless unknown.empty?
202
+ raise UnknownArgumentError, "Unknown switches '#{unknown.join(', ')}'"
142
203
  end
143
204
  end
144
-
145
- def current_is_switch_formatted?
146
- case peek
147
- when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM, SHORT_SQ_RE
148
- true
149
- else
150
- false
205
+
206
+
207
+ protected # Instance Methods
208
+ # ==========================================================================
209
+
210
+ def last?
211
+ super() || peek == OPTS_END
151
212
  end
152
- end
153
213
 
154
- def current_is_value?
155
- peek && (!parsing_options? || super)
156
- end
157
-
158
- def switch?(arg)
159
- switch_option(normalize_switch(arg))
160
- end
161
-
162
- def switch_option(arg)
163
- if match = no_or_skip?(arg) # rubocop:disable AssignmentInCondition
164
- @switches[arg] || @switches["--#{match}"]
165
- else
166
- @switches[arg]
214
+ # Check if the current value in peek is a registered switch.
215
+ #
216
+ # Two booleans are returned. The first is true if the current value
217
+ # starts with a hyphen; the second is true if it is a registered switch.
218
+ def current_is_switch?
219
+ case peek
220
+ when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM
221
+ [true, switch?($1)]
222
+ when SHORT_SQ_RE
223
+ [true, $1.split("").any? { |f| switch?("-#{f}") }]
224
+ else
225
+ [false, false]
226
+ end
167
227
  end
168
- end
169
-
170
- # Check if the given argument is actually a shortcut.
171
- #
172
- def normalize_switch(arg)
173
- (@shorts[arg] || arg).tr("_", "-")
174
- end
175
-
176
- def parsing_options?
177
- peek
178
- @parsing_options
179
- end
180
-
181
- # Parse boolean values which can be given as --foo=true, --foo or --no-foo.
182
- #
183
- def parse_boolean(switch)
184
- if current_is_value?
185
- if ["true", "TRUE", "t", "T", true].include?(peek)
186
- shift
228
+
229
+
230
+ def current_is_switch_formatted?
231
+ case peek
232
+ when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM, SHORT_SQ_RE
187
233
  true
188
- elsif ["false", "FALSE", "f", "F", false].include?(peek)
189
- shift
234
+ else
190
235
  false
236
+ end
237
+ end
238
+
239
+
240
+ def switch?(arg)
241
+ switch_option(normalize_switch(arg))
242
+ end
243
+
244
+
245
+ # Get the option for a switch arg.
246
+ #
247
+ # Handles parsing `--no-<option>` and `--skip-<option>` styles as well.
248
+ #
249
+ # @param [String] arg
250
+ # The switch part of the CLI arg, like `--blah`.
251
+ #
252
+ # @return [Thor::Option]
253
+ # If we have an option for the switch.
254
+ #
255
+ # @return [nil]
256
+ # If we don't have an option for the switch.
257
+ #
258
+ def switch_option(arg)
259
+ if match = no_or_skip?(arg) # rubocop:disable AssignmentInCondition
260
+ @switches[arg] || @switches["--#{match}"]
191
261
  else
192
- !no_or_skip?(switch)
262
+ @switches[arg]
193
263
  end
194
- else
195
- @switches.key?(switch) || !no_or_skip?(switch)
196
264
  end
197
- end
198
-
199
- # Parse the value at the peek analyzing if it requires an input or not.
200
- #
201
- def parse_peek(switch, option)
202
- if parsing_options? && (current_is_switch_formatted? || last?)
203
- if option.boolean?
204
- # No problem for boolean types
205
- elsif no_or_skip?(switch)
206
- return nil # User set value to nil
207
- elsif option.string? && !option.required?
208
- # Return the default if there is one, else the human name
209
- return option.lazy_default || option.default || option.human_name
210
- elsif option.lazy_default
211
- return option.lazy_default
265
+
266
+
267
+ # Check if the given argument is actually a shortcut.
268
+ #
269
+ # Also normalizes '_' to '-'.
270
+ #
271
+ # @param [String] raw_switch_arg
272
+ # The raw switch arg that we received (essentially, what was passed
273
+ # on the CLI).
274
+ #
275
+ # @return [String]
276
+ # Normalized, de-aliased switch string.
277
+ #
278
+ def normalize_switch raw_switch_arg
279
+ (@shorts[raw_switch_arg] || raw_switch_arg).tr("_", "-")
280
+ end
281
+
282
+
283
+ def parsing_options?
284
+ peek
285
+ @parsing_options
286
+ end
287
+
288
+
289
+ # Parse boolean values which can be given as --foo=true, --foo or --no-foo.
290
+ #
291
+ def parse_boolean(switch)
292
+ if current_is_value?
293
+ if ["true", "TRUE", "t", "T", true].include?(peek)
294
+ shift
295
+ true
296
+ elsif ["false", "FALSE", "f", "F", false].include?(peek)
297
+ shift
298
+ false
299
+ else
300
+ !no_or_skip?(switch)
301
+ end
212
302
  else
213
- raise MalformattedArgumentError, "No value provided for option '#{switch}'"
303
+ @switches.key?(switch) || !no_or_skip?(switch)
214
304
  end
215
305
  end
306
+
307
+
308
+ # Parse the value at the peek analyzing if it requires an input or not.
309
+ #
310
+ # @param [String] switch
311
+ # The normalized option switch, as returned from {#normalize_switch}.
312
+ #
313
+ def parse_peek switch, option
314
+ if current_is_switch_formatted? || last?
315
+ if option.boolean?
316
+ # No problem for boolean types
317
+ elsif no_or_skip?(switch)
318
+ return nil # User set value to nil
319
+ elsif option.string? && !option.required?
320
+ # Return the default if there is one, else the human name
321
+ return option.lazy_default || option.default || option.human_name
322
+ elsif option.lazy_default
323
+ return option.lazy_default
324
+ else
325
+ raise MalformattedArgumentError,
326
+ "No value provided for option '#{switch}'"
327
+ end
328
+ end
216
329
 
217
- @non_assigned_required.delete(option)
218
- send(:"parse_#{option.type}", switch)
219
- end
220
- end
221
- end
330
+ @non_assigned_required.delete(option)
331
+ send(:"parse_#{option.type}", switch)
332
+ end # #parse_peek
333
+
334
+ public # end protected Instance Methods **********************************
335
+
336
+ end # class Options
337
+ end # class Thor
@@ -14,7 +14,7 @@ class Thor
14
14
  #
15
15
  # @return [String]
16
16
  #
17
- VERSION = '0.1.4'
17
+ VERSION = '0.1.5'
18
18
 
19
19
 
20
20
  # The version of Thor that Atli is up to date with.
@@ -27,5 +27,5 @@ class Thor
27
27
  #
28
28
  # @return [String]
29
29
  #
30
- THOR_VERSION = '0.1.4'
30
+ THOR_VERSION = '0.1.5'
31
31
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: atli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Neil Souza (Atli)
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2018-02-27 00:00:00.000000000 Z
13
+ date: 2018-03-03 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: bundler
@@ -91,6 +91,7 @@ files:
91
91
  - lib/thor/actions/file_manipulation.rb
92
92
  - lib/thor/actions/inject_into_file.rb
93
93
  - lib/thor/base.rb
94
+ - lib/thor/base/class_methods.rb
94
95
  - lib/thor/base/common_class_options.rb
95
96
  - lib/thor/command.rb
96
97
  - lib/thor/core_ext/hash_with_indifferent_access.rb