atli 0.1.4 → 0.1.5

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.
@@ -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