Thursday, August 13, 2009

Ruby DSL: define_unit

module TinyUnits
  def self.define_unit(name, quantity, *aliases)
    Numeric.module_eval do
      define_method(name) { self * quantity }
      aliases.each { |ali| alias_method ali, name }
    end
    define_method(name) { |x| x / quantity }
    aliases.each do |ali|
      alias_method ali, name
      module_function ali
    end
    module_function name
  end
  private_class_method :define_unit
  
  define_unit :cm, 0.01
  define_unit :mm, 0.1.cm
  define_unit :inch, 2.54.cm, :in
  define_unit :feet, 12.inch, :ft
  define_unit :yard, 3.feet
  define_unit :mile, 1760.yard
end

1.cm # => 0.01
2.mm # => 0.002
3.ft # => 0.9144
4.mile # => 6437.376
tall = 6.ft + 2.in # => 1.8796

include TinyUnits
cm(tall) # => 187.96

No comments: