Class: Stick::Units::Converter

Inherits:
Object
  • Object
show all
Defined in:
lib/stick/units.rb,
lib/stick/currency.rb,
lib/stick/units/base.rb,
lib/stick/units/loaders.rb,
lib/stick/units/currency.rb

Overview

This class handles all conversions between units.

There are two kinds of units; those that are not expressed as a function of other units –called base units– and those that are expressed as a function of other units –called derived units. The latter kind is registered specifying how it depends on other units, while the former kind is not.

This class also registers a list of Converters that are generally useable. The default Converter which is used when none is specified, can be retrieved with Converter.current. Converters can be registered with Converter.register.

Converters can be loaded from YAML. This allows Converters to be specified in configuration files.

Defined Under Namespace

Classes: Conversion, ExchangeRate, ShiftedConversion

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name) ⇒ Converter

Creates a new Converter. If a block is given, it is executed in the newly created Converter’s context.



667
668
669
670
671
# File 'lib/stick/units/base.rb', line 667

def initialize(name)
  @conversions = {}
  @included = []
  @name = name
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(m, *args, &blk) ⇒ Object



728
729
730
731
732
733
734
735
736
# File 'lib/stick/units/base.rb', line 728

def method_missing(m, *args, &blk)
  if registered?(m)
    raise ::ArgumentError, "Wrong number of arguments" if args.length != 0
    return ::Stick::Units::Unit.new({m => 1}, self)
  end
  ::Exception.with_clean_backtrace("method_missing") {
    super
  }
end

Instance Attribute Details

#nameObject

Returns the name of this Converter, or nil if the Converter is not registered.



662
663
664
# File 'lib/stick/units/base.rb', line 662

def name
  @name
end

Class Method Details

.coerce_units(unit1, unit2) ⇒ Object

:nodoc:



906
907
908
# File 'lib/stick/units/base.rb', line 906

def coerce_units(unit1, unit2) # :nodoc:
  [convert_conversion(unit1.units), convert_conversion(unit2.units)]
end

.convert_conversion(units, multiplier = nil) ⇒ Object



915
916
917
918
919
920
921
922
923
924
925
926
927
# File 'lib/stick/units/base.rb', line 915

def convert_conversion(units, multiplier = nil)
  multiplier ||= 1
  base_units = {}
  other_units = {}
  units.each_pair do |u, e|
    (u.conversion != :none ? other_units : base_units)[u] = e
  end
  result = Conversion.new(::Stick::Units::Unit.new(base_units, self), multiplier)
  other_units.each_pair do |u, e|
    result *= (u.conversion ** e)
  end
  result
end

.converter(name, &blk) ⇒ Object

Returns the converter with the given name. This name can be a Symbol or a String.



880
881
882
883
884
885
886
# File 'lib/stick/units/base.rb', line 880

def converter(name, &blk)
  if blk
    (converters[name.to_sym] ||= new(name.to_sym)).instance_eval(&blk)
  else
    converters[name.to_sym] or raise ::ArgumentError, "No converter #{name.to_s.dump} found"
  end
end

.convertersObject



929
930
931
# File 'lib/stick/units/base.rb', line 929

def converters
  @converters ||= {}
end

.currentObject

Returns the current Converter in the current Thread. The default converter is the one returned by converter(:default). See also Stick::Units#with_converter and Converter.converter.



855
856
857
# File 'lib/stick/units/base.rb', line 855

def current
  Thread.current[:'Stick::Units::converter'] ||= converter(:default)
end

.register_loader(loader) ⇒ Object

def load(file)

  load_config(file, self)
end


49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/stick/units/loaders.rb', line 49

def register_loader(loader)
  loaders[loader] ||= loader
  loader.handles.each do |h|
    loader_hash[h] ||= begin
      eval %{
        module_eval do
          def #{h}(*a, &b)
            self.class.send(:loader_hash)[#{h.inspect}].#{h}(self, *a, &b)
          end
        end
      }
      loader
    end
  end
  @loader_hash
end

.registered_convertersObject

Returns the list of names of registered converters.



902
903
904
# File 'lib/stick/units/base.rb', line 902

def registered_converters
  converters.keys
end

.require(file) ⇒ Object



38
39
40
41
42
43
# File 'lib/stick/units/loaders.rb', line 38

def require(file)
  @required_configs[file] ||= begin
    load_config(file + ".rb", self)
    true
  end
end

.simplify_unit(unit) ⇒ Object

:nodoc:



910
911
912
913
# File 'lib/stick/units/base.rb', line 910

def simplify_unit(unit) # :nodoc:
  conv = convert_conversion(unit.units)
  [conv[:multiplier], conv[:units]]
end

.with_converter(conv) ⇒ Object

:nodoc:

Raises:

  • (::ArgumentError)


859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
# File 'lib/stick/units/base.rb', line 859

def with_converter(conv) # :nodoc:
  conv = converter(conv) if not conv.is_a? ::Stick::Units::Converter
  raise ::ArgumentError, "Converter expected" if not conv.is_a? ::Stick::Units::Converter
  begin
    old_conv = Thread.current[:'Stick::Units::converter']
    if old_conv
      new_conv = Converter.send(:new, nil)
      new_conv.include(old_conv)
      new_conv.include(conv)
    else
      new_conv = conv
    end
    Thread.current[:'Stick::Units::converter'] = new_conv
    yield
  ensure
    Thread.current[:'Stick::Units::converter'] = old_conv
  end
end

Instance Method Details

#base_unit(name) ⇒ Object

Returns the base unit with this name



715
716
717
718
719
720
# File 'lib/stick/units/base.rb', line 715

def base_unit(name)
  if conv = registered?(name)
    return ::Stick::Units::BaseUnit.new(name, conv)
  end
  raise "unit #{name.to_s.dump} not registered with #{self}"
end

#include(conv) ⇒ Object

Included the given converter in the receiver, unless it was already included.



675
676
677
678
679
680
# File 'lib/stick/units/base.rb', line 675

def include(conv)
  conv = ::Stick::Units::Converter.converter(conv) if not conv.is_a?(::Stick::Units::Converter)
  raise "Circular include" if conv.includes?(self)
  @included << conv if not includes? conv
  self
end

#included_converters(result = []) ⇒ Object

Returns the list of all included converters. This list may contain duplicates in some cases.



695
696
697
698
699
# File 'lib/stick/units/base.rb', line 695

def included_converters(result = [])
  result << self
  @included.reverse_each { |c| c.included_converters(result) }
  result
end

#includes?(conv) ⇒ Boolean

Returns whether the given converter was included in the receiver.

Returns:

  • (Boolean)


684
685
686
687
688
689
690
691
# File 'lib/stick/units/base.rb', line 684

def includes?(conv)
  conv = ::Stick::Units::Converter.converter(conv) if not conv.is_a?(::Stick::Units::Converter)
  return true if conv == self
  @included.each do |c|
    return true if conv == c || c.includes?(conv)
  end
  false
end

#load(file) ⇒ Object



83
84
85
# File 'lib/stick/units/loaders.rb', line 83

def load(file)
  self.class.send(:load_config, file, self)
end

#registered?(unit) ⇒ Boolean

Checks whether the unit with the given name is registered. The name can be a symbol or a string.

Returns:

  • (Boolean)


703
704
705
706
707
708
709
710
711
712
# File 'lib/stick/units/base.rb', line 703

def registered?(unit)
  unit = unit.to_sym
  return self if registered_here?(unit)
  @included.reverse_each do |c|
    if res = c.registered?(unit)
      return res
    end
  end
  nil
end

#registered_unitsObject

Returns the list of registered unit names as symbols.



723
724
725
# File 'lib/stick/units/base.rb', line 723

def registered_units
  @conversions.keys
end

#to_sObject Also known as: inspect

Returns a human readable string representation of this Converter.



739
740
741
# File 'lib/stick/units/base.rb', line 739

def to_s
  (@name.to_s if @name) || "#<Converter:#{object_id.to_s(16)}>"
end