class Optimist::Option

def self.create(name, desc="", opts={}, settings={})

set the option's type.
parsers (e.g. Slop) because we allow the +default:+ to be able to
to +Optimist::opt+. This is trickier in Optimist, than other cmdline
Determines which type of object to create based on arguments passed
def self.create(name, desc="", opts={}, settings={})
  opttype = Optimist::Parser.registry_getopttype(opts[:type])
  opttype_from_default = get_klass_from_default(opts, opttype)
  raise ArgumentError, ":type specification and default type don't match (default type is #{opttype_from_default.class})" if opttype && opttype_from_default && (opttype.class != opttype_from_default.class)
  opt_inst = (opttype || opttype_from_default || Optimist::BooleanOption.new)
  ## fill in :long
  opt_inst.long = handle_long_opt(opts[:long], name)
  ## fill in :short
  opt_inst.short = handle_short_opt(opts[:short])
  ## fill in :multi
  multi_given = opts[:multi] || false
  opt_inst.multi_given = multi_given
  ## fill in :default for flags
  defvalue = opts[:default] || opt_inst.default
  ## autobox :default for :multi (multi-occurrence) arguments
  defvalue = [defvalue] if defvalue && multi_given && !defvalue.kind_of?(Array)
  opt_inst.default = defvalue
  opt_inst.name = name
  opt_inst.opts = opts
  opt_inst
end

def self.get_klass_from_default(opts, opttype)

def self.get_klass_from_default(opts, opttype)
  ## for options with :multi => true, an array default doesn't imply
  ## a multi-valued argument. for that you have to specify a :type
  ## as well. (this is how we disambiguate an ambiguous situation;
  ## see the docs for Parser#opt for details.)
  disambiguated_default = if opts[:multi] && opts[:default].is_a?(Array) && opttype.nil?
                            opts[:default].first
                          else
                            opts[:default]
                          end
  return nil if disambiguated_default.nil?
  type_from_default = get_type_from_disdef(opts[:default], opttype, disambiguated_default)
  return Optimist::Parser.registry_getopttype(type_from_default)
end

def self.get_type_from_disdef(optdef, opttype, disambiguated_default)

def self.get_type_from_disdef(optdef, opttype, disambiguated_default)
  if disambiguated_default.is_a? Array
    return(optdef.first.class.name.downcase + "s") if !optdef.empty?
    if opttype
      raise ArgumentError, "multiple argument type must be plural" unless opttype.multi_arg?
      return nil
    else
      raise ArgumentError, "multiple argument type cannot be deduced from an empty array"
    end
  end
  return disambiguated_default.class.name.downcase
end

def self.handle_long_opt(lopt, name)

def self.handle_long_opt(lopt, name)
  lopt = lopt ? lopt.to_s : name.to_s.gsub("_", "-")
  lopt = case lopt
         when /^--([^-].*)$/ then $1
         when /^[^-]/        then lopt
         else                     raise ArgumentError, "invalid long option name #{lopt.inspect}"
         end
end

def self.handle_short_opt(sopt)

def self.handle_short_opt(sopt)
  sopt = sopt.to_s if sopt && sopt != :none
  sopt = case sopt
         when /^-(.)$/          then $1
         when nil, :none, /^.$/ then sopt
         else                   raise ArgumentError, "invalid short option name '#{sopt.inspect}'"
         end
  if sopt
    raise ArgumentError, "a short option name can't be a number or a dash" if sopt =~ ::Optimist::Parser::INVALID_SHORT_ARG_REGEX
  end
  return sopt
end

def self.register_alias(*alias_keys)

# Provide a way to register symbol aliases to the Parser
def self.register_alias(*alias_keys)
  alias_keys.each do |alias_key|
    # pass in the alias-key and the class
    Parser.register(alias_key, self)
  end
end

def array_default? ; self.default.kind_of?(Array) ; end

def array_default? ; self.default.kind_of?(Array) ; end

def callback ; opts(:callback) ; end

def callback ; opts(:callback) ; end

def desc ; opts(:desc) ; end

def desc ; opts(:desc) ; end

def description_with_default

# Format the educate-line description including the default-value(s)
def description_with_default
  return desc unless default
  default_s = case default
              when $stdout   then '<stdout>'
              when $stdin    then '<stdin>'
              when $stderr   then '<stderr>'
              when Array
                default.join(', ')
              else
                default.to_s
              end
  defword = desc.end_with?('.') ? 'Default' : 'default'
  return "#{desc} (#{defword}: #{default_s})"
end

def educate

def educate
  (short? ? "-#{short}, " : "") + "--#{long}" + type_format + (flag? && default ? ", --no-#{long}" : "")
end

def flag? ; false ; end

# Indicates a flag option, which is an option without an argument
def flag? ; false ; end

def initialize

def initialize
  @long = nil
  @short = nil
  @name = nil
  @multi_given = false
  @hidden = false
  @default = nil
  @optshash = Hash.new()
end

def multi ; @multi_given ; end

def multi ; @multi_given ; end

def multi_arg? ; false ; end

# Indicates that this is a multivalued (Array type) argument
def multi_arg? ; false ; end

def opts(key)

def opts(key)
  @optshash[key]
end

def opts=(o)

def opts=(o)
  @optshash = o
end

def parse(_paramlist, _neg_given)

def parse(_paramlist, _neg_given)
  raise NotImplementedError, "parse must be overridden for newly registered type"
end

def required? ; opts(:required) ; end

def required? ; opts(:required) ; end

def short? ; short && short != :none ; end

def short? ; short && short != :none ; end

def single_arg?

def single_arg?
  !self.multi_arg? && !self.flag?
end

def type_format ; "" ; end

provide type-format string. default to empty, but user should probably override it
def type_format ; "" ; end