Skip to content
Browse files

Validate floats properly, so they are not forced to have scale defined.

  • Loading branch information...
1 parent 56e697f commit 0ee0f36491dd4df9b88a10cb1a2aca43814472fa @mayo mayo committed Jul 21, 2008
View
17 dm-validations/lib/dm-validations/numeric_validator.rb
@@ -28,7 +28,16 @@ def call(target)
error_message ||= '%s must be an integer'.t(Extlib::Inflection.humanize(@field_name))
else
# FIXME: if precision and scale are not specified, can we assume that it is an integer?
+ # probably not, as floating point numbers don't have hard
+ # defined scale. the scale floats with the length of the
+ # integral and precision. Ie. if precision = 10 and integral
+ # portion of the number is 9834 (4 digits), the max scale will
+ # be 6 (10 - 4). But if the integral length is 1, max scale
+ # will be (10 - 1) = 9, so 1.234567890.
+ # In MySQL somehow you can hard-define scale on floats. Not
+ # quite sure how that works...
if precision && scale
+ #handles both Float when it has scale specified and BigDecimal
if precision > scale && scale > 0
return true if value =~ /\A[+-]?(?:\d{1,#{precision - scale}}|\d{0,#{precision - scale}}\.\d{1,#{scale}})\z/
elsif precision > scale && scale == 0
@@ -38,6 +47,14 @@ def call(target)
else
raise ArgumentError, "Invalid precision #{precision.inspect} and scale #{scale.inspect} for #{field_name} (value: #{value.inspect} #{value.class})"
end
+ elsif precision && scale.nil?
+ # for floats, if scale is not set
+
+ #total number of digits is less or equal precision
+ return true if value.gsub(/[^\d]/,'').length <= precision
+
+ #number of digits before decimal == precision, and the number is x.0. same as scale = 0
+ return true if value =~ /\A[+-]?(?:\d{1,#{precision}}(?:\.0)?)\z/
else
return true if value =~ /\A[+-]?(?:\d+|\d*\.\d+)\z/
end
View
50 dm-validations/spec/integration/numeric_validator_spec.rb
@@ -65,12 +65,56 @@ class Fish
describe 'Float' do
describe 'with default precision and scale' do
before :all do
- class RobotFish < Fish
+ class CloudFish < Fish
property :average_weight, Float
end
end
before do
+ @cloud_fish = CloudFish.new
+ end
+
+ it 'should allow up to 10 digits before the decimal' do
+ @cloud_fish.average_weight = 0
+ @cloud_fish.should be_valid
+
+ @cloud_fish.average_weight = 9_999_999_999
+ @cloud_fish.should be_valid
+
+ @cloud_fish.average_weight = 10_000_000_000
+ @cloud_fish.should_not be_valid
+ end
+
+ it 'should allow 0 digits after the decimal' do
+ @cloud_fish.average_weight = 0
+ @cloud_fish.should be_valid
+ end
+
+ it 'should allow any digits after the decimal' do
+ @cloud_fish.average_weight = 1.2
+ @cloud_fish.should be_valid
+
+ @cloud_fish.average_weight = 123.456
+ @cloud_fish.should be_valid
+ end
+
+ it "should only allow up to 10 digits overall" do
+ @cloud_fish.average_weight = 1.234567890
+ @cloud_fish.should be_valid
+
+ @cloud_fish.average_weight = 1.2345678901
+ @cloud_fish.should_not be_valid
+ end
+ end
+
+ describe 'with default precision and scaleof 0' do
+ before :all do
+ class RobotFish < Fish
+ property :average_weight, Float, :scale => 0
+ end
+ end
+
+ before do
@robot_fish = RobotFish.new
end
@@ -112,6 +156,10 @@ class GoldFish < Fish
before do
@gold_fish = GoldFish.new
end
+
+ it "should have scale of 2" do
+ @gold_fish.model.average_weight.scale.should == 2
+ end
it 'should allow up to 2 digits before the decimal' do
@gold_fish.average_weight = 0

0 comments on commit 0ee0f36

Please sign in to comment.
Something went wrong with that request. Please try again.