class Thor::Options
def assert_value!(switch)
def assert_value!(switch) raise Error, "no value provided for argument '#{switch}'" if peek.nil? end
def check_required!(hash)
def check_required!(hash) for name, type in @switches if type == :required and !hash[undasherize(name)] raise Error, "no value provided for required argument '#{name}'" end end end
def current_is_option?
def current_is_option? case peek when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM valid?($1) when SHORT_SQ_RE $1.split('').any? { |f| valid?("-#{f}") } end end
def dasherize(str)
def dasherize(str) (str.length > 1 ? "--" : "-") + str end
def formatted_usage
def formatted_usage return "" if @switches.empty? @switches.map do |opt, type| case type when :boolean "[#{opt}]" when :required opt + "=" + opt.gsub(/\-/, "").upcase else sample = @defaults[undasherize(opt)] sample ||= case type when :optional then opt.gsub(/\-/, "").upcase when :numeric then "N" end "[" + opt + "=" + sample.to_s + "]" end end.join(" ") end
def initialize(switches)
).parse(args)
["--level", "-l"] => :numeric
["--verbose", "-v"] => true,
"--debug" => true,
opts = Thor::Options.new(
Example:
first letter of the short switch. The default type is :boolean.
The long switch _must_ be provided. The short switch defaults to the
by the user.
for each key depends on the type of switch and/or the value provided
containing each switch name, minus the '-', as a key. The value
elements that indicate the name and type of switch. Returns a hash
Takes an array of switches. Each array consists of up to three
def initialize(switches) @defaults = {} @shorts = {} @switches = switches.inject({}) do |mem, (name, type)| if name.is_a?(Array) name, *shorts = name else name = name.to_s shorts = [] end # we need both nice and dasherized form of switch name if name.index('-') == 0 nice_name = undasherize name else nice_name = name name = dasherize name end # if there are no shortcuts specified, generate one using the first character shorts << "-" + nice_name[0,1] if shorts.empty? and nice_name.length > 1 shorts.each { |short| @shorts[short] = name } # normalize type case type when TrueClass then type = :boolean when String @defaults[nice_name] = type type = :optional when Numeric @defaults[nice_name] = type type = :numeric end mem[name] = type mem end # remove shortcuts that happen to coincide with any of the main switches @shorts.keys.each do |short| @shorts.delete(short) if @switches.key?(short) end end
def non_opts
def non_opts leading_non_opts + trailing_non_opts end
def normalize_switch(switch)
def normalize_switch(switch) @shorts.key?(switch) ? @shorts[switch] : switch end
def parse(args, skip_leading_non_opts = true)
def parse(args, skip_leading_non_opts = true) @args = args # start with Thor::Options::Hash pre-filled with defaults hash = Hash.new @defaults @leading_non_opts = [] if skip_leading_non_opts @leading_non_opts << shift until current_is_option? || @args.empty? end while current_is_option? case shift 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) nice_name = undasherize(switch) type = switch_type(switch) case type when :required assert_value!(switch) raise Error, "cannot pass switch '#{peek}' as an argument" if valid?(peek) hash[nice_name] = shift when :optional hash[nice_name] = peek.nil? || valid?(peek) || shift when :boolean hash[nice_name] = true when :numeric assert_value!(switch) unless peek =~ NUMERIC and $& == peek raise Error, "expected numeric value for '#{switch}'; got #{peek.inspect}" end hash[nice_name] = $&.index('.') ? shift.to_f : shift.to_i end end @trailing_non_opts = @args check_required! hash hash.freeze hash end
def peek
def peek @args.first end
def shift
def shift @args.shift end
def switch_type(switch)
def switch_type(switch) @switches[switch] end
def undasherize(str)
def undasherize(str) str.sub(/^-{1,2}/, '') end
def unshift(arg)
def unshift(arg) unless arg.kind_of?(Array) @args.unshift(arg) else @args = arg + @args end end
def valid?(arg)
def valid?(arg) @switches.key?(arg) or @shorts.key?(arg) end