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.