Class: Mixture::Coerce::Base

Inherits:
Object
  • Object
show all
Includes:
Singleton
Defined in:
lib/mixture/coerce/base.rb

Overview

The base for coercion actions. Each action defines the "from" type, and the instance handles the "to".

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.coerce_to(to) {|value, type| ... } ⇒ void .coerce_to(to, value) ⇒ void

This is a DSL for the class itself. It essentially defines a method to perform the coercion of the given type.

Overloads:

  • .coerce_to(to) {|value, type| ... } ⇒ void

    This method returns an undefined value.

    This is a DSL for the class itself. It essentially defines a method to perform the coercion of the given type.

    Parameters:

    Yields:

    • (value, type)

      The block is called with the value to coerce when coercion needs to happen. Note that the block is not used as the body of the method - the method returns the block.

    Yield Parameters:

    Yield Returns:

    • (Object)

      The coerced value.

  • .coerce_to(to, value) ⇒ void

    This method returns an undefined value.

    This is a DSL for the class itself. It essentially defines a method to perform the coercion of the given type.

    Parameters:

    • to (Mixture::Types::Type)

      The type to coerce to.

    • value (Proc, Symbol)

      The block that is called with the value for coercion. This block is returned by the defined coercion method. If it's a symbol, it's turned into a block. Note that this doesn't use Symbol#to_proc; it uses a similar block that ignores the excess paramters.


85
86
87
88
89
90
91
92
# File 'lib/mixture/coerce/base.rb', line 85

def self.coerce_to(to, data = Undefined, &block)
  fail ArgumentError, "Expected Mixture::Types::Type, got #{to}" unless
    to <= Mixture::Types::Type

  body = data_block(data, &block)
  coercions[to] = to.options[:method]
  define_method(to.options[:method]) { body }
end

.coercionsHash{Mixture::Type => Symbol}

The coercions that this class has. It's a map of the type to the method that performs that coercion.

Returns:


33
34
35
# File 'lib/mixture/coerce/base.rb', line 33

def self.coercions
  @_coercions ||= ThreadSafe::Hash.new
end

.data_block(data, &block) ⇒ void

This method returns an undefined value.

Turns a data/block given to coerce_to into a block worthy of a body for a method.

Parameters:

  • data (Proc, Symbol)

    A proc/symbol to be used for a method.


103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/mixture/coerce/base.rb', line 103

def self.data_block(data, &block)
  case
  when data.is_a?(::Symbol)
    proc { |value| value.public_send(data) }
  when data.is_a?(::Proc)
    data
  when block_given?
    block
  else
    fail ArgumentError, "Expected a block, got #{data.inspect}"
  end
end

.inherited(base) ⇒ void

This method returns an undefined value.

This is a method that's called by ruby interally. We're going to use it to hook into the coercions, to allow a class coercion.

Parameters:

  • base (Class)

    A subclass.


43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/mixture/coerce/base.rb', line 43

def self.inherited(base)
  super # for Singleton
  base.coerce_to(Types::Class) do |value, type|
    member = type.options.fetch(:members).first
    if member.respond_to?(:coerce) then member.coerce(value)
    elsif member.respond_to?(:new) then member.new(value)
    else
      fail CoercionError, "Expected #{member} to " \
           "respond to #coerce, #new"
    end
  end
end

.to(type) ⇒ Proc{(Object) => Object}

Returns a block to perform the coercion to the given type. If it cannot find a coercion, it raises Mixture::CoercionError.

Parameters:

  • type (Mixture::Type)

    The type to coerce to.

Returns:

Raises:


117
118
119
# File 'lib/mixture/coerce/base.rb', line 117

def self.to(type)
  instance.to(type)
end

.typeMixture::Type .type(value) ⇒ void

Overloads:

  • .typeMixture::Type

    Returns the type this instance corresponds to.

    Returns:

    • (Mixture::Type)
  • .type(value) ⇒ void

    This method returns an undefined value.

    Sets the type this instance corresponds to.

    Parameters:

    • value (Mixture::Type)

21
22
23
24
25
26
27
# File 'lib/mixture/coerce/base.rb', line 21

def self.type(value = Undefined)
  if value == Undefined
    @_type
  else
    @_type = value
  end
end

Instance Method Details

#to(type) ⇒ Proc{(Object) => Object}

Returns a block to perform the coercion to the given type. If it cannot find a coercion, it raises Mixture::CoercionError.

Parameters:

  • type (Mixture::Type)

    The type to coerce to.

Returns:

Raises:


127
128
129
130
131
132
133
134
135
# File 'lib/mixture/coerce/base.rb', line 127

def to(type)
  coercions = self.class.coercions
  coercable = type.inheritable
              .find { |ancestor| coercions.key?(ancestor) }
  fail CoercionError, "Undefined coercion #{self.class.type} " \
    "=> #{type}" unless coercable

  public_send(coercions[coercable])
end