Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow temperatures to work when the display name is changed #44

Merged
merged 1 commit into from May 26, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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