def opt name, desc="", opts={}
raise ArgumentError, "you already have an argument named '#{name}'" if @specs.member? name
opts[:type] =
case opts[:type]
when :flag, :boolean, :bool; :flag
when :int, :integer; :int
when :ints, :integers; :ints
when :string; :string
when :strings; :strings
when :double, :float; :float
when :doubles, :floats; :floats
when Class
case opts[:type].to_s
when 'TrueClass', 'FalseClass'; :flag
when 'String'; :string
when 'Integer'; :int
when 'Float'; :float
else
raise ArgumentError, "unsupported argument type '#{opts[:type].class.name}'"
end
when nil; nil
else
raise ArgumentError, "unsupported argument type '#{opts[:type]}'" unless TYPES.include?(opts[:type])
end
type_from_default =
case opts[:default]
when Integer; :int
when Numeric; :float
when TrueClass, FalseClass; :flag
when String; :string
when Array
if opts[:default].empty?
raise ArgumentError, "multiple argument type cannot be deduced from an empty array for '#{opts[:default][0].class.name}'"
end
case opts[:default][0]
when Integer; :ints
when Numeric; :floats
when String; :strings
else
raise ArgumentError, "unsupported multiple argument type '#{opts[:default][0].class.name}'"
end
when nil; nil
else
raise ArgumentError, "unsupported argument type '#{opts[:default].class.name}'"
end
raise ArgumentError, ":type specification and default type don't match" if opts[:type] && type_from_default && opts[:type] != type_from_default
opts[:type] = (opts[:type] || type_from_default || :flag)
opts[:long] = opts[:long] ? opts[:long].to_s : name.to_s.gsub("_", "-")
opts[:long] =
case opts[:long]
when /^--([^-].*)$/
$1
when /^[^-]/
opts[:long]
else
raise ArgumentError, "invalid long option name #{opts[:long].inspect}"
end
raise ArgumentError, "long option name #{opts[:long].inspect} is already taken; please specify a (different) :long" if @long[opts[:long]]
opts[:short] = opts[:short].to_s if opts[:short] unless opts[:short] == :none
opts[:short] =
case opts[:short]
when nil
c = opts[:long].split(//).find { |c| c !~ INVALID_SHORT_ARG_REGEX && !@short.member?(c) }
raise ArgumentError, "can't generate a short option name for #{opts[:long].inspect}: out of unique characters" unless c
c
when /^-(.)$/
$1
when /^.$/
opts[:short]
when :none
nil
else
raise ArgumentError, "invalid short option name '#{opts[:short].inspect}'"
end
if opts[:short]
raise ArgumentError, "short option name #{opts[:short].inspect} is already taken; please specify a (different) :short" if @short[opts[:short]]
raise ArgumentError, "a short option name can't be a number or a dash" if opts[:short] =~ INVALID_SHORT_ARG_REGEX
end
opts[:default] = false if opts[:type] == :flag && opts[:default].nil?
opts[:multi] ||= false
opts[:desc] ||= desc
@long[opts[:long]] = name
@short[opts[:short]] = name if opts[:short]
@specs[name] = opts
@order << [:opt, name]
end