Module: StronglyTyped::Coercible

Defined in:
lib/strongly_typed/coercible.rb

Constant Summary collapse

LOCAL_OFFSET =
Float(Time.now.gmt_offset) / Float(3600)

Instance Method Summary collapse

Instance Method Details

#coerce(value, opts = {}) ⇒ Object

Coerce (convert) a value to some specified type

Examples:

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`

Parameters:

  • value (Object)

    the value to coerce

  • opts (Hash) (defaults to: {})

    the conversion options

Options Hash (opts):

  • :to (Class, Module)

    the type to convert to

Returns:

  • (Object)

    the converted value into the specified type

Raises:

  • (ArgumentError)

    if :to => Class option was not provided correctly

  • (TypeError)

    if unable to perform the coersion



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/strongly_typed/coercible.rb', line 27

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