Skip to content
This repository has been archived by the owner on Apr 17, 2018. It is now read-only.

Commit

Permalink
Use String#to_i for integer/float, and Integer() for octal/binary/hex
Browse files Browse the repository at this point in the history
* This represents a change in how we typecast values.  If the value
  does not match a format we know can be coerced into the object, then
  we skip typecasting and leave the value as-is.  If dm-validations is
  enabled, the value can be identified as invalid, but the original
  value is left alone by dm-core rather than turned into a nil.
  • Loading branch information
dkubb committed Jun 12, 2009
1 parent 0cd150e commit 14d1072
Show file tree
Hide file tree
Showing 2 changed files with 10 additions and 20 deletions.
23 changes: 6 additions & 17 deletions lib/dm-core/property.rb
Expand Up @@ -686,23 +686,12 @@ def typecast(value)
begin
# TODO: optimize this using a Hash lookup table
if primitive == Integer
# The simplest possible implementation, i.e. value.to_i, is not
# desirable because "junk".to_i gives "0". We want nil instead,
# because this makes it clear that the typecast failed.
#
# After benchmarking, we preferred the current implementation over
# these two alternatives:
# * Integer(value) rescue nil
# * Integer(value_to_s =~ /(\d+)/ ? $1 : value_to_s) rescue nil

# DB: I've reverted this to Integer(value), since the behavior
# DB: of Integer(value) is NOT the same as value.to_i, for example:
# Integer("0x24") == 36
# "0x24".to_i == 0
begin
Integer(value)
rescue
value.to_s =~ /^(0x|0b|0\.)?0+$/ ? 0 : nil
# only typecast a String that looks like a number
case value.to_s
when /\A((?:0|[1-9]\d*)(?:\.\d+)?)\z/ then $1.to_i # integer or float
when /\A(0(?:\d+|b[01]+|x[a-fA-F\d]+))\z/ then Integer($1) # octal, binary or hex
else
value
end
elsif primitive == String then value.to_s
elsif primitive == TrueClass then %w[ true 1 t ].include?(value.to_s.downcase)
Expand Down
7 changes: 4 additions & 3 deletions spec/public/property_spec.rb
Expand Up @@ -346,15 +346,16 @@ class ::Image
it { Image.properties[:width].typecast(0.0).should == 0 }
it { Image.properties[:width].typecast("0").should == 0 }
it { Image.properties[:width].typecast("0.0").should == 0 }
it { Image.properties[:width].typecast("00").should == 0 }
it { Image.properties[:width].typecast("0b0").should == 0 }
it { Image.properties[:width].typecast("0x0").should == 0 }
it { Image.properties[:width].typecast(BigDecimal("0.0")).should == 0 }
it { Image.properties[:width].typecast(Rational(0,1)).should == 0 }
end

describe "but value has non-digits and punctuation in it" do
it "returns result of property type's casting of nil" do
# nil.to_f => 0.0
Image.properties[:width].typecast("datamapper").should be_nil
it "returns value without typecasting" do
Image.properties[:width].typecast('datamapper').should == 'datamapper'
end
end
end
Expand Down

0 comments on commit 14d1072

Please sign in to comment.