def coerce(value, opts={})
      raise ArgumentError, "Needs option :to => Class/Module" unless opts.has_key?(:to) && ( opts[:to].is_a?(Class) || opts[:to].is_a?(Module) )
      type = opts[:to]

      case
      # Direct conversions
      when type <= String   then String(value)
      when type <= Boolean  then Boolean(value)
      when type == Bignum   then raise TypeError, "directly converting to Bignum is not supported, use Integer instead"
      when type <= Integer  then Integer(value)
      when type <= Float    then Float(value)
      when type <= Rational then Rational(value)
      when type <= Complex  then Complex(value)
      # Symbol
      when type <= Symbol && value.respond_to?(:to_sym)
        value.to_sym
      # Dates and Times
      when type <= Time && value.is_a?(Numeric)
        Time.at(value)
      when type <= Time && value.is_a?(String)
        DateTime.parse(value).new_offset(LOCAL_OFFSET/24).to_time
      when type <= DateTime && value.respond_to?(:to_datetime)
        value.to_datetime.new_offset(LOCAL_OFFSET/24)
      when type <= DateTime && value.is_a?(String)
        DateTime.parse(value).new_offset(LOCAL_OFFSET/24)
      when type <= DateTime && value.is_a?(Integer)
        DateTime.parse(value.to_s).new_offset(LOCAL_OFFSET/24)
      # Important: DateTime < Date so the order in this case statement matters
      when type <= Date && value.is_a?(String)
        Date.parse(value)
      when type <= Date && value.is_a?(Integer)
        Date.parse(value.to_s)
      else
        raise TypeError, "can't convert `#{value}:#{value.class}` to `#{type}`"
      end
    end
def coerce(value, opts={})
      raise ArgumentError, "Needs option :to => Class/Module" unless opts.has_key?(:to) && ( opts[:to].is_a?(Class) || opts[:to].is_a?(Module) )
      type = opts[:to]

      case
      # Direct conversions
      when type <= String   then String(value)
      when type <= Boolean  then Boolean(value)
      when type == Bignum   then raise TypeError, "directly converting to Bignum is not supported, use Integer instead"
      when type <= Integer  then Integer(value)
      when type <= Float    then Float(value)
      when type <= Rational then Rational(value)
      when type <= Complex  then Complex(value)
      # Symbol
      when type <= Symbol && value.respond_to?(:to_sym)
        value.to_sym
      # Dates and Times
      when type <= Time && value.is_a?(Numeric)
        Time.at(value)
      when type <= Time && value.is_a?(String)
        DateTime.parse(value).new_offset(LOCAL_OFFSET/24).to_time
      when type <= DateTime && value.respond_to?(:to_datetime)
        value.to_datetime.new_offset(LOCAL_OFFSET/24)
      when type <= DateTime && value.is_a?(String)
        DateTime.parse(value).new_offset(LOCAL_OFFSET/24)
      when type <= DateTime && value.is_a?(Integer)
        DateTime.parse(value.to_s).new_offset(LOCAL_OFFSET/24)
      # Important: DateTime < Date so the order in this case statement matters
      when type <= Date && value.is_a?(String)
        Date.parse(value)
      when type <= Date && value.is_a?(Integer)
        Date.parse(value.to_s)
      else
        raise TypeError, "can't convert `#{value}:#{value.class}` to `#{type}`"
      end
    end
Coerce (convert) a value to some specified type

 @param [Object] value the value to coerce
 @param [Hash] opts the conversion options
 @option opts [Class, Module] :to the type to convert to

 @return [Object] the converted value into the specified type

 @example
   include StronglyTyped::Coercible

   coerce 100, to: Float   #=> 100.0
   coerce 100              #=> ArgumentError: Needs option :to => Class/Module
   coerce 100, to: String  #=> "100"
   coerce 100, to: Boolean #=> true
   coerce 100, to: Symbol  #=> TypeError: can't convert `100:Fixnum` to `Symbol`

 @raise [ArgumentError] if :to => Class option was not provided correctly
 @raise [TypeError] if unable to perform the coersion