Class: Myrrha::Coercions

Inherits:
Object show all
Defined in:
lib/myrrha/coercions.rb

Overview

Defines a set of coercion rules

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(&defn) ⇒ Coercions

Creates an empty list of coercion rules



13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/myrrha/coercions.rb', line 13

def initialize(&defn)
  @definitions = []
  @upons = []
  @rules = []
  @fallbacks = []
  @appender = :<<
  @main_target_domain = nil
  @error_handler = lambda{|value, target_domain, cause|
    raise Error.new("Unable to coerce `#{value}` to #{target_domain}", cause)
  }
  extend_rules(:<<, defn) if defn
end

Instance Attribute Details

#error_handlerProc

Returns the proc that handles coercion errors.

Returns:

  • (Proc)

    the proc that handles coercion errors



10
11
12
# File 'lib/myrrha/coercions.rb', line 10

def error_handler
  @error_handler
end

#main_target_domainDomain

Returns The main target domain, if any.

Returns:

  • (Domain)

    The main target domain, if any



7
8
9
# File 'lib/myrrha/coercions.rb', line 7

def main_target_domain
  @main_target_domain
end

Instance Method Details

#append(&proc) ⇒ Object

Appends the list of rules with new ones.

New upon, coercion and fallback rules will be put after the already existing ones, in each case.

Example:

rules = Myrrha.coercions do ... end
rules.append do |r|

  # [previous coercion rules would come here]

  # install new rules
  r.coercion String, Float, lambda{|v,t| Float(t)}
end


42
43
44
# File 'lib/myrrha/coercions.rb', line 42

def append(&proc)
  extend_rules(:<<, proc)
end

#coerce(value, target_domain = main_target_domain) ⇒ Object Also known as: apply

Coerces ‘value` to an element of `target_domain`

This method tries each coercion rule, then each fallback in turn. Rules for which source and target domain match are executed until one succeeds. A Myrrha::Error is raised if no rule matches or executes successfuly.

Parameters:

  • value (Object)

    any ruby value

  • target_domain (Domain) (defaults to: main_target_domain)

    a target domain to convert to (mimic Domain)

Returns:

  • self



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/myrrha/coercions.rb', line 170

def coerce(value, target_domain = main_target_domain)
  return value if belongs_to?(value, target_domain)
  error = nil
  each_rule do |from,to,converter|
    next unless from.nil? or belongs_to?(value, from, target_domain)
    begin
      catch(:nextrule) do
        if to.nil? or subdomain?(to, target_domain)
          got = convert(value, target_domain, converter)
          return got
        elsif subdomain?(target_domain, to)
          got = convert(value, target_domain, converter)
          return got if belongs_to?(got, target_domain)
        end
      end
    rescue => ex
      error = ex unless error
    end
  end
  error_handler.call(value, target_domain, error)
end

#coercion(source, target = main_target_domain, converter = nil, &convproc) ⇒ Object

Adds a coercion rule from a source to a target domain.

The conversion can be provided through ‘converter` or via a block directly. See main documentation about recognized converters.

Example:

Myrrha.coercions do |r|

  # With an explicit proc
  r.coercion String, Integer, lambda{|v,t|
    Integer(v)
  }

  # With an implicit proc
  r.coercion(String, Float) do |v,t|
    Float(v)
  end

end

Parameters:

  • source (Domain)

    a source domain (mimicing Domain)

  • target (Domain) (defaults to: main_target_domain)

    a target domain (mimicing Domain)

  • converter (Converter) (defaults to: nil)

    an optional converter (mimic Converter)

  • convproc (Proc)

    used when converter is not specified

Returns:

  • self



132
133
134
135
# File 'lib/myrrha/coercions.rb', line 132

def coercion(source, target = main_target_domain, converter = nil, &convproc)
  @rules.send(@appender, [source, target, converter || convproc])
  self
end

#delegate(method, &convproc) ⇒ Object

Adds an upon rule that works by delegation if the value responds to ‘method`.

Example:

Myrrha.coercions do |r|
  r.delegate(:to_foo)

  # is a shortcut for
  r.upon(lambda{|v,_| v.respond_to?(:to_foo)}){|v,_| v.to_foo}
end


100
101
102
103
# File 'lib/myrrha/coercions.rb', line 100

def delegate(method, &convproc)
  convproc ||= lambda{|v,t| v.send(method) }
  upon(lambda{|v,t| v.respond_to?(method) }, convproc)
end

#dupCoercions

Duplicates this set of rules in such a way that the original will not be affected by any change made to the copy.

Returns:

  • (Coercions)

    a copy of this set of rules



198
199
200
201
202
203
204
# File 'lib/myrrha/coercions.rb', line 198

def dup
  c = Coercions.new
  @definitions.each do |defn|
    c.extend_rules(*defn)
  end
  c
end

#fallback(source, converter = nil, &convproc) ⇒ Object

Adds a fallback rule for a source domain.

Example:

Myrrha.coercions do |r|

  # Add a 'last chance' rule for Strings
  r.fallback(String) do |v,t|
    # the user wants _v_ to be converted to a value of domain _t_
  end

end

Parameters:

  • source (Domain)

    a source domain (mimic Domain)

  • converter (Converter) (defaults to: nil)

    an optional converter (mimic Converter)

  • convproc (Proc)

    used when converter is not specified

Returns:

  • self



155
156
157
158
# File 'lib/myrrha/coercions.rb', line 155

def fallback(source, converter = nil, &convproc)
  @fallbacks.send(@appender, [source, nil, converter || convproc])
  self
end

#prepend(&proc) ⇒ Object

Prepends the list of rules with new ones.

New upon, coercion and fallback rules will be put before the already existing ones, in each case.

Example:

rules = Myrrha.coercions do ... end
rules.prepend do |r|

  # install new rules
  r.coercion String, Float, lambda{|v,t| Float(t)}

  # [previous coercion rules would come here]

end


63
64
65
# File 'lib/myrrha/coercions.rb', line 63

def prepend(&proc)
  extend_rules(:unshift, proc)
end

#upon(source, converter = nil, &convproc) ⇒ Object

Adds an upon rule for a source domain.

Example:

Myrrha.coercions do |r|

  # Don't even try something else on nil
  r.upon(NilClass){|s,t| nil}
  [...]

end

Parameters:

  • source (Domain)

    a source domain (mimic Domain)

  • converter (Converter) (defaults to: nil)

    an optional converter (mimic Converter)

  • convproc (Proc)

    used when converter is not specified

Returns:

  • self



84
85
86
87
# File 'lib/myrrha/coercions.rb', line 84

def upon(source, converter = nil, &convproc)
  @upons.send(@appender, [source, nil, converter || convproc])
  self
end