Class: Thor::Options
Overview
rubocop:disable ClassLength
Constant Summary collapse
- LONG_RE =
Constants
/^(--\w+(?:-\w+)*)$/
- SHORT_RE =
/^(-[a-z])$/i
- EQ_RE =
/^(--\w+(?:-\w+)*|-[a-z])=(.*)$/i
- SHORT_SQ_RE =
Matches “multiple short switches”, like ‘-xv`.
/^-([a-z]{2,})$/i
- SHORT_NUM =
Matches things like ‘’-x123’‘.
/^(-[a-z])#{ Thor::Arguments::NUMERIC }$/i
- OPTS_END =
The “bare double-dash” used to indicate that following arguments should not be parsed for options.
"--"
Constants inherited from Arguments
Class Method Summary collapse
-
.to_switches(options) ⇒ Object
Receives a hash and makes it switches.
Instance Method Summary collapse
- #check_unknown! ⇒ Object
-
#current_is_switch? ⇒ Boolean
protected
Check if the current value in peek is a registered switch.
- #current_is_switch_formatted? ⇒ Boolean protected
-
#initialize(options_to_parse_by_name = {}, option_default_values = {}, stop_on_unknown = false, disable_required_check = false) ⇒ Options
constructor
Takes a hash of Thor::Option and a hash with defaults.
-
#last? ⇒ Boolean
protected
.
-
#normalize_switch(raw_switch_arg) ⇒ String
protected
Check if the given argument is actually a shortcut.
-
#parse(args) ⇒ Object
rubocop:disable MethodLength.
-
#parse_boolean(switch) ⇒ Object
protected
Parse boolean values which can be given as –foo=true, –foo or –no-foo.
-
#parse_peek(switch, option) ⇒ Object
protected
Parse the value at the peek analyzing if it requires an input or not.
- #parsing_options? ⇒ Boolean protected
-
#peek ⇒ Object
What’s next?! I think.
-
#remaining ⇒ Object
Instance Methods ========================================================================.
- #switch?(arg) ⇒ Boolean protected
-
#switch_option(arg) ⇒ Thor::Option?
protected
Get the option for a switch arg.
Methods inherited from Arguments
Constructor Details
#initialize(options_to_parse_by_name = {}, option_default_values = {}, stop_on_unknown = false, disable_required_check = false) ⇒ Options
Takes a hash of Thor::Option and a hash with defaults.
If stop_on_unknown
is true, #parse will stop as soon as it encounters an unknown option or a regular argument.
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/thor/parser/options.rb', line 68 def initialize = {}, option_default_values = {}, stop_on_unknown = false, disable_required_check = false @stop_on_unknown = stop_on_unknown @disable_required_check = disable_required_check = .values super( ) # Add defaults option_default_values.each do |option_name, value| @assigns[ option_name.to_s ] = value @non_assigned_required.delete \ [ option_name ] end @shorts = {} @switches = {} @extra = [] .each do |option| @switches[option.switch_name] = option option.aliases.each do |short| name = short.to_s.sub(/^(?!\-)/, "-") @shorts[name] ||= option.switch_name end end end |
Class Method Details
.to_switches(options) ⇒ Object
Receives a hash and makes it switches.
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/thor/parser/options.rb', line 39 def self.to_switches() .map do |key, value| case value when true "--#{key}" when Array "--#{key} #{value.map(&:inspect).join(' ')}" when Hash "--#{key} #{value.map { |k, v| "#{k}:#{v}" }.join(' ')}" when nil, false nil else "--#{key} #{value.inspect}" end end.compact.join(" ") end |
Instance Method Details
#check_unknown! ⇒ Object
201 202 203 204 205 206 207 |
# File 'lib/thor/parser/options.rb', line 201 def check_unknown! # an unknown option starts with - or -- and has no more --'s afterward. unknown = @extra.select { |str| str =~ /^--?(?:(?!--).)*$/ } unless unknown.empty? raise UnknownArgumentError, "Unknown switches '#{unknown.join(', ')}'" end end |
#current_is_switch? ⇒ Boolean (protected)
Check if the current value in peek is a registered switch.
Two booleans are returned. The first is true if the current value starts with a hyphen; the second is true if it is a registered switch.
221 222 223 224 225 226 227 228 229 230 |
# File 'lib/thor/parser/options.rb', line 221 def current_is_switch? case peek when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM [true, switch?($1)] when SHORT_SQ_RE [true, $1.split("").any? { |f| switch?("-#{f}") }] else [false, false] end end |
#current_is_switch_formatted? ⇒ Boolean (protected)
233 234 235 236 237 238 239 240 |
# File 'lib/thor/parser/options.rb', line 233 def current_is_switch_formatted? case peek when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM, SHORT_SQ_RE true else false end end |
#last? ⇒ Boolean (protected)
213 214 215 |
# File 'lib/thor/parser/options.rb', line 213 def last? super() || peek == OPTS_END end |
#normalize_switch(raw_switch_arg) ⇒ String (protected)
Check if the given argument is actually a shortcut.
Also normalizes ‘_’ to ‘-’.
281 282 283 |
# File 'lib/thor/parser/options.rb', line 281 def normalize_switch raw_switch_arg (@shorts[raw_switch_arg] || raw_switch_arg).tr("_", "-") end |
#parse(args) ⇒ Object
rubocop:disable MethodLength
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
# File 'lib/thor/parser/options.rb', line 145 def parse args # rubocop:disable MethodLength logger.debug __method__.to_s, args: args @pile = args.dup @parsing_options = true while peek if match, is_switch = current_is_switch? shifted = shift if is_switch case shifted when SHORT_SQ_RE unshift($1.split("").map { |f| "-#{f}" }) next when EQ_RE, SHORT_NUM unshift $2 raw_switch_arg = $1 when LONG_RE, SHORT_RE raw_switch_arg = $1 end switch = normalize_switch raw_switch_arg option = switch_option switch @assigns[option.human_name] = parse_peek switch, option elsif @stop_on_unknown @parsing_options = false @extra << shifted @extra << shift while peek break elsif match @extra << shifted @extra << shift while peek && peek !~ /^-/ else @extra << shifted end else @extra << shift end end check_requirement! unless @disable_required_check assigns = Thor::CoreExt::HashWithIndifferentAccess.new(@assigns) assigns.freeze logger.debug "#{ __method__ } done", assigns: assigns, remaining: remaining assigns end |
#parse_boolean(switch) ⇒ Object (protected)
Parse boolean values which can be given as –foo=true, –foo or –no-foo.
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 |
# File 'lib/thor/parser/options.rb', line 294 def parse_boolean(switch) if current_is_value? if ["true", "TRUE", "t", "T", true].include?(peek) shift true elsif ["false", "FALSE", "f", "F", false].include?(peek) shift false else !no_or_skip?(switch) end else @switches.key?(switch) || !no_or_skip?(switch) end end |
#parse_peek(switch, option) ⇒ Object (protected)
Parse the value at the peek analyzing if it requires an input or not.
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 |
# File 'lib/thor/parser/options.rb', line 316 def parse_peek switch, option if current_is_switch_formatted? || last? if option.boolean? # No problem for boolean types elsif no_or_skip?(switch) return nil # User set value to nil elsif option.string? && !option.required? # Return the default if there is one, else the human name return option.lazy_default || option.default || option.human_name elsif option.lazy_default return option.lazy_default else raise MalformattedArgumentError, "No value provided for option '#{switch}'" end end @non_assigned_required.delete(option) send(:"parse_#{option.type}", switch) end |
#parsing_options? ⇒ Boolean (protected)
286 287 288 289 |
# File 'lib/thor/parser/options.rb', line 286 def peek @parsing_options end |
#peek ⇒ Object
This *used to* remove ‘–` separators (what OPTS_END is), but that was problematic with multiple nested subcommands ’cause Thor classes further down the chain wouldn’t know that it was there and would parse options that had been after it.
Maybe that’s how Thor was supposed to work (???), but it didn’t really jive with me… I’ve always felt like stuff after ‘–` meant **_stop parsing options - these are always args_** since I usually see it used when passing shell commands to other shell commands - which is how I was using it when I came across the issues.
And it ain’t like Thor has any documentation to straiten it out. Hell, this method had no doc when I showed up. The line that dropped the ‘–` has no comment. The Thor::Options class itself had no doc.
So, now it does mean that… ‘–` means “no option parsing after here”. For real.
What’s next?! I think.
130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/thor/parser/options.rb', line 130 def peek return super unless @parsing_options result = super if result == OPTS_END # Removed, see note above: # shift @parsing_options = false super else result end end |
#remaining ⇒ Object
Instance Methods
104 105 106 |
# File 'lib/thor/parser/options.rb', line 104 def remaining @extra end |
#switch?(arg) ⇒ Boolean (protected)
243 244 245 |
# File 'lib/thor/parser/options.rb', line 243 def switch?(arg) switch_option(normalize_switch(arg)) end |
#switch_option(arg) ⇒ Thor::Option? (protected)
Get the option for a switch arg.
Handles parsing ‘–no-<option>` and `–skip-<option>` styles as well.
261 262 263 264 265 266 267 |
# File 'lib/thor/parser/options.rb', line 261 def switch_option(arg) if match = no_or_skip?(arg) # rubocop:disable AssignmentInCondition @switches[arg] || @switches["--#{match}"] else @switches[arg] end end |