class Pulo::QuantityBuilder

Public Class Methods

build(name,&block) click to toggle source
# File lib/pulo/quantity/quantity_builder.rb, line 8
def self.build(name,&block)
  klass=Class.new(Quantity)
  Pulo.const_set(name,klass)
  QuantityBuilder.new(klass,&block)
end
new(klass,&block) click to toggle source
# File lib/pulo/quantity/quantity_builder.rb, line 14
def initialize(klass,&block)
  @klass=klass
  instance_eval(&block)
end

Public Instance Methods

klass() click to toggle source
# File lib/pulo/quantity/quantity_builder.rb, line 19
def klass
  @klass
end

Private Instance Methods

constant(name,symbol,unit,value) click to toggle source
# File lib/pulo/quantity/quantity_builder.rb, line 68
def constant(name,symbol,unit,value)
  @klass.define_singleton_method(name) do
    # noinspection RubyArgCount
    self.new value, self.units[unit]
  end
  unless symbol==''
    @klass.define_singleton_method(symbol) do
      # noinspection RubyArgCount
      self.new value, self.units[unit]
    end
  end
end
define_method_on_klass(klass,method, &block) click to toggle source
# File lib/pulo/quantity/quantity_builder.rb, line 25
def define_method_on_klass(klass,method, &block)
  klass.send :define_method, method, &block
end
define_unit_methods(unit) click to toggle source
# File lib/pulo/quantity/quantity_builder.rb, line 96
def define_unit_methods(unit)
  @klass.units.merge!({unit.name=>unit})

  #Class method for creating by unit name
  @klass.define_singleton_method("#{unit.name}") do |val|
    # noinspection RubyArgCount
    self.new val,unit
  end

  #Class method for creating by unit plural name
  unless unit.name.to_s==unit.plural
    @klass.define_singleton_method("#{unit.plural}") do |val|
      self.send(unit.name,val) #Could also be done as a method alias?
    end
  end

  #Class method for creating by unit abbreviated name
  unless unit.name.to_s==unit.abbreviation || unit.abbreviation==''
    @klass.define_singleton_method("#{unit.abbreviation}") do |val|
      self.send(unit.name,val) #Could also be done as a method alias?
    end
  end

  #Instance method for conversion to this unit by plural
  unless unit.name.to_s==unit.plural
    define_method_on_klass(@klass,"#{unit.plural}") do
      self.send(unit.name) #Could also be done as a method alias?
    end
  end

  #Instance method for conversion to this unit by abbreviation
  unless unit.name.to_s==unit.abbreviation || unit.abbreviation==''
    define_method_on_klass(@klass,"#{unit.abbreviation}") do
      self.send(unit.name) #Could also be done as a method alias?
    end
  end

  define_method_on_klass(@klass,"#{unit.name}") do
    #If its conversion to and from the same unit then just return self
    if self.unit.name==unit.name  ##TODO: Make == work for units
      return self
    end

    #Actual conversions depending on si or non-si from and to units
    case

      #si to si
      when self.unit.is_si? && unit.is_si?
        # noinspection RubyArgCount
        self.class.new self.value*10**(self.unit.scale-unit.scale),unit

      #si to non-si
      when self.unit.is_si? && !unit.is_si?
        to_unit=self.class.units[unit.name]
        if to_unit.si_convert_unit==self.unit.name
          intermediate_si=self
        else
          intermediate_si=self.send(to_unit.si_convert_unit)
        end
        # noinspection RubyArgCount
        self.class.new intermediate_si.value*to_unit.si_convert_factor,unit

      #non-si to si
      when !self.unit.is_si? && unit.is_si?
        # noinspection RubyArgCount
        intermediate_si=self.class.new self.value/self.unit.si_convert_factor,self.class.units[self.unit.si_convert_unit]
        if intermediate_si.unit==unit
          intermediate_si
        else
          intermediate_si.send(unit.name)
        end

      #non-si to non-si
      else
        #get the destination non-si unit definition
        to_unit=self.class.units[unit.name]

        #first convert self to si
        intermediate_si=self.send(self.unit.si_convert_unit)

        #then convert this si to the si 'partner' of the destination unit
        intermediate_si2=intermediate_si.send(to_unit.si_convert_unit)

        #lastly convert this to the final required non-si
        intermediate_si2.send(to_unit.name)
    end
  end
end
dimensions(*dims) click to toggle source
# File lib/pulo/quantity/quantity_builder.rb, line 29
def dimensions(*dims)
  #Create a dimensions object based on the supplied specification and set it on the new class
  spec=Dimension.new(dims[0])
  @klass.dimensions=spec

  if Pulo.quantities[spec]
    #If a quantity has already been defined with this set of dimensions

    Pulo.quantities[spec].each do |quan_klass|
      #for each of the other quantities with the same dimensions
      # define a method on them with the name of this quantity
      quan_klass.instance_exec(@klass) do |other_klass|
        define_method other_klass.quantity_name.downcase do
          other_unit=other_klass.si_unit_scales[self.unit.scale]
          other_unit=other_klass.best_si_unit(Math.log10(self.value)+self.unit.scale) unless other_unit
          return other_klass.new(self.value*10**(self.unit.scale-other_unit.scale),other_unit)
        end
      end

      #and define a method on us for the reverse
      define_method_on_klass @klass, quan_klass.quantity_name.downcase do
        other_unit=quan_klass.si_unit_scales[self.unit.scale]
        other_unit=quan_klass.best_si_unit(Math.log10(self.value)+self.unit.scale) unless other_unit
        return quan_klass.new(self.value*10**(self.unit.scale-other_unit.scale),other_unit)
      end
    end
    Pulo.quantities[spec] << @klass
  else
    Pulo.quantities.merge!({spec=>[@klass]})
  end
end
non_si_unit(name,plural,abbreviation,si_convert_unit,si_convert_factor) click to toggle source
# File lib/pulo/quantity/quantity_builder.rb, line 91
def non_si_unit(name,plural,abbreviation,si_convert_unit,si_convert_factor)
  unit=NonSI_Unit.new(name,plural, abbreviation, si_convert_unit, si_convert_factor)
  define_unit_methods unit
end
si_unit(name,plural,abbreviation,scale) click to toggle source
# File lib/pulo/quantity/quantity_builder.rb, line 81
def si_unit(name,plural,abbreviation,scale)
  scale=Math.log10(scale)
  unit=SI_Unit.new(name,plural, abbreviation,scale)
  if scale==0
    @klass.base_unit=unit
  end
  define_unit_methods unit
  @klass.si_unit_scales.merge!({scale=>unit})
end
synonyms(*synonyms) click to toggle source
# File lib/pulo/quantity/quantity_builder.rb, line 61
def synonyms(*synonyms)
  synonyms.each do |synonym|
    @klass.synonyms << synonym
    Pulo.const_set(synonym,@klass.clone)
  end
end