Skip to content

Commit

Permalink
Merge pull request olbrich#44 from twalpole/temperature_Fixes
Browse files Browse the repository at this point in the history
allow temperatures to work when the display name is changed
  • Loading branch information
olbrich committed May 26, 2012
2 parents 74692a5 + 1a59caf commit 52ee093
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 18 deletions.
45 changes: 27 additions & 18 deletions lib/ruby_units/unit.rb
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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}
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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?

Expand All @@ -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
Expand Down Expand Up @@ -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}")
Expand Down Expand Up @@ -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 }
Expand Down
94 changes: 94 additions & 0 deletions spec/ruby-units/temperature_spec.rb
@@ -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.