Object
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.
Load conversion units.
Load conversion units.
def load(file)
load_config(file, self)
end
# File lib/van/units/loaders.rb, line 49
49: def register_loader(loader)
50: loaders[loader] ||= loader
51: loader.handles.each do |h|
52: loader_hash[h] ||= begin
53: eval %{
54: module_eval do
55: def #{h}(*a, &b)
56: self.class.send(:loader_hash)[#{h.inspect}].#{h}(self, *a, &b)
57: end
58: end
59: }
60: loader
61: end
62: end
63: @loader_hash
64: end
# File lib/van/units/base.rb, line 924
924: def convert_conversion(units, multiplier = nil)
925: multiplier ||= 1
926: base_units = {}
927: other_units = {}
928: units.each_pair do |u, e|
929: (u.conversion != :none ? other_units : base_units)[u] = e
930: end
931: result = Conversion.new(Units::Unit.new(base_units, self), multiplier)
932: other_units.each_pair do |u, e|
933: result *= (u.conversion ** e)
934: end
935: result
936: end
Returns the converter with the given name. This name can be a Symbol or a String.
# File lib/van/units/base.rb, line 889
889: def converter(name, &blk)
890: if blk
891: (converters[name.to_sym] ||= new(name.to_sym)).instance_eval(&blk)
892: else
893: converters[name.to_sym] or raise ::ArgumentError, "No converter #{name.to_s.dump} found"
894: end
895: end
# File lib/van/units/base.rb, line 938
938: def converters
939: @converters ||= {}
940: end
Returns the current Converter in the current Thread. The default converter is the one returned by converter(:default). See also Units#with_converter and Converter.converter.
# File lib/van/units/base.rb, line 864
864: def current
865: Thread.current[THREAD_REFERENCE] ||= converter(:default)
866: end
# File lib/van/units/loaders.rb, line 76
76: def load_config(file, context)
77: data = File.read(File.join(Units::Config::CONFIGDIR, file)) rescue File.read(file)
78: context.instance_eval { eval data, nil, file }
79: end
# File lib/van/units/loaders.rb, line 72
72: def loader_hash
73: @loader_hash ||= {}
74: end
# File lib/van/units/loaders.rb, line 68
68: def loaders
69: @loaders ||= {}
70: end
Creates a new Converter. If a block is given, it is executed in the newly created Converter’s context.
# File lib/van/units/base.rb, line 668
668: def initialize(name)
669: @conversions = {}
670: @included = []
671: @name = name
672: end
Returns the base unit with this name
# File lib/van/units/base.rb, line 716
716: def base_unit(name)
717: if conv = registered?(name)
718: return Units::BaseUnit.new(name, conv)
719: end
720: raise "unit #{name.to_s.dump} not registered with #{self}"
721: end
Included the given converter in the receiver, unless it was already included.
# File lib/van/units/base.rb, line 676
676: def include(conv)
677: conv = Units::Converter.converter(conv) if not conv.is_a?(Units::Converter)
678: raise "Circular include" if conv.includes?(self)
679: @included << conv if not includes? conv
680: self
681: end
Returns the list of all included converters. This list may contain duplicates in some cases.
# File lib/van/units/base.rb, line 696
696: def included_converters(result = [])
697: result << self
698: @included.reverse_each { |c| c.included_converters(result) }
699: result
700: end
Returns whether the given converter was included in the receiver.
# File lib/van/units/base.rb, line 685
685: def includes?(conv)
686: conv = Units::Converter.converter(conv) if not conv.is_a?(Units::Converter)
687: return true if conv == self
688: @included.each do |c|
689: return true if conv == c || c.includes?(conv)
690: end
691: false
692: end
# File lib/van/units/loaders.rb, line 83
83: def load(file)
84: self.class.send(:load_config, file, self)
85: end
# File lib/van/units/base.rb, line 729
729: def method_missing(m, *args, &blk)
730: if registered?(m)
731: raise ::ArgumentError, "Wrong number of arguments" if args.length != 0
732: return Units::Unit.new({m => 1}, self)
733: end
734: ::Exception.with_clean_backtrace("method_missing") {
735: super
736: }
737: end
Checks whether the unit with the given name is registered. The name can be a symbol or a string.
# File lib/van/units/base.rb, line 704
704: def registered?(unit)
705: unit = unit.to_sym
706: return self if registered_here?(unit)
707: @included.reverse_each do |c|
708: if res = c.registered?(unit)
709: return res
710: end
711: end
712: nil
713: end
# File lib/van/units/base.rb, line 851
851: def conversions(unit)
852: @conversions[unit] #|| (unit == :'--base-currency--' ? :none : nil)
853: end
# File lib/van/units/currency.rb, line 147
147: def conversions(unit)
148: @conversions[unit] || (unit == '--base-currency--'.to_sym ? :none : nil)
149: end
# File lib/van/units/base.rb, line 824
824: def decode_conversion(data)
825: if not data.is_a? ::String
826: return {:unit => data[:unit] || data['unit'],
827: :multiplier => data[:multiplier] || data['multiplier']}
828: end
829: if /^\s*1\s*\// =~ data
830: {:unit => Units::Unit.new(data, self)}
831: elsif m = /^\s*#{Units::Regexps::NUMBER_REGEXP}(?:\s+(\S.*)$|\s*$)/.match(data)
832: unit = m[3] ? Units::Unit.new(m[3], self) : Units::Unit.new({}, self)
833: if m[1]
834: multiplier = m[2].empty? ? Integer(m[1]) : Float(m[1])
835: {:unit => unit, :multiplier => multiplier}
836: else
837: {:unit => unit}
838: end
839: else
840: {:unit => Units::Unit.new(data, self)}
841: end
842: end
# File lib/van/units/base.rb, line 796
796: def register_prefixed_unit(unit, prefixes, abbrevs=[], aliases=[], &conversion)
797: unit = unit.to_s
798: abbrevs = [abbrevs].flatten.map{ |a| a.to_s }
799: aliases = [aliases].flatten.map{ |a| a.to_s }
800: aliases = ["#{unit}s"] if aliases.empty?
801: #aliases, abbrevs = extract_data(unit, data, :to_s)
802: register_unit(unit, abbrevs, aliases, &conversion)
803: unit_sym = unit.to_sym
804: prefixes.each_pair do |pre,info|
805: abbrev = info[:abbrev]
806: multiplier = info[:multiplier] || 1
807: power = info[:power] || 1
808: register_unit(pre + unit) do
809: {:unit => Units::Unit.new({unit_sym => power}, self), :multiplier => multiplier}
810: end
811: aliases.each do |a|
812: register_unit(pre + a) do
813: {:unit => Units::Unit.new({unit_sym => power}, self), :multiplier => multiplier}
814: end
815: end
816: abbrevs.each do |a|
817: register_unit(abbrev + a) do
818: {:unit => Units::Unit.new({unit_sym => power}, self), :multiplier => multiplier}
819: end
820: end
821: end
822: end
Registers a new Unit with the given name. The data parameter is a Hash with some extra parameters (can be Strings or Symbols):
| alias | Specifies possible aliases for the Unit. |
| abbrev | Specifies possible abbreviations or symbols for the Unit. The differences with aliases is that prefixes work differently; see register_si_unit, register_binary_unit and register_binary_iec_unit. |
| equals | If present, specifies how the Unit depends on other units. The value for this key can either be a Hash with unit mapping to a Unit and multiplier mapping to a numeric multiplier, or a String containing the multiplier, followed by a space, followed by a representation of the Unit as returned by Unit#to_s. |
Examples:
converter.register_unit(:pint, :alias => :pints, :abbrev => [:pt, :pts]))
converter.register_unit(:quart, 'alias' => :quarts, :abbrev => ['qt', :qts], :equals => '2.0 pt'))
converter.register_unit(:gallon, :alias => :gallons, :abbrev => :gal, 'equals' => {:unit => Unit.new('qt' => 1, converter), 'multiplier' => 4.0))
Note that Symbols and Strings are generally exchangeable within this library (internally they are converted to Symbols). The number one reason for this is that String look better in YAML.
See also register_si_unit, register_binary_unit, register_binary_iec_unit, register_length_unit, and register_currency in currency.rb.
# File lib/van/units/base.rb, line 773
773: def register_unit(unit, abbrevs=[], aliases=[], &conversion)
774: unit = unit.to_sym
775: abbrevs = [abbrevs].flatten.map{ |a| a.to_sym }
776: aliases = [aliases].flatten.map{ |a| a.to_sym }
777: #aliases = ["#{unit}s".to_sym] if aliases.empty? # TRANS: hmm... not here?
778: #unit, aliases, abbrevs = extract_data(name, data, :to_sym)
779: #conversion = data[:equals]
780: # TRANS: this can be imporved now that conversion is a block?
781: conversion = conversion.call if conversion
782: conversion = decode_conversion(conversion) if conversion
783: conversion = self.class.convert_conversion(conversion[:unit].units, conversion[:multiplier]) if conversion
784: register_unit_internal(unit, conversion)
785: conversion = self.class.convert_conversion({base_unit(unit) => 1}, 1) if not conversion
786: (aliases + abbrevs).each do |u|
787: register_unit_internal(u, conversion)
788: end
789: end
# File lib/van/units/base.rb, line 791
791: def register_unit_internal(unit, conversion)
792: raise "unit #{unit.to_s.dump} already registered with #{self}" if registered_here? unit
793: @conversions[unit] = conversion || :none
794: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.