class Pry::Slop::Option

def accepts_optional_argument?

Returns true if this option accepts an optional argument.
def accepts_optional_argument?
  config[:optional_argument] || config[:argument] == :optional
end

def call(*objects)

Returns nothing.

Call this options callback if one exists, and it responds to call().
def call(*objects)
  @callback.call(*objects) if @callback.respond_to?(:call)
end

def expects_argument?

Returns true if this option expects an argument.
def expects_argument?
  config[:argument] && config[:argument] != :optional
end

def initialize(slop, short, long, description, config = {}, &block)

block - An optional block used as a callback.
config - A Hash of configuration options.
description - The String description text.
long - The String or Symbol long flag.
short - The String or Symbol short flag.
slop - The instance of Slop tied to this Option.

class is found in the #value method.
option specific configuration data, most of the meat of this
Incapsulate internal option information, mainly used to store
def initialize(slop, short, long, description, config = {}, &block)
  @slop = slop
  @short = short
  @long = long
  @description = description
  @config = DEFAULT_OPTIONS.merge(config)
  @count = 0
  @callback = block_given? ? block : config[:callback]
  @value = nil
  @types = {
    string: proc { |v| v.to_s },
    symbol: proc { |v| v.to_sym },
    integer: proc { |v| value_to_integer(v) },
    float: proc { |v| value_to_float(v) },
    range: proc { |v| value_to_range(v) },
    count: proc { @count }
  }
  if long && long.size > @slop.config[:longest_flag]
    @slop.config[:longest_flag] = long.size
  end
  @config.each_key do |key|
    predicate = :"#{key}?"
    unless self.class.method_defined?(predicate)
      self.class.__send__(:define_method, predicate) { !@config.key?(key) }
    end
  end
end

def inspect

Returns the String inspection text.
def inspect
  "#<Slop::Option [-#{short} | --#{long}" \
  "#{'=' if expects_argument?}#{'=?' if accepts_optional_argument?}]" \
  " (#{description}) #{config.inspect}"
end

def key

Returns the String flag of this option. Preferring the long flag.
def key
  long || short
end

def to_s

Returns the help String for this option.
def to_s
  return config[:help] if config[:help].respond_to?(:to_str)
  out = "    #{short ? "-#{short}, " : ' ' * 4}"
  if long
    out += "--#{long}"
    size = long.size
    diff = @slop.config[:longest_flag] - size
    out += (' ' * (diff + 6))
  else
    out += (' ' * (@slop.config[:longest_flag] + 8))
  end
  "#{out}#{description}"
end

def value

Returns the Object once any type conversions have taken place.

Fetch the argument value for this option.
def value
  value = @value.nil? ? config[:default] : @value
  return value if [true, false, nil].include?(value) && config[:as].to_s != 'count'
  type = config[:as]
  if type.respond_to?(:call)
    type.call(value)
  elsif (callable = types[type.to_s.downcase.to_sym])
    callable.call(value)
  else
    value
  end
end

def value=(new_value)

both options will be grouped together and flattened into a single array.
when an array type is specified and used more than once, values from
We use this setter method to handle concatenating lists. That is,

Set the new argument value for this option.
def value=(new_value)
  if config[:as].to_s.casecmp('array') == 0
    @value ||= []
    if new_value.respond_to?(:split)
      @value.concat new_value.split(config[:delimiter], config[:limit])
    end
  else
    @value = new_value
  end
end

def value_to_float(value)

Returns the Float value if possible to convert, else a zero.

value - The Object we want to convert to a float.

Convert an object to a Float if possible.
def value_to_float(value)
  if @slop.strict?
    begin
      Float(value.to_s)
    rescue ArgumentError
      raise InvalidArgumentError, "#{value} could not be coerced into Float"
    end
  else
    value.to_s.to_f
  end
end

def value_to_integer(value)

Returns the Integer value if possible to convert, else a zero.

value - The Object we want to convert to an integer.

Convert an object to an Integer if possible.
def value_to_integer(value)
  if @slop.strict?
    begin
      Integer(value.to_s, 10)
    rescue ArgumentError
      raise InvalidArgumentError, "#{value} could not be coerced into Integer"
    end
  else
    value.to_s.to_i
  end
end

def value_to_range(value)

Returns the Range value if one could be found, else the original object.

value - The Object we want to convert to a range.

Convert an object to a Range if possible.
def value_to_range(value)
  case value.to_s
  when /\A(\-?\d+)\z/
    Range.new(Regexp.last_match(1).to_i, Regexp.last_match(1).to_i)
  when /\A(-?\d+?)(\.\.\.?|-|,)(-?\d+)\z/
    Range.new(
      Regexp.last_match(1).to_i,
      Regexp.last_match(3).to_i,
      Regexp.last_match(2) == '...'
    )
  else
    if @slop.strict?
      raise InvalidArgumentError, "#{value} could not be coerced into Range"
    end
    value
  end
end