lib/active_model/validations/numericality.rb in activemodel-7.0.8.6 vs lib/active_model/validations/numericality.rb in activemodel-7.1.0.beta1

- old
+ new

@@ -1,19 +1,21 @@ # frozen_string_literal: true require "active_model/validations/comparability" +require "active_model/validations/resolve_value" require "bigdecimal/util" module ActiveModel module Validations class NumericalityValidator < EachValidator # :nodoc: include Comparability + include ResolveValue RANGE_CHECKS = { in: :in? } NUMBER_CHECKS = { odd: :odd?, even: :even? } - RESERVED_OPTIONS = COMPARE_CHECKS.keys + NUMBER_CHECKS.keys + RANGE_CHECKS.keys + [:only_integer] + RESERVED_OPTIONS = COMPARE_CHECKS.keys + NUMBER_CHECKS.keys + RANGE_CHECKS.keys + [:only_integer, :only_numeric] INTEGER_REGEX = /\A[+-]?\d+\z/ HEXADECIMAL_REGEX = /\A[+-]?0[xX]/ @@ -62,11 +64,11 @@ end end private def option_as_number(record, option_value, precision, scale) - parse_as_number(option_value(record, option_value), precision, scale) + parse_as_number(resolve_value(record, option_value), precision, scale) end def parse_as_number(raw_value, precision, scale) if raw_value.is_a?(Float) parse_float(raw_value, precision, scale) @@ -88,10 +90,14 @@ def round(raw_value, scale) scale ? raw_value.round(scale) : raw_value end def is_number?(raw_value, precision, scale) + if options[:only_numeric] && !raw_value.is_a?(Numeric) + return false + end + !parse_as_number(raw_value, precision, scale).nil? rescue ArgumentError, TypeError false end @@ -108,18 +114,11 @@ filtered[:value] = value filtered end def allow_only_integer?(record) - case options[:only_integer] - when Symbol - record.send(options[:only_integer]) - when Proc - options[:only_integer].call(record) - else - options[:only_integer] - end + resolve_value(record, options[:only_integer]) end def prepare_value_for_validation(value, record, attr_name) return value if record_attribute_changed_in_place?(record, attr_name) @@ -147,40 +146,53 @@ end end module HelperMethods # Validates whether the value of the specified attribute is numeric by - # trying to convert it to a float with Kernel.Float (if <tt>only_integer</tt> - # is +false+) or applying it to the regular expression <tt>/\A[\+\-]?\d+\z/</tt> - # (if <tt>only_integer</tt> is set to +true+). Precision of Kernel.Float values - # are guaranteed up to 15 digits. + # trying to convert it to a float with +Kernel.Float+ (if + # <tt>only_integer</tt> is +false+) or applying it to the regular + # expression <tt>/\A[\+\-]?\d+\z/</tt> (if <tt>only_integer</tt> is set to + # +true+). Precision of +Kernel.Float+ values are guaranteed up to 15 + # digits. # # class Person < ActiveRecord::Base # validates_numericality_of :value, on: :create # end # # Configuration options: # * <tt>:message</tt> - A custom error message (default is: "is not a number"). # * <tt>:only_integer</tt> - Specifies whether the value has to be an # integer (default is +false+). + # * <tt>:only_numeric</tt> - Specifies whether the value has to be an + # instance of Numeric (default is +false+). The default behavior is to + # attempt parsing the value if it is a String. # * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+ (default is # +false+). Notice that for Integer and Float columns empty strings are # converted to +nil+. # * <tt>:greater_than</tt> - Specifies the value must be greater than the - # supplied value. + # supplied value. The default error message for this option is _"must be + # greater than %{count}"_. # * <tt>:greater_than_or_equal_to</tt> - Specifies the value must be - # greater than or equal the supplied value. + # greater than or equal the supplied value. The default error message + # for this option is _"must be greater than or equal to %{count}"_. # * <tt>:equal_to</tt> - Specifies the value must be equal to the supplied - # value. + # value. The default error message for this option is _"must be equal to + # %{count}"_. # * <tt>:less_than</tt> - Specifies the value must be less than the - # supplied value. + # supplied value. The default error message for this option is _"must be + # less than %{count}"_. # * <tt>:less_than_or_equal_to</tt> - Specifies the value must be less - # than or equal the supplied value. + # than or equal the supplied value. The default error message for this + # option is _"must be less than or equal to %{count}"_. # * <tt>:other_than</tt> - Specifies the value must be other than the - # supplied value. - # * <tt>:odd</tt> - Specifies the value must be an odd number. - # * <tt>:even</tt> - Specifies the value must be an even number. - # * <tt>:in</tt> - Check that the value is within a range. + # supplied value. The default error message for this option is _"must be + # other than %{count}"_. + # * <tt>:odd</tt> - Specifies the value must be an odd number. The default + # error message for this option is _"must be odd"_. + # * <tt>:even</tt> - Specifies the value must be an even number. The + # default error message for this option is _"must be even"_. + # * <tt>:in</tt> - Check that the value is within a range. The default + # error message for this option is _"must be in %{count}"_. # # There is also a list of default options supported by every validator: # +:if+, +:unless+, +:on+, +:allow_nil+, +:allow_blank+, and +:strict+ . # See ActiveModel::Validations::ClassMethods#validates for more information. #