lib/active_model/validations/numericality.rb in activemodel-5.2.2.1 vs lib/active_model/validations/numericality.rb in activemodel-5.2.3.rc1

- old
+ new

@@ -1,16 +1,20 @@ # frozen_string_literal: true +require "bigdecimal/util" + module ActiveModel module Validations class NumericalityValidator < EachValidator # :nodoc: CHECKS = { greater_than: :>, greater_than_or_equal_to: :>=, equal_to: :==, less_than: :<, less_than_or_equal_to: :<=, odd: :odd?, even: :even?, other_than: :!= }.freeze RESERVED_OPTIONS = CHECKS.keys + [:only_integer] + INTEGER_REGEX = /\A[+-]?\d+\z/ + def check_validity! keys = CHECKS.keys - [:odd, :even] options.slice(*keys).each do |option, value| unless value.is_a?(Numeric) || value.is_a?(Proc) || value.is_a?(Symbol) raise ArgumentError, ":#{option} must be a number, a symbol or a proc" @@ -47,15 +51,11 @@ if allow_only_integer?(record) && !is_integer?(raw_value) record.errors.add(attr_name, :not_an_integer, filtered_options(raw_value)) return end - if raw_value.is_a?(Numeric) - value = raw_value - else - value = parse_raw_value_as_a_number(raw_value) - end + value = parse_as_number(raw_value) options.slice(*CHECKS.keys).each do |option, option_value| case option when :odd, :even unless value.to_i.send(CHECKS[option]) @@ -67,35 +67,44 @@ option_value = option_value.call(record) when Symbol option_value = record.send(option_value) end + option_value = parse_as_number(option_value) + unless value.send(CHECKS[option], option_value) record.errors.add(attr_name, option, filtered_options(value).merge!(count: option_value)) end end end end private def is_number?(raw_value) - !parse_raw_value_as_a_number(raw_value).nil? + !parse_as_number(raw_value).nil? rescue ArgumentError, TypeError false end - def parse_raw_value_as_a_number(raw_value) - return raw_value.to_i if is_integer?(raw_value) - Kernel.Float(raw_value) unless is_hexadecimal_literal?(raw_value) + def parse_as_number(raw_value) + if raw_value.is_a?(Float) + raw_value.to_d + elsif raw_value.is_a?(Numeric) + raw_value + elsif is_integer?(raw_value) + raw_value.to_i + elsif !is_hexadecimal_literal?(raw_value) + Kernel.Float(raw_value).to_d + end end def is_integer?(raw_value) - /\A[+-]?\d+\z/ === raw_value.to_s + INTEGER_REGEX === raw_value.to_s end def is_hexadecimal_literal?(raw_value) - /\A0[xX]/ === raw_value + /\A0[xX]/ === raw_value.to_s end def filtered_options(value) filtered = options.except(*RESERVED_OPTIONS) filtered[:value] = value