Module: Myrrha

Defined in:
lib/myrrha.rb,
lib/myrrha/coerce.rb,
lib/myrrha/errors.rb,
lib/myrrha/version.rb,
lib/myrrha/coercions.rb,
lib/myrrha/to_ruby_literal.rb

Overview

Myrrha – the missing coercion framework for Ruby

Defined Under Namespace

Modules: Version Classes: Coercions, Error

Constant Summary collapse

OPTIONS =

Myrrha main options

{
  :core_ext => false
}
Boolean =
Domain.union(TrueClass, FalseClass)
Coerce =

Defines basic coercions for Ruby, mostly from String

coercions do |g|

  # Returns a constant denoted by `s`
  def g.constant_lookup(s, target_domain)
    found = (s.split('::') - [""]).inject(Kernel){|cur,n|
      cur.const_get(n.to_sym)
    }
    belongs_to?(found, target_domain) ? found : throw(:nextrule)
  end

  # NilClass should return immediately
  g.upon(NilClass) do |s,t|
    nil
  end

  # Use t.coerce if it exists
  g.upon(lambda{|s,t| t.respond_to?(:coerce)}) do |s,t|
    t.coerce(s)
  end

  # Specific basic rules
  g.coercion Object,  String, lambda{|s,t| String(s)                     }
  g.coercion String, Integer, lambda{|s,t| Integer(s)                    }
  g.coercion String,   Float, lambda{|s,t| Float(s)                      }
  g.coercion String, Boolean, lambda{|s,t| Boolean(s)                    }
  g.coercion Integer,  Float, lambda{|s,t| Float(s)                      }
  g.coercion String,  Symbol, lambda{|s,t| s.to_sym                      }
  g.coercion String,  Regexp, lambda{|s,t| Regexp.compile(s)             }
  g.coercion Symbol,   Class, lambda{|s,t| g.constant_lookup(s.to_s, t)  }
  g.coercion Symbol,  Module, lambda{|s,t| g.constant_lookup(s.to_s, t)  }
  g.coercion String,   Class, lambda{|s,t| g.constant_lookup(s, t)       }
  g.coercion String,  Module, lambda{|s,t| g.constant_lookup(s, t)       }
  g.coercion String,    Time, lambda{|s,t| Time.parse(s)                 }
  g.coercion Time,  DateTime, lambda{|s,t| DateTime.parse(s.iso8601)     }

  # By default, we try to invoke :parse on the class
  g.fallback(String) do |s,t|
    t.respond_to?(:parse) ? t.parse(s.to_str) : throw(:nextrule)
  end

end
VERSION =
Version.to_s
TO_RUBY_THROUGH_INSPECT =

These are all classes for which using inspect is safe for to_ruby_literal

[ NilClass, TrueClass, FalseClass, 
Fixnum, Bignum, Float, 
String, Symbol, Class, Module, Regexp ]
ToRubyLiteral =

Defines basic coercions for implementing to_ruby_literal

coercions do |r|
  r.main_target_domain = :to_ruby_literal
  
  r.upon(Object) do |s,t|
    s.to_ruby_literal{ throw :nextrule }
  end
  
  # On safe .inspect 
  safe = lambda{|x,_| TO_RUBY_THROUGH_INSPECT.include?(x.class)}
  r.coercion(safe) do |s,t| 
    s.inspect
  end
  
  # Best-effort on Range or let it be marshalled
  r.coercion(Range) do |s,t|
    (TO_RUBY_THROUGH_INSPECT.include?(s.first.class) &&
     TO_RUBY_THROUGH_INSPECT.include?(s.last.class)) ?
      s.inspect : throw(:nextrule)
  end
  
  # Be friendly on array
  r.coercion(Array) do |s,t|
    "[" + s.collect{|v| r.apply(v)}.join(', ') + "]"
  end
  
  # As well as on Hash
  r.coercion(Hash) do |s,t|
    "{" + s.collect{|k,v| 
      r.apply(k) + " => " + r.apply(v) 
    }.join(', ') + "}"
  end
  
  # Use Marshal by default
  r.fallback(Object) do |s,t| 
    "Marshal.load(#{Marshal.dump(s).inspect})"
  end
  
end

Class Method Summary collapse

Class Method Details

.Boolean(s) ⇒ Boolean

Coerces s to a Boolean

This method mimics Ruby’s Integer(), Float(), etc. for Boolean values.

Parameters:

  • s (Object)

    a Boolean or a String

Returns:

  • (Boolean)

    true if ‘s` is already true of the string ’true’, false if ‘s` is already false of the string ’false’.

Raises:

  • (ArgumentError)

    if ‘s` cannot be coerced to a boolean.



15
16
17
18
19
20
21
22
23
# File 'lib/myrrha/coerce.rb', line 15

def self.Boolean(s)
  if (s==true || s.to_str.strip == "true")
    true
  elsif (s==false || s.to_str.strip == "false")
    false
  else
    raise ArgumentError, "invalid value for Boolean: \"#{s}\""
  end
end

.coerce(value, domain) ⇒ Object

Coerce



68
69
70
# File 'lib/myrrha/coerce.rb', line 68

def self.coerce(value, domain)
  Coerce.apply(value, domain)
end

.coercions(&block) ⇒ Object

Builds a set of coercions rules.

Example:

rules = Myrrha.coercions do |c|
  c.coercion String, Integer, lambda{|s,t| Integer(s)}
  #
  # [...]
  #
  c.fallback String, lambda{|s,t| ... }
end


25
26
27
# File 'lib/myrrha.rb', line 25

def self.coercions(&block)
  Coercions.new(&block)
end

.core_ext?Boolean

Install core extensions?

Returns:



35
36
37
# File 'lib/myrrha.rb', line 35

def self.core_ext?
  OPTIONS[:core_ext]
end

.to_ruby_literal(value = self) ⇒ String

Converts ‘value` to a ruby literal

Parameters:

  • value (Object) (defaults to: self)

    any ruby value

Returns:

  • (String)

    a representation ‘s` of `value` such that Kernel.eval(s) == value is true



56
57
58
59
60
# File 'lib/myrrha/to_ruby_literal.rb', line 56

def self.to_ruby_literal(value = self)
  block_given? ? 
    yield : 
    ToRubyLiteral.apply(value)
end