Permalink
Browse files

Merge pull request #44 from twalpole/temperature_Fixes

allow temperatures to work when the display name is changed
  • Loading branch information...
2 parents 74692a5 + 1a59caf commit 52ee0939f1c8907027df3351837ec829eb9d8491 @olbrich committed May 26, 2012
Showing with 121 additions and 18 deletions.
  1. +27 −18 lib/ruby_units/unit.rb
  2. +94 −0 spec/ruby-units/temperature_spec.rb
View
@@ -59,8 +59,7 @@ class Unit < Numeric
FAHRENHEIT = ['<fahrenheit>']
RANKINE = ['<rankine>']
CELSIUS = ['<celsius>']
- TEMP_REGEX = /(?:temp|deg)[CFRK]/
-
+ @@TEMP_REGEX = nil
SIGNATURE_VECTOR = [
:length,
:time,
@@ -191,7 +190,7 @@ def self.define(unit_definition, &block)
Unit.use_definition(unit_definition)
return unit_definition
end
-
+
# @param [String] name Name of unit to redefine
# @param [Block] block
# @raise [ArgumentError] if a block is not given
@@ -370,11 +369,11 @@ def initialize(*options)
unary_unit = self.units || ""
if options.first.instance_of?(String)
opt_scalar, opt_units = Unit.parse_into_numbers_and_units(options[0])
- unless @@cached_units.keys.include?(opt_units) || (opt_units =~ /(#{TEMP_REGEX})|(pounds|lbs[ ,]\d+ ounces|oz)|('\d+")|(ft|feet[ ,]\d+ in|inch|inches)|%|(#{TIME_REGEX})|i\s?(.+)?|&plusmn;|\+\/-/)
+ unless @@cached_units.keys.include?(opt_units) || (opt_units =~ /(#{Unit.temp_regex})|(pounds|lbs[ ,]\d+ ounces|oz)|('\d+")|(ft|feet[ ,]\d+ in|inch|inches)|%|(#{TIME_REGEX})|i\s?(.+)?|&plusmn;|\+\/-/)
@@cached_units[opt_units] = (self.scalar == 1 ? self : opt_units.unit) if opt_units && !opt_units.empty?
end
end
- unless @@cached_units.keys.include?(unary_unit) || (unary_unit =~ /#{TEMP_REGEX}/) then
+ unless @@cached_units.keys.include?(unary_unit) || (unary_unit =~ /#{Unit.temp_regex}/) then
@@cached_units[unary_unit] = (self.scalar == 1 ? self : unary_unit.unit)
end
[@scalar, @numerator, @denominator, @base_scalar, @signature, @is_base].each {|x| x.freeze}
@@ -441,7 +440,7 @@ def is_base?
# @todo this is brittle as it depends on the display_name of a unit, which can be changed
def to_base
return self if self.is_base?
- if self.units =~ /\A(?:temp|deg)[CRF]\Z/
+ if @@UNIT_MAP[self.units] =~ /\A<(?:temp|deg)[CRF]>\Z/
if RUBY_VERSION < "1.9"
# :nocov_19:
@signature = @@KINDS.index(:temperature)
@@ -563,7 +562,7 @@ def inspect(option=nil)
# @return [Boolean]
# @todo use unit definition to determine if it's a temperature instead of a regex
def is_temperature?
- return self.is_degree? && (!(self.units =~ /temp[CFRK]/).nil?)
+ return self.is_degree? && (!(@@UNIT_MAP[self.units] =~ /temp[CFRK]/).nil?)
end
alias :temperature? :is_temperature?
@@ -579,7 +578,7 @@ def is_degree?
# @return [String] possible values: degC, degF, degR, or degK
def temperature_scale
return nil unless self.is_temperature?
- return "deg#{self.units[/temp([CFRK])/,1]}"
+ return "deg#{@@UNIT_MAP[self.units][/temp([CFRK])/,1]}"
end
# returns true if no associated units
@@ -946,25 +945,25 @@ def convert_to(other)
start_unit = self.units
target_unit = other.units rescue other
unless @base_scalar
- @base_scalar = case start_unit
- when 'tempC'
+ @base_scalar = case @@UNIT_MAP[start_unit]
+ when '<tempC>'
@scalar + 273.15
- when 'tempK'
+ when '<tempK>'
@scalar
- when 'tempF'
+ when '<tempF>'
(@scalar+459.67)*Rational(5,9)
- when 'tempR'
+ when '<tempR>'
@scalar*Rational(5,9)
end
end
- q= case target_unit
- when 'tempC'
+ q= case @@UNIT_MAP[target_unit]
+ when '<tempC>'
@base_scalar - 273.15
- when 'tempK'
+ when '<tempK>'
@base_scalar
- when 'tempF'
+ when '<tempF>'
@base_scalar * Rational(9,5) - 459.67
- when 'tempR'
+ when '<tempR>'
@base_scalar * Rational(9,5)
end
return Unit.new("#{q} #{target_unit}")
@@ -1537,10 +1536,20 @@ def self.prefix_regex
return @@PREFIX_REGEX ||= @@PREFIX_MAP.keys.sort_by {|prefix| [prefix.length, prefix]}.reverse.join('|')
end
+ def self.temp_regex
+ @@TEMP_REGEX ||= Regexp.new "(?:#{
+ temp_units=%w(tempK tempC tempF tempR degK degC degF degR)
+ aliases=temp_units.map{|unit| d=Unit.definition(unit); d && d.aliases}.flatten.compact
+ regex_str= aliases.empty? ? '(?!x)x' : aliases.join('|')
+ regex_str
+ })"
+ end
+
# inject a definition into the internal array and set it up for use
# @private
def self.use_definition(definition)
@@UNIT_MATCH_REGEX = nil #invalidate the unit match regex
+ @@TEMP_REGEX = nil #invalidate the temp regex
if definition.prefix?
@@PREFIX_VALUES[definition.name] = definition.scalar
definition.aliases.each {|_alias| @@PREFIX_MAP[_alias] = definition.name }
@@ -0,0 +1,94 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+
+describe 'temperatures' do
+ describe 'redfine display name' do
+ before(:all) do
+ Unit.redefine!("tempC") do |c|
+ c.aliases = %w{tC tempC}
+ c.display_name = "tC"
+ end
+
+ Unit.redefine!("tempF") do |f|
+ f.aliases = %w{tF tempF}
+ f.display_name = "tF"
+ end
+
+ Unit.redefine!("tempR") do |f|
+ f.aliases = %w{tR tempR}
+ f.display_name = "tR"
+ end
+
+ Unit.redefine!("tempK") do |f|
+ f.aliases = %w{tK tempK}
+ f.display_name = "tK"
+ end
+ end
+
+ after(:all) do
+ #define the temp units back to normal
+ Unit.define("tempK") do |unit|
+ unit.scalar = 1
+ unit.numerator = %w{<tempK>}
+ unit.aliases = %w{tempK}
+ unit.kind = :temperature
+ end
+
+ Unit.define('tempC') do |tempC|
+ tempC.definition = Unit('1 tempK')
+ end
+
+ temp_convert_factor = Rational(2501999792983609,4503599627370496) # approximates 1/1.8
+
+ Unit.define('tempF') do |tempF|
+ tempF.definition = Unit(temp_convert_factor, 'tempK')
+ end
+
+ Unit.define('tempR') do |tempR|
+ tempR.definition = Unit('1 tempF')
+ end
+ end
+
+ describe "Unit('100 tC')" do
+ subject {Unit("100 tC")}
+ its(:scalar) {should be_within(0.001).of 100}
+ its(:units) {should == "tC"}
+ its(:kind) {should == :temperature}
+ it {should be_temperature}
+ it {should be_degree}
+ it {should_not be_base}
+ it {should_not be_unitless}
+ it {should_not be_zero}
+ its(:base) {should be_within(Unit("0.01 degK")).of Unit("373.15 tempK")}
+ its(:temperature_scale) {should == "degC"}
+ end
+
+ context "between temperature scales" do
+ # note that 'temp' units are for temperature readings on a scale, while 'deg' units are used to represent
+ # differences between temperatures, offsets, or other differential temperatures.
+
+ specify { Unit("100 tC").should be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) }
+ specify { Unit("0 tC").should be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) }
+ specify { Unit("37 tC").should be_within(Unit("0.01 degK")).of(Unit("310.15 tempK"))}
+ specify { Unit("-273.15 tC").should == Unit("0 tempK") }
+
+ specify { Unit("212 tF").should be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) }
+ specify { Unit("32 tF").should be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) }
+ specify { Unit("98.6 tF").should be_within(Unit("0.01 degK")).of(Unit("310.15 tempK"))}
+ specify { Unit("-459.67 tF").should == Unit("0 tempK") }
+
+ specify { Unit("671.67 tR").should be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) }
+ specify { Unit("491.67 tR").should be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) }
+ specify { Unit("558.27 tR").should be_within(Unit("0.01 degK")).of(Unit("310.15 tempK"))}
+ specify { Unit("0 tR").should == Unit("0 tempK") }
+
+ specify { Unit("100 tK").convert_to("tempC").should be_within(U"0.01 degC").of(Unit("-173.15 tempC"))}
+ specify { Unit("100 tK").convert_to("tempF").should be_within(U"0.01 degF").of(Unit("-279.67 tempF"))}
+ specify { Unit("100 tK").convert_to("tempR").should be_within(U"0.01 degR").of(Unit("180 tempR"))}
+ end
+
+
+
+
+ end
+end
+

0 comments on commit 52ee093

Please sign in to comment.