class Thor::Options
:nodoc: # rubocop:disable ClassLength
def self.to_switches(options)
def self.to_switches(options) options.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
def check_unknown!
def check_unknown! to_check = @stopped_parsing_after_extra_index ? @extra[0...@stopped_parsing_after_extra_index] : @extra # an unknown option starts with - or -- and has no more --'s afterward. unknown = to_check.select { |str| str =~ /^--?(?:(?!--).)*$/ } raise UnknownArgumentError.new(@switches.keys, unknown) unless unknown.empty? end
def current_is_switch?
Two booleans are returned. The first is true if the current value
Check if the current value in peek is a registered switch.
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
def current_is_switch_formatted?
def current_is_switch_formatted? case peek when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM, SHORT_SQ_RE true else false end end
def current_is_value?
def current_is_value? peek && (!parsing_options? || super) end
def initialize(hash_options = {}, defaults = {}, stop_on_unknown = false, disable_required_check = false)
If +stop_on_unknown+ is true, #parse will stop as soon as it encounters
Takes a hash of Thor::Option and a hash with defaults.
def initialize(hash_options = {}, defaults = {}, stop_on_unknown = false, disable_required_check = false) @stop_on_unknown = stop_on_unknown @disable_required_check = disable_required_check options = hash_options.values super(options) # Add defaults defaults.each do |key, value| @assigns[key.to_s] = value @non_assigned_required.delete(hash_options[key]) end @shorts = {} @switches = {} @extra = [] @stopped_parsing_after_extra_index = nil options.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
def normalize_switch(arg)
Check if the given argument is actually a shortcut.
def normalize_switch(arg) (@shorts[arg] || arg).tr("_", "-") end
def parse(args) # rubocop:disable MethodLength
def parse(args) # rubocop:disable MethodLength @pile = args.dup @parsing_options = true while peek if parsing_options? 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) switch = $1 when LONG_RE, SHORT_RE switch = $1 end switch = normalize_switch(switch) option = switch_option(switch) @assigns[option.human_name] = parse_peek(switch, option) elsif @stop_on_unknown @parsing_options = false @extra << shifted @stopped_parsing_after_extra_index ||= @extra.size @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 assigns end
def parse_boolean(switch)
Parse boolean values which can be given as --foo=true, --foo or --no-foo.
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
def parse_peek(switch, option)
Parse the value at the peek analyzing if it requires an input or not.
def parse_peek(switch, option) if parsing_options? && (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
def parsing_options?
def parsing_options? peek @parsing_options end
def peek
def peek return super unless @parsing_options result = super if result == OPTS_END shift @parsing_options = false @stopped_parsing_after_extra_index ||= @extra.size super else result end end
def remaining
def remaining @extra end
def switch?(arg)
def switch?(arg) switch_option(normalize_switch(arg)) end
def switch_option(arg)
def switch_option(arg) if match = no_or_skip?(arg) # rubocop:disable AssignmentInCondition @switches[arg] || @switches["--#{match}"] else @switches[arg] end end