activemodel 7.0.5 → 7.1.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/CHANGELOG.md +158 -123
 - data/MIT-LICENSE +1 -1
 - data/README.rdoc +11 -11
 - data/lib/active_model/access.rb +16 -0
 - data/lib/active_model/api.rb +5 -5
 - data/lib/active_model/attribute/user_provided_default.rb +4 -0
 - data/lib/active_model/attribute.rb +26 -1
 - data/lib/active_model/attribute_assignment.rb +1 -1
 - data/lib/active_model/attribute_methods.rb +103 -64
 - data/lib/active_model/attribute_registration.rb +77 -0
 - data/lib/active_model/attribute_set.rb +10 -1
 - data/lib/active_model/attributes.rb +62 -45
 - data/lib/active_model/callbacks.rb +5 -5
 - data/lib/active_model/conversion.rb +14 -4
 - data/lib/active_model/deprecator.rb +7 -0
 - data/lib/active_model/dirty.rb +134 -13
 - data/lib/active_model/error.rb +5 -4
 - data/lib/active_model/errors.rb +37 -6
 - data/lib/active_model/forbidden_attributes_protection.rb +2 -0
 - data/lib/active_model/gem_version.rb +4 -4
 - data/lib/active_model/lint.rb +1 -1
 - data/lib/active_model/locale/en.yml +1 -0
 - data/lib/active_model/model.rb +34 -2
 - data/lib/active_model/naming.rb +29 -10
 - data/lib/active_model/railtie.rb +4 -0
 - data/lib/active_model/secure_password.rb +61 -23
 - data/lib/active_model/serialization.rb +3 -3
 - data/lib/active_model/serializers/json.rb +1 -1
 - data/lib/active_model/translation.rb +18 -16
 - data/lib/active_model/type/big_integer.rb +23 -1
 - data/lib/active_model/type/binary.rb +10 -2
 - data/lib/active_model/type/boolean.rb +11 -9
 - data/lib/active_model/type/date.rb +28 -2
 - data/lib/active_model/type/date_time.rb +45 -3
 - data/lib/active_model/type/decimal.rb +39 -1
 - data/lib/active_model/type/float.rb +30 -1
 - data/lib/active_model/type/helpers/accepts_multiparameter_time.rb +5 -1
 - data/lib/active_model/type/helpers/mutable.rb +4 -4
 - data/lib/active_model/type/helpers/numeric.rb +6 -1
 - data/lib/active_model/type/helpers/time_value.rb +28 -12
 - data/lib/active_model/type/immutable_string.rb +37 -1
 - data/lib/active_model/type/integer.rb +44 -1
 - data/lib/active_model/type/serialize_cast_value.rb +47 -0
 - data/lib/active_model/type/string.rb +9 -1
 - data/lib/active_model/type/time.rb +48 -7
 - data/lib/active_model/type/value.rb +23 -3
 - data/lib/active_model/type.rb +1 -0
 - data/lib/active_model/validations/absence.rb +1 -1
 - data/lib/active_model/validations/acceptance.rb +1 -1
 - data/lib/active_model/validations/callbacks.rb +4 -4
 - data/lib/active_model/validations/clusivity.rb +5 -8
 - data/lib/active_model/validations/comparability.rb +0 -11
 - data/lib/active_model/validations/comparison.rb +15 -7
 - data/lib/active_model/validations/format.rb +6 -7
 - data/lib/active_model/validations/length.rb +10 -8
 - data/lib/active_model/validations/numericality.rb +35 -23
 - data/lib/active_model/validations/presence.rb +1 -1
 - data/lib/active_model/validations/resolve_value.rb +26 -0
 - data/lib/active_model/validations/validates.rb +4 -4
 - data/lib/active_model/validations/with.rb +9 -2
 - data/lib/active_model/validations.rb +44 -9
 - data/lib/active_model/validator.rb +7 -5
 - data/lib/active_model/version.rb +1 -1
 - data/lib/active_model.rb +5 -1
 - metadata +16 -11
 
| 
         @@ -16,8 +16,8 @@ module ActiveModel 
     | 
|
| 
       16 
16 
     | 
    
         | 
| 
       17 
17 
     | 
    
         
             
                module ClassMethods
         
     | 
| 
       18 
18 
     | 
    
         
             
                  # Adds methods to set and authenticate against a BCrypt password.
         
     | 
| 
       19 
     | 
    
         
            -
                  # This mechanism requires you to have a +XXX_digest+ attribute 
     | 
| 
       20 
     | 
    
         
            -
                  #  
     | 
| 
      
 19 
     | 
    
         
            +
                  # This mechanism requires you to have a +XXX_digest+ attribute,
         
     | 
| 
      
 20 
     | 
    
         
            +
                  # where +XXX+ is the attribute name of your desired password.
         
     | 
| 
       21 
21 
     | 
    
         
             
                  #
         
     | 
| 
       22 
22 
     | 
    
         
             
                  # The following validations are added automatically:
         
     | 
| 
       23 
23 
     | 
    
         
             
                  # * Password must be present on creation
         
     | 
| 
         @@ -29,10 +29,17 @@ module ActiveModel 
     | 
|
| 
       29 
29 
     | 
    
         
             
                  # it). When this attribute has a +nil+ value, the validation will not be
         
     | 
| 
       30 
30 
     | 
    
         
             
                  # triggered.
         
     | 
| 
       31 
31 
     | 
    
         
             
                  #
         
     | 
| 
       32 
     | 
    
         
            -
                  #  
     | 
| 
       33 
     | 
    
         
            -
                  #  
     | 
| 
      
 32 
     | 
    
         
            +
                  # Additionally, a +XXX_challenge+ attribute is created. When set to a
         
     | 
| 
      
 33 
     | 
    
         
            +
                  # value other than +nil+, it will validate against the currently persisted
         
     | 
| 
      
 34 
     | 
    
         
            +
                  # password. This validation relies on dirty tracking, as provided by
         
     | 
| 
      
 35 
     | 
    
         
            +
                  # ActiveModel::Dirty; if dirty tracking methods are not defined, this
         
     | 
| 
      
 36 
     | 
    
         
            +
                  # validation will fail.
         
     | 
| 
       34 
37 
     | 
    
         
             
                  #
         
     | 
| 
       35 
     | 
    
         
            -
                  #  
     | 
| 
      
 38 
     | 
    
         
            +
                  # All of the above validations can be omitted by passing
         
     | 
| 
      
 39 
     | 
    
         
            +
                  # <tt>validations: false</tt> as an argument. This allows complete
         
     | 
| 
      
 40 
     | 
    
         
            +
                  # customizability of validation behavior.
         
     | 
| 
      
 41 
     | 
    
         
            +
                  #
         
     | 
| 
      
 42 
     | 
    
         
            +
                  # To use +has_secure_password+, add bcrypt (~> 3.1.7) to your Gemfile:
         
     | 
| 
       36 
43 
     | 
    
         
             
                  #
         
     | 
| 
       37 
44 
     | 
    
         
             
                  #   gem 'bcrypt', '~> 3.1.7'
         
     | 
| 
       38 
45 
     | 
    
         
             
                  #
         
     | 
| 
         @@ -46,20 +53,30 @@ module ActiveModel 
     | 
|
| 
       46 
53 
     | 
    
         
             
                  #     has_secure_password :recovery_password, validations: false
         
     | 
| 
       47 
54 
     | 
    
         
             
                  #   end
         
     | 
| 
       48 
55 
     | 
    
         
             
                  #
         
     | 
| 
       49 
     | 
    
         
            -
                  #   user = User.new(name:  
     | 
| 
       50 
     | 
    
         
            -
                  # 
     | 
| 
       51 
     | 
    
         
            -
                  #   user.password  
     | 
| 
       52 
     | 
    
         
            -
                  #   user. 
     | 
| 
       53 
     | 
    
         
            -
                  #   user. 
     | 
| 
       54 
     | 
    
         
            -
                  #   user. 
     | 
| 
      
 56 
     | 
    
         
            +
                  #   user = User.new(name: "david", password: "", password_confirmation: "nomatch")
         
     | 
| 
      
 57 
     | 
    
         
            +
                  #
         
     | 
| 
      
 58 
     | 
    
         
            +
                  #   user.save                                                      # => false, password required
         
     | 
| 
      
 59 
     | 
    
         
            +
                  #   user.password = "vr00m"
         
     | 
| 
      
 60 
     | 
    
         
            +
                  #   user.save                                                      # => false, confirmation doesn't match
         
     | 
| 
      
 61 
     | 
    
         
            +
                  #   user.password_confirmation = "vr00m"
         
     | 
| 
      
 62 
     | 
    
         
            +
                  #   user.save                                                      # => true
         
     | 
| 
      
 63 
     | 
    
         
            +
                  #
         
     | 
| 
      
 64 
     | 
    
         
            +
                  #   user.authenticate("notright")                                  # => false
         
     | 
| 
      
 65 
     | 
    
         
            +
                  #   user.authenticate("vr00m")                                     # => user
         
     | 
| 
      
 66 
     | 
    
         
            +
                  #   User.find_by(name: "david")&.authenticate("notright")          # => false
         
     | 
| 
      
 67 
     | 
    
         
            +
                  #   User.find_by(name: "david")&.authenticate("vr00m")             # => user
         
     | 
| 
      
 68 
     | 
    
         
            +
                  #
         
     | 
| 
       55 
69 
     | 
    
         
             
                  #   user.recovery_password = "42password"
         
     | 
| 
       56 
     | 
    
         
            -
                  #   user.recovery_password_digest 
     | 
| 
       57 
     | 
    
         
            -
                  #   user.save 
     | 
| 
       58 
     | 
    
         
            -
                  # 
     | 
| 
       59 
     | 
    
         
            -
                  #   user. 
     | 
| 
       60 
     | 
    
         
            -
                  # 
     | 
| 
       61 
     | 
    
         
            -
                  #    
     | 
| 
       62 
     | 
    
         
            -
                  #    
     | 
| 
      
 70 
     | 
    
         
            +
                  #   user.recovery_password_digest                                  # => "$2a$04$iOfhwahFymCs5weB3BNH/uXkTG65HR.qpW.bNhEjFP3ftli3o5DQC"
         
     | 
| 
      
 71 
     | 
    
         
            +
                  #   user.save                                                      # => true
         
     | 
| 
      
 72 
     | 
    
         
            +
                  #
         
     | 
| 
      
 73 
     | 
    
         
            +
                  #   user.authenticate_recovery_password("42password")              # => user
         
     | 
| 
      
 74 
     | 
    
         
            +
                  #
         
     | 
| 
      
 75 
     | 
    
         
            +
                  #   user.update(password: "pwn3d", password_challenge: "")         # => false, challenge doesn't authenticate
         
     | 
| 
      
 76 
     | 
    
         
            +
                  #   user.update(password: "nohack4u", password_challenge: "vr00m") # => true
         
     | 
| 
      
 77 
     | 
    
         
            +
                  #
         
     | 
| 
      
 78 
     | 
    
         
            +
                  #   user.authenticate("vr00m")                                     # => false, old password
         
     | 
| 
      
 79 
     | 
    
         
            +
                  #   user.authenticate("nohack4u")                                  # => user
         
     | 
| 
       63 
80 
     | 
    
         
             
                  #
         
     | 
| 
       64 
81 
     | 
    
         
             
                  # ===== Conditionally requiring a password
         
     | 
| 
       65 
82 
     | 
    
         
             
                  #
         
     | 
| 
         @@ -88,7 +105,7 @@ module ActiveModel 
     | 
|
| 
       88 
105 
     | 
    
         
             
                    begin
         
     | 
| 
       89 
106 
     | 
    
         
             
                      require "bcrypt"
         
     | 
| 
       90 
107 
     | 
    
         
             
                    rescue LoadError
         
     | 
| 
       91 
     | 
    
         
            -
                       
     | 
| 
      
 108 
     | 
    
         
            +
                      warn "You don't have bcrypt installed in your application. Please add it to your Gemfile and run bundle install."
         
     | 
| 
       92 
109 
     | 
    
         
             
                      raise
         
     | 
| 
       93 
110 
     | 
    
         
             
                    end
         
     | 
| 
       94 
111 
     | 
    
         | 
| 
         @@ -105,7 +122,24 @@ module ActiveModel 
     | 
|
| 
       105 
122 
     | 
    
         
             
                        record.errors.add(attribute, :blank) unless record.public_send("#{attribute}_digest").present?
         
     | 
| 
       106 
123 
     | 
    
         
             
                      end
         
     | 
| 
       107 
124 
     | 
    
         | 
| 
       108 
     | 
    
         
            -
                       
     | 
| 
      
 125 
     | 
    
         
            +
                      validate do |record|
         
     | 
| 
      
 126 
     | 
    
         
            +
                        if challenge = record.public_send(:"#{attribute}_challenge")
         
     | 
| 
      
 127 
     | 
    
         
            +
                          digest_was = record.public_send(:"#{attribute}_digest_was") if record.respond_to?(:"#{attribute}_digest_was")
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
                          unless digest_was.present? && BCrypt::Password.new(digest_was).is_password?(challenge)
         
     | 
| 
      
 130 
     | 
    
         
            +
                            record.errors.add(:"#{attribute}_challenge")
         
     | 
| 
      
 131 
     | 
    
         
            +
                          end
         
     | 
| 
      
 132 
     | 
    
         
            +
                        end
         
     | 
| 
      
 133 
     | 
    
         
            +
                      end
         
     | 
| 
      
 134 
     | 
    
         
            +
             
     | 
| 
      
 135 
     | 
    
         
            +
                      # Validates that the password does not exceed the maximum allowed bytes for BCrypt (72 bytes).
         
     | 
| 
      
 136 
     | 
    
         
            +
                      validate do |record|
         
     | 
| 
      
 137 
     | 
    
         
            +
                        password_value = record.public_send(attribute)
         
     | 
| 
      
 138 
     | 
    
         
            +
                        if password_value.present? && password_value.bytesize > ActiveModel::SecurePassword::MAX_PASSWORD_LENGTH_ALLOWED
         
     | 
| 
      
 139 
     | 
    
         
            +
                          record.errors.add(attribute, :password_too_long)
         
     | 
| 
      
 140 
     | 
    
         
            +
                        end
         
     | 
| 
      
 141 
     | 
    
         
            +
                      end
         
     | 
| 
      
 142 
     | 
    
         
            +
             
     | 
| 
       109 
143 
     | 
    
         
             
                      validates_confirmation_of attribute, allow_blank: true
         
     | 
| 
       110 
144 
     | 
    
         
             
                    end
         
     | 
| 
       111 
145 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -126,9 +160,7 @@ module ActiveModel 
     | 
|
| 
       126 
160 
     | 
    
         
             
                      end
         
     | 
| 
       127 
161 
     | 
    
         
             
                    end
         
     | 
| 
       128 
162 
     | 
    
         | 
| 
       129 
     | 
    
         
            -
                     
     | 
| 
       130 
     | 
    
         
            -
                      instance_variable_set("@#{attribute}_confirmation", unencrypted_password)
         
     | 
| 
       131 
     | 
    
         
            -
                    end
         
     | 
| 
      
 163 
     | 
    
         
            +
                    attr_accessor :"#{attribute}_confirmation", :"#{attribute}_challenge"
         
     | 
| 
       132 
164 
     | 
    
         | 
| 
       133 
165 
     | 
    
         
             
                    # Returns +self+ if the password is correct, otherwise +false+.
         
     | 
| 
       134 
166 
     | 
    
         
             
                    #
         
     | 
| 
         @@ -145,6 +177,12 @@ module ActiveModel 
     | 
|
| 
       145 
177 
     | 
    
         
             
                      attribute_digest.present? && BCrypt::Password.new(attribute_digest).is_password?(unencrypted_password) && self
         
     | 
| 
       146 
178 
     | 
    
         
             
                    end
         
     | 
| 
       147 
179 
     | 
    
         | 
| 
      
 180 
     | 
    
         
            +
                    # Returns the salt, a small chunk of random data added to the password before it's hashed.
         
     | 
| 
      
 181 
     | 
    
         
            +
                    define_method("#{attribute}_salt") do
         
     | 
| 
      
 182 
     | 
    
         
            +
                      attribute_digest = public_send("#{attribute}_digest")
         
     | 
| 
      
 183 
     | 
    
         
            +
                      attribute_digest.present? ? BCrypt::Password.new(attribute_digest).salt : nil
         
     | 
| 
      
 184 
     | 
    
         
            +
                    end
         
     | 
| 
      
 185 
     | 
    
         
            +
             
     | 
| 
       148 
186 
     | 
    
         
             
                    alias_method :authenticate, :authenticate_password if attribute == :password
         
     | 
| 
       149 
187 
     | 
    
         
             
                  end
         
     | 
| 
       150 
188 
     | 
    
         
             
                end
         
     | 
| 
         @@ -3,7 +3,7 @@ 
     | 
|
| 
       3 
3 
     | 
    
         
             
            require "active_support/core_ext/enumerable"
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
            module ActiveModel
         
     | 
| 
       6 
     | 
    
         
            -
              #  
     | 
| 
      
 6 
     | 
    
         
            +
              # = Active \Model \Serialization
         
     | 
| 
       7 
7 
     | 
    
         
             
              #
         
     | 
| 
       8 
8 
     | 
    
         
             
              # Provides a basic serialization to a serializable_hash for your objects.
         
     | 
| 
       9 
9 
     | 
    
         
             
              #
         
     | 
| 
         @@ -33,8 +33,8 @@ module ActiveModel 
     | 
|
| 
       33 
33 
     | 
    
         
             
              # at the private method +read_attribute_for_serialization+.
         
     | 
| 
       34 
34 
     | 
    
         
             
              #
         
     | 
| 
       35 
35 
     | 
    
         
             
              # ActiveModel::Serializers::JSON module automatically includes
         
     | 
| 
       36 
     | 
    
         
            -
              # the  
     | 
| 
       37 
     | 
    
         
            -
              # explicitly include  
     | 
| 
      
 36 
     | 
    
         
            +
              # the +ActiveModel::Serialization+ module, so there is no need to
         
     | 
| 
      
 37 
     | 
    
         
            +
              # explicitly include +ActiveModel::Serialization+.
         
     | 
| 
       38 
38 
     | 
    
         
             
              #
         
     | 
| 
       39 
39 
     | 
    
         
             
              # A minimal implementation including JSON would be:
         
     | 
| 
       40 
40 
     | 
    
         
             
              #
         
     | 
| 
         @@ -1,9 +1,9 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            module ActiveModel
         
     | 
| 
       4 
     | 
    
         
            -
              #  
     | 
| 
      
 4 
     | 
    
         
            +
              # = Active \Model \Translation
         
     | 
| 
       5 
5 
     | 
    
         
             
              #
         
     | 
| 
       6 
     | 
    
         
            -
              # Provides integration between your object and the Rails internationalization
         
     | 
| 
      
 6 
     | 
    
         
            +
              # Provides integration between your object and the \Rails internationalization
         
     | 
| 
       7 
7 
     | 
    
         
             
              # (i18n) framework.
         
     | 
| 
       8 
8 
     | 
    
         
             
              #
         
     | 
| 
       9 
9 
     | 
    
         
             
              # A minimal implementation could be:
         
     | 
| 
         @@ -16,7 +16,7 @@ module ActiveModel 
     | 
|
| 
       16 
16 
     | 
    
         
             
              #   # => "My attribute"
         
     | 
| 
       17 
17 
     | 
    
         
             
              #
         
     | 
| 
       18 
18 
     | 
    
         
             
              # This also provides the required class methods for hooking into the
         
     | 
| 
       19 
     | 
    
         
            -
              # Rails internationalization API, including being able to define a
         
     | 
| 
      
 19 
     | 
    
         
            +
              # \Rails internationalization API, including being able to define a
         
     | 
| 
       20 
20 
     | 
    
         
             
              # class-based +i18n_scope+ and +lookup_ancestors+ to find translations in
         
     | 
| 
       21 
21 
     | 
    
         
             
              # parent classes.
         
     | 
| 
       22 
22 
     | 
    
         
             
              module Translation
         
     | 
| 
         @@ -35,6 +35,8 @@ module ActiveModel 
     | 
|
| 
       35 
35 
     | 
    
         
             
                  ancestors.select { |x| x.respond_to?(:model_name) }
         
     | 
| 
       36 
36 
     | 
    
         
             
                end
         
     | 
| 
       37 
37 
     | 
    
         | 
| 
      
 38 
     | 
    
         
            +
                MISSING_TRANSLATION = -(2**60) # :nodoc:
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
       38 
40 
     | 
    
         
             
                # Transforms attribute names into a more human format, such as "First name"
         
     | 
| 
       39 
41 
     | 
    
         
             
                # instead of "first_name".
         
     | 
| 
       40 
42 
     | 
    
         
             
                #
         
     | 
| 
         @@ -42,29 +44,29 @@ module ActiveModel 
     | 
|
| 
       42 
44 
     | 
    
         
             
                #
         
     | 
| 
       43 
45 
     | 
    
         
             
                # Specify +options+ with additional translating options.
         
     | 
| 
       44 
46 
     | 
    
         
             
                def human_attribute_name(attribute, options = {})
         
     | 
| 
       45 
     | 
    
         
            -
                   
     | 
| 
       46 
     | 
    
         
            -
             
     | 
| 
       47 
     | 
    
         
            -
                  attribute 
     | 
| 
       48 
     | 
    
         
            -
             
     | 
| 
       49 
     | 
    
         
            -
             
     | 
| 
      
 47 
     | 
    
         
            +
                  attribute = attribute.to_s
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                  if attribute.include?(".")
         
     | 
| 
      
 50 
     | 
    
         
            +
                    namespace, _, attribute = attribute.rpartition(".")
         
     | 
| 
      
 51 
     | 
    
         
            +
                    namespace.tr!(".", "/")
         
     | 
| 
       50 
52 
     | 
    
         | 
| 
       51 
     | 
    
         
            -
                  if namespace
         
     | 
| 
       52 
53 
     | 
    
         
             
                    defaults = lookup_ancestors.map do |klass|
         
     | 
| 
       53 
     | 
    
         
            -
                      :"#{ 
     | 
| 
      
 54 
     | 
    
         
            +
                      :"#{i18n_scope}.attributes.#{klass.model_name.i18n_key}/#{namespace}.#{attribute}"
         
     | 
| 
       54 
55 
     | 
    
         
             
                    end
         
     | 
| 
       55 
     | 
    
         
            -
                    defaults << :"#{ 
     | 
| 
      
 56 
     | 
    
         
            +
                    defaults << :"#{i18n_scope}.attributes.#{namespace}.#{attribute}"
         
     | 
| 
       56 
57 
     | 
    
         
             
                  else
         
     | 
| 
       57 
58 
     | 
    
         
             
                    defaults = lookup_ancestors.map do |klass|
         
     | 
| 
       58 
     | 
    
         
            -
                      :"#{ 
     | 
| 
      
 59 
     | 
    
         
            +
                      :"#{i18n_scope}.attributes.#{klass.model_name.i18n_key}.#{attribute}"
         
     | 
| 
       59 
60 
     | 
    
         
             
                    end
         
     | 
| 
       60 
61 
     | 
    
         
             
                  end
         
     | 
| 
       61 
62 
     | 
    
         | 
| 
       62 
63 
     | 
    
         
             
                  defaults << :"attributes.#{attribute}"
         
     | 
| 
       63 
     | 
    
         
            -
                  defaults << options 
     | 
| 
       64 
     | 
    
         
            -
                  defaults <<  
     | 
| 
      
 64 
     | 
    
         
            +
                  defaults << options[:default] if options[:default]
         
     | 
| 
      
 65 
     | 
    
         
            +
                  defaults << MISSING_TRANSLATION
         
     | 
| 
       65 
66 
     | 
    
         | 
| 
       66 
     | 
    
         
            -
                   
     | 
| 
       67 
     | 
    
         
            -
                   
     | 
| 
      
 67 
     | 
    
         
            +
                  translation = I18n.translate(defaults.shift, count: 1, **options, default: defaults)
         
     | 
| 
      
 68 
     | 
    
         
            +
                  translation = attribute.humanize if translation == MISSING_TRANSLATION
         
     | 
| 
      
 69 
     | 
    
         
            +
                  translation
         
     | 
| 
       68 
70 
     | 
    
         
             
                end
         
     | 
| 
       69 
71 
     | 
    
         
             
              end
         
     | 
| 
       70 
72 
     | 
    
         
             
            end
         
     | 
| 
         @@ -4,7 +4,29 @@ require "active_model/type/integer" 
     | 
|
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
            module ActiveModel
         
     | 
| 
       6 
6 
     | 
    
         
             
              module Type
         
     | 
| 
       7 
     | 
    
         
            -
                 
     | 
| 
      
 7 
     | 
    
         
            +
                # = Active Model \BigInteger \Type
         
     | 
| 
      
 8 
     | 
    
         
            +
                #
         
     | 
| 
      
 9 
     | 
    
         
            +
                # Attribute type for integers that can be serialized to an unlimited number
         
     | 
| 
      
 10 
     | 
    
         
            +
                # of bytes. This type is registered under the +:big_integer+ key.
         
     | 
| 
      
 11 
     | 
    
         
            +
                #
         
     | 
| 
      
 12 
     | 
    
         
            +
                #   class Person
         
     | 
| 
      
 13 
     | 
    
         
            +
                #     include ActiveModel::Attributes
         
     | 
| 
      
 14 
     | 
    
         
            +
                #
         
     | 
| 
      
 15 
     | 
    
         
            +
                #     attribute :id, :big_integer
         
     | 
| 
      
 16 
     | 
    
         
            +
                #   end
         
     | 
| 
      
 17 
     | 
    
         
            +
                #
         
     | 
| 
      
 18 
     | 
    
         
            +
                #   person = Person.new
         
     | 
| 
      
 19 
     | 
    
         
            +
                #   person.id = "18_000_000_000"
         
     | 
| 
      
 20 
     | 
    
         
            +
                #
         
     | 
| 
      
 21 
     | 
    
         
            +
                #   person.id # => 18000000000
         
     | 
| 
      
 22 
     | 
    
         
            +
                #
         
     | 
| 
      
 23 
     | 
    
         
            +
                # All casting and serialization are performed in the same way as the
         
     | 
| 
      
 24 
     | 
    
         
            +
                # standard ActiveModel::Type::Integer type.
         
     | 
| 
      
 25 
     | 
    
         
            +
                class BigInteger < Integer
         
     | 
| 
      
 26 
     | 
    
         
            +
                  def serialize_cast_value(value) # :nodoc:
         
     | 
| 
      
 27 
     | 
    
         
            +
                    value
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
       8 
30 
     | 
    
         
             
                  private
         
     | 
| 
       9 
31 
     | 
    
         
             
                    def max_value
         
     | 
| 
       10 
32 
     | 
    
         
             
                      ::Float::INFINITY
         
     | 
| 
         @@ -2,7 +2,13 @@ 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            module ActiveModel
         
     | 
| 
       4 
4 
     | 
    
         
             
              module Type
         
     | 
| 
       5 
     | 
    
         
            -
                 
     | 
| 
      
 5 
     | 
    
         
            +
                # = Active Model \Binary \Type
         
     | 
| 
      
 6 
     | 
    
         
            +
                #
         
     | 
| 
      
 7 
     | 
    
         
            +
                # Attribute type for representation of binary data. This type is registered
         
     | 
| 
      
 8 
     | 
    
         
            +
                # under the +:binary+ key.
         
     | 
| 
      
 9 
     | 
    
         
            +
                #
         
     | 
| 
      
 10 
     | 
    
         
            +
                # Non-string values are coerced to strings using their +to_s+ method.
         
     | 
| 
      
 11 
     | 
    
         
            +
                class Binary < Value
         
     | 
| 
       6 
12 
     | 
    
         
             
                  def type
         
     | 
| 
       7 
13 
     | 
    
         
             
                    :binary
         
     | 
| 
       8 
14 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -15,7 +21,9 @@ module ActiveModel 
     | 
|
| 
       15 
21 
     | 
    
         
             
                    if value.is_a?(Data)
         
     | 
| 
       16 
22 
     | 
    
         
             
                      value.to_s
         
     | 
| 
       17 
23 
     | 
    
         
             
                    else
         
     | 
| 
       18 
     | 
    
         
            -
                      super
         
     | 
| 
      
 24 
     | 
    
         
            +
                      value = super
         
     | 
| 
      
 25 
     | 
    
         
            +
                      value = value.b if ::String === value && value.encoding != Encoding::BINARY
         
     | 
| 
      
 26 
     | 
    
         
            +
                      value
         
     | 
| 
       19 
27 
     | 
    
         
             
                    end
         
     | 
| 
       20 
28 
     | 
    
         
             
                  end
         
     | 
| 
       21 
29 
     | 
    
         | 
| 
         @@ -2,17 +2,15 @@ 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            module ActiveModel
         
     | 
| 
       4 
4 
     | 
    
         
             
              module Type
         
     | 
| 
       5 
     | 
    
         
            -
                #  
     | 
| 
      
 5 
     | 
    
         
            +
                # = Active Model \Boolean \Type
         
     | 
| 
       6 
6 
     | 
    
         
             
                #
         
     | 
| 
       7 
     | 
    
         
            -
                # A class that behaves like a boolean type, including rules for coercion of 
     | 
| 
      
 7 
     | 
    
         
            +
                # A class that behaves like a boolean type, including rules for coercion of
         
     | 
| 
      
 8 
     | 
    
         
            +
                # user input.
         
     | 
| 
       8 
9 
     | 
    
         
             
                #
         
     | 
| 
       9 
     | 
    
         
            -
                #  
     | 
| 
       10 
     | 
    
         
            -
                #  
     | 
| 
       11 
     | 
    
         
            -
                #  
     | 
| 
       12 
     | 
    
         
            -
                #
         
     | 
| 
       13 
     | 
    
         
            -
                # - "false", "f" , "0", +0+ or any other value in +FALSE_VALUES+ will be coerced to +false+
         
     | 
| 
       14 
     | 
    
         
            -
                # - Empty strings are coerced to +nil+
         
     | 
| 
       15 
     | 
    
         
            -
                # - All other values will be coerced to +true+
         
     | 
| 
      
 10 
     | 
    
         
            +
                # - <tt>"false"</tt>, <tt>"f"</tt>, <tt>"0"</tt>, +0+ or any other value in
         
     | 
| 
      
 11 
     | 
    
         
            +
                #   +FALSE_VALUES+ will be coerced to +false+.
         
     | 
| 
      
 12 
     | 
    
         
            +
                # - Empty strings are coerced to +nil+.
         
     | 
| 
      
 13 
     | 
    
         
            +
                # - All other values will be coerced to +true+.
         
     | 
| 
       16 
14 
     | 
    
         
             
                class Boolean < Value
         
     | 
| 
       17 
15 
     | 
    
         
             
                  FALSE_VALUES = [
         
     | 
| 
       18 
16 
     | 
    
         
             
                    false, 0,
         
     | 
| 
         @@ -33,6 +31,10 @@ module ActiveModel 
     | 
|
| 
       33 
31 
     | 
    
         
             
                    cast(value)
         
     | 
| 
       34 
32 
     | 
    
         
             
                  end
         
     | 
| 
       35 
33 
     | 
    
         | 
| 
      
 34 
     | 
    
         
            +
                  def serialize_cast_value(value) # :nodoc:
         
     | 
| 
      
 35 
     | 
    
         
            +
                    value
         
     | 
| 
      
 36 
     | 
    
         
            +
                  end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
       36 
38 
     | 
    
         
             
                  private
         
     | 
| 
       37 
39 
     | 
    
         
             
                    def cast_value(value)
         
     | 
| 
       38 
40 
     | 
    
         
             
                      if value == ""
         
     | 
| 
         @@ -2,7 +2,28 @@ 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            module ActiveModel
         
     | 
| 
       4 
4 
     | 
    
         
             
              module Type
         
     | 
| 
       5 
     | 
    
         
            -
                 
     | 
| 
      
 5 
     | 
    
         
            +
                # = Active Model \Date \Type
         
     | 
| 
      
 6 
     | 
    
         
            +
                #
         
     | 
| 
      
 7 
     | 
    
         
            +
                # Attribute type for date representation. It is registered under the
         
     | 
| 
      
 8 
     | 
    
         
            +
                # +:date+ key.
         
     | 
| 
      
 9 
     | 
    
         
            +
                #
         
     | 
| 
      
 10 
     | 
    
         
            +
                #   class Person
         
     | 
| 
      
 11 
     | 
    
         
            +
                #     include ActiveModel::Attributes
         
     | 
| 
      
 12 
     | 
    
         
            +
                #
         
     | 
| 
      
 13 
     | 
    
         
            +
                #     attribute :birthday, :date
         
     | 
| 
      
 14 
     | 
    
         
            +
                #   end
         
     | 
| 
      
 15 
     | 
    
         
            +
                #
         
     | 
| 
      
 16 
     | 
    
         
            +
                #   person = Person.new
         
     | 
| 
      
 17 
     | 
    
         
            +
                #   person.birthday = "1989-07-13"
         
     | 
| 
      
 18 
     | 
    
         
            +
                #
         
     | 
| 
      
 19 
     | 
    
         
            +
                #   person.birthday.class # => Date
         
     | 
| 
      
 20 
     | 
    
         
            +
                #   person.birthday.year  # => 1989
         
     | 
| 
      
 21 
     | 
    
         
            +
                #   person.birthday.month # => 7
         
     | 
| 
      
 22 
     | 
    
         
            +
                #   person.birthday.day   # => 13
         
     | 
| 
      
 23 
     | 
    
         
            +
                #
         
     | 
| 
      
 24 
     | 
    
         
            +
                # String values are parsed using the ISO 8601 date format. Any other values
         
     | 
| 
      
 25 
     | 
    
         
            +
                # are cast using their +to_date+ method, if it exists.
         
     | 
| 
      
 26 
     | 
    
         
            +
                class Date < Value
         
     | 
| 
       6 
27 
     | 
    
         
             
                  include Helpers::Timezone
         
     | 
| 
       7 
28 
     | 
    
         
             
                  include Helpers::AcceptsMultiparameterTime.new
         
     | 
| 
       8 
29 
     | 
    
         | 
| 
         @@ -34,7 +55,12 @@ module ActiveModel 
     | 
|
| 
       34 
55 
     | 
    
         
             
                    end
         
     | 
| 
       35 
56 
     | 
    
         | 
| 
       36 
57 
     | 
    
         
             
                    def fallback_string_to_date(string)
         
     | 
| 
       37 
     | 
    
         
            -
                       
     | 
| 
      
 58 
     | 
    
         
            +
                      parts = begin
         
     | 
| 
      
 59 
     | 
    
         
            +
                        ::Date._parse(string, false)
         
     | 
| 
      
 60 
     | 
    
         
            +
                      rescue ArgumentError
         
     | 
| 
      
 61 
     | 
    
         
            +
                      end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                      new_date(*parts.values_at(:year, :mon, :mday)) if parts
         
     | 
| 
       38 
64 
     | 
    
         
             
                    end
         
     | 
| 
       39 
65 
     | 
    
         | 
| 
       40 
66 
     | 
    
         
             
                    def new_date(year, mon, mday)
         
     | 
| 
         @@ -2,12 +2,49 @@ 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            module ActiveModel
         
     | 
| 
       4 
4 
     | 
    
         
             
              module Type
         
     | 
| 
       5 
     | 
    
         
            -
                 
     | 
| 
      
 5 
     | 
    
         
            +
                # = Active Model \DateTime \Type
         
     | 
| 
      
 6 
     | 
    
         
            +
                #
         
     | 
| 
      
 7 
     | 
    
         
            +
                # Attribute type to represent dates and times. It is registered under the
         
     | 
| 
      
 8 
     | 
    
         
            +
                # +:datetime+ key.
         
     | 
| 
      
 9 
     | 
    
         
            +
                #
         
     | 
| 
      
 10 
     | 
    
         
            +
                #   class Event
         
     | 
| 
      
 11 
     | 
    
         
            +
                #     include ActiveModel::Attributes
         
     | 
| 
      
 12 
     | 
    
         
            +
                #
         
     | 
| 
      
 13 
     | 
    
         
            +
                #     attribute :start, :datetime
         
     | 
| 
      
 14 
     | 
    
         
            +
                #   end
         
     | 
| 
      
 15 
     | 
    
         
            +
                #
         
     | 
| 
      
 16 
     | 
    
         
            +
                #   event = Event.new
         
     | 
| 
      
 17 
     | 
    
         
            +
                #   event.start = "Wed, 04 Sep 2013 03:00:00 EAT"
         
     | 
| 
      
 18 
     | 
    
         
            +
                #
         
     | 
| 
      
 19 
     | 
    
         
            +
                #   event.start.class # => Time
         
     | 
| 
      
 20 
     | 
    
         
            +
                #   event.start.year  # => 2013
         
     | 
| 
      
 21 
     | 
    
         
            +
                #   event.start.month # => 9
         
     | 
| 
      
 22 
     | 
    
         
            +
                #   event.start.day   # => 4
         
     | 
| 
      
 23 
     | 
    
         
            +
                #   event.start.hour  # => 3
         
     | 
| 
      
 24 
     | 
    
         
            +
                #   event.start.min   # => 0
         
     | 
| 
      
 25 
     | 
    
         
            +
                #   event.start.sec   # => 0
         
     | 
| 
      
 26 
     | 
    
         
            +
                #   event.start.zone  # => "EAT"
         
     | 
| 
      
 27 
     | 
    
         
            +
                #
         
     | 
| 
      
 28 
     | 
    
         
            +
                # String values are parsed using the ISO 8601 datetime format. Partial
         
     | 
| 
      
 29 
     | 
    
         
            +
                # time-only formats are also accepted.
         
     | 
| 
      
 30 
     | 
    
         
            +
                #
         
     | 
| 
      
 31 
     | 
    
         
            +
                #   event.start = "06:07:08+09:00"
         
     | 
| 
      
 32 
     | 
    
         
            +
                #   event.start.utc # => 1999-12-31 21:07:08 UTC
         
     | 
| 
      
 33 
     | 
    
         
            +
                #
         
     | 
| 
      
 34 
     | 
    
         
            +
                # The degree of sub-second precision can be customized when declaring an
         
     | 
| 
      
 35 
     | 
    
         
            +
                # attribute:
         
     | 
| 
      
 36 
     | 
    
         
            +
                #
         
     | 
| 
      
 37 
     | 
    
         
            +
                #   class Event
         
     | 
| 
      
 38 
     | 
    
         
            +
                #     include ActiveModel::Attributes
         
     | 
| 
      
 39 
     | 
    
         
            +
                #
         
     | 
| 
      
 40 
     | 
    
         
            +
                #     attribute :start, :datetime, precision: 4
         
     | 
| 
      
 41 
     | 
    
         
            +
                #   end
         
     | 
| 
      
 42 
     | 
    
         
            +
                class DateTime < Value
         
     | 
| 
       6 
43 
     | 
    
         
             
                  include Helpers::Timezone
         
     | 
| 
       7 
     | 
    
         
            -
                  include Helpers::TimeValue
         
     | 
| 
       8 
44 
     | 
    
         
             
                  include Helpers::AcceptsMultiparameterTime.new(
         
     | 
| 
       9 
45 
     | 
    
         
             
                    defaults: { 4 => 0, 5 => 0 }
         
     | 
| 
       10 
46 
     | 
    
         
             
                  )
         
     | 
| 
      
 47 
     | 
    
         
            +
                  include Helpers::TimeValue
         
     | 
| 
       11 
48 
     | 
    
         | 
| 
       12 
49 
     | 
    
         
             
                  def type
         
     | 
| 
       13 
50 
     | 
    
         
             
                    :datetime
         
     | 
| 
         @@ -28,7 +65,12 @@ module ActiveModel 
     | 
|
| 
       28 
65 
     | 
    
         
             
                    end
         
     | 
| 
       29 
66 
     | 
    
         | 
| 
       30 
67 
     | 
    
         
             
                    def fallback_string_to_time(string)
         
     | 
| 
       31 
     | 
    
         
            -
                      time_hash =  
     | 
| 
      
 68 
     | 
    
         
            +
                      time_hash = begin
         
     | 
| 
      
 69 
     | 
    
         
            +
                        ::Date._parse(string)
         
     | 
| 
      
 70 
     | 
    
         
            +
                      rescue ArgumentError
         
     | 
| 
      
 71 
     | 
    
         
            +
                      end
         
     | 
| 
      
 72 
     | 
    
         
            +
                      return unless time_hash
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
       32 
74 
     | 
    
         
             
                      time_hash[:sec_fraction] = microseconds(time_hash)
         
     | 
| 
       33 
75 
     | 
    
         | 
| 
       34 
76 
     | 
    
         
             
                      new_time(*time_hash.values_at(:year, :mon, :mday, :hour, :min, :sec, :sec_fraction, :offset))
         
     | 
| 
         @@ -4,7 +4,45 @@ require "bigdecimal/util" 
     | 
|
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
            module ActiveModel
         
     | 
| 
       6 
6 
     | 
    
         
             
              module Type
         
     | 
| 
       7 
     | 
    
         
            -
                 
     | 
| 
      
 7 
     | 
    
         
            +
                # = Active Model \Decimal \Type
         
     | 
| 
      
 8 
     | 
    
         
            +
                #
         
     | 
| 
      
 9 
     | 
    
         
            +
                # Attribute type for decimal, high-precision floating point numeric
         
     | 
| 
      
 10 
     | 
    
         
            +
                # representation. It is registered under the +:decimal+ key.
         
     | 
| 
      
 11 
     | 
    
         
            +
                #
         
     | 
| 
      
 12 
     | 
    
         
            +
                #   class BagOfCoffee
         
     | 
| 
      
 13 
     | 
    
         
            +
                #     include ActiveModel::Attributes
         
     | 
| 
      
 14 
     | 
    
         
            +
                #
         
     | 
| 
      
 15 
     | 
    
         
            +
                #     attribute :weight, :decimal
         
     | 
| 
      
 16 
     | 
    
         
            +
                #   end
         
     | 
| 
      
 17 
     | 
    
         
            +
                #
         
     | 
| 
      
 18 
     | 
    
         
            +
                # Numeric instances are converted to BigDecimal instances. Any other objects
         
     | 
| 
      
 19 
     | 
    
         
            +
                # are cast using their +to_d+ method, except for blank strings, which are
         
     | 
| 
      
 20 
     | 
    
         
            +
                # cast to +nil+. If a +to_d+ method is not defined, the object is converted
         
     | 
| 
      
 21 
     | 
    
         
            +
                # to a string using +to_s+, which is then cast using +to_d+.
         
     | 
| 
      
 22 
     | 
    
         
            +
                #
         
     | 
| 
      
 23 
     | 
    
         
            +
                #   bag = BagOfCoffee.new
         
     | 
| 
      
 24 
     | 
    
         
            +
                #
         
     | 
| 
      
 25 
     | 
    
         
            +
                #   bag.weight = 0.01
         
     | 
| 
      
 26 
     | 
    
         
            +
                #   bag.weight # => 0.1e-1
         
     | 
| 
      
 27 
     | 
    
         
            +
                #
         
     | 
| 
      
 28 
     | 
    
         
            +
                #   bag.weight = "0.01"
         
     | 
| 
      
 29 
     | 
    
         
            +
                #   bag.weight # => 0.1e-1
         
     | 
| 
      
 30 
     | 
    
         
            +
                #
         
     | 
| 
      
 31 
     | 
    
         
            +
                #   bag.weight = ""
         
     | 
| 
      
 32 
     | 
    
         
            +
                #   bag.weight # => nil
         
     | 
| 
      
 33 
     | 
    
         
            +
                #
         
     | 
| 
      
 34 
     | 
    
         
            +
                #   bag.weight = :arbitrary
         
     | 
| 
      
 35 
     | 
    
         
            +
                #   bag.weight # => nil (the result of `.to_s.to_d`)
         
     | 
| 
      
 36 
     | 
    
         
            +
                #
         
     | 
| 
      
 37 
     | 
    
         
            +
                # Decimal precision defaults to 18, and can be customized when declaring an
         
     | 
| 
      
 38 
     | 
    
         
            +
                # attribute:
         
     | 
| 
      
 39 
     | 
    
         
            +
                #
         
     | 
| 
      
 40 
     | 
    
         
            +
                #   class BagOfCoffee
         
     | 
| 
      
 41 
     | 
    
         
            +
                #     include ActiveModel::Attributes
         
     | 
| 
      
 42 
     | 
    
         
            +
                #
         
     | 
| 
      
 43 
     | 
    
         
            +
                #     attribute :weight, :decimal, precision: 24
         
     | 
| 
      
 44 
     | 
    
         
            +
                #   end
         
     | 
| 
      
 45 
     | 
    
         
            +
                class Decimal < Value
         
     | 
| 
       8 
46 
     | 
    
         
             
                  include Helpers::Numeric
         
     | 
| 
       9 
47 
     | 
    
         
             
                  BIGDECIMAL_PRECISION = 18
         
     | 
| 
       10 
48 
     | 
    
         | 
| 
         @@ -4,7 +4,36 @@ require "active_support/core_ext/object/try" 
     | 
|
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
            module ActiveModel
         
     | 
| 
       6 
6 
     | 
    
         
             
              module Type
         
     | 
| 
       7 
     | 
    
         
            -
                 
     | 
| 
      
 7 
     | 
    
         
            +
                # = Active Model \Float \Type
         
     | 
| 
      
 8 
     | 
    
         
            +
                #
         
     | 
| 
      
 9 
     | 
    
         
            +
                # Attribute type for floating point numeric values. It is registered under
         
     | 
| 
      
 10 
     | 
    
         
            +
                # the +:float+ key.
         
     | 
| 
      
 11 
     | 
    
         
            +
                #
         
     | 
| 
      
 12 
     | 
    
         
            +
                #   class BagOfCoffee
         
     | 
| 
      
 13 
     | 
    
         
            +
                #     include ActiveModel::Attributes
         
     | 
| 
      
 14 
     | 
    
         
            +
                #
         
     | 
| 
      
 15 
     | 
    
         
            +
                #     attribute :weight, :float
         
     | 
| 
      
 16 
     | 
    
         
            +
                #   end
         
     | 
| 
      
 17 
     | 
    
         
            +
                #
         
     | 
| 
      
 18 
     | 
    
         
            +
                # Values are cast using their +to_f+ method, except for the following
         
     | 
| 
      
 19 
     | 
    
         
            +
                # strings:
         
     | 
| 
      
 20 
     | 
    
         
            +
                #
         
     | 
| 
      
 21 
     | 
    
         
            +
                # - Blank strings are cast to +nil+.
         
     | 
| 
      
 22 
     | 
    
         
            +
                # - <tt>"Infinity"</tt> is cast to +Float::INFINITY+.
         
     | 
| 
      
 23 
     | 
    
         
            +
                # - <tt>"-Infinity"</tt> is cast to <tt>-Float::INFINITY</tt>.
         
     | 
| 
      
 24 
     | 
    
         
            +
                # - <tt>"NaN"</tt> is cast to +Float::NAN+.
         
     | 
| 
      
 25 
     | 
    
         
            +
                #
         
     | 
| 
      
 26 
     | 
    
         
            +
                #   bag = BagOfCoffee.new
         
     | 
| 
      
 27 
     | 
    
         
            +
                #
         
     | 
| 
      
 28 
     | 
    
         
            +
                #   bag.weight = "0.25"
         
     | 
| 
      
 29 
     | 
    
         
            +
                #   bag.weight # => 0.25
         
     | 
| 
      
 30 
     | 
    
         
            +
                #
         
     | 
| 
      
 31 
     | 
    
         
            +
                #   bag.weight = ""
         
     | 
| 
      
 32 
     | 
    
         
            +
                #   bag.weight # => nil
         
     | 
| 
      
 33 
     | 
    
         
            +
                #
         
     | 
| 
      
 34 
     | 
    
         
            +
                #   bag.weight = "NaN"
         
     | 
| 
      
 35 
     | 
    
         
            +
                #   bag.weight # => Float::NAN
         
     | 
| 
      
 36 
     | 
    
         
            +
                class Float < Value
         
     | 
| 
       8 
37 
     | 
    
         
             
                  include Helpers::Numeric
         
     | 
| 
       9 
38 
     | 
    
         | 
| 
       10 
39 
     | 
    
         
             
                  def type
         
     | 
| 
         @@ -4,10 +4,6 @@ module ActiveModel 
     | 
|
| 
       4 
4 
     | 
    
         
             
              module Type
         
     | 
| 
       5 
5 
     | 
    
         
             
                module Helpers # :nodoc: all
         
     | 
| 
       6 
6 
     | 
    
         
             
                  module Mutable
         
     | 
| 
       7 
     | 
    
         
            -
                    def immutable_value(value)
         
     | 
| 
       8 
     | 
    
         
            -
                      value.deep_dup.freeze
         
     | 
| 
       9 
     | 
    
         
            -
                    end
         
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
7 
     | 
    
         
             
                    def cast(value)
         
     | 
| 
       12 
8 
     | 
    
         
             
                      deserialize(serialize(value))
         
     | 
| 
       13 
9 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -18,6 +14,10 @@ module ActiveModel 
     | 
|
| 
       18 
14 
     | 
    
         
             
                    def changed_in_place?(raw_old_value, new_value)
         
     | 
| 
       19 
15 
     | 
    
         
             
                      raw_old_value != serialize(new_value)
         
     | 
| 
       20 
16 
     | 
    
         
             
                    end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                    def mutable? # :nodoc:
         
     | 
| 
      
 19 
     | 
    
         
            +
                      true
         
     | 
| 
      
 20 
     | 
    
         
            +
                    end
         
     | 
| 
       21 
21 
     | 
    
         
             
                  end
         
     | 
| 
       22 
22 
     | 
    
         
             
                end
         
     | 
| 
       23 
23 
     | 
    
         
             
              end
         
     | 
| 
         @@ -8,6 +8,10 @@ module ActiveModel 
     | 
|
| 
       8 
8 
     | 
    
         
             
                      cast(value)
         
     | 
| 
       9 
9 
     | 
    
         
             
                    end
         
     | 
| 
       10 
10 
     | 
    
         | 
| 
      
 11 
     | 
    
         
            +
                    def serialize_cast_value(value)
         
     | 
| 
      
 12 
     | 
    
         
            +
                      value
         
     | 
| 
      
 13 
     | 
    
         
            +
                    end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
       11 
15 
     | 
    
         
             
                    def cast(value)
         
     | 
| 
       12 
16 
     | 
    
         
             
                      # Checks whether the value is numeric. Spaceship operator
         
     | 
| 
       13 
17 
     | 
    
         
             
                      # will return nil if value is not numeric.
         
     | 
| 
         @@ -38,7 +42,8 @@ module ActiveModel 
     | 
|
| 
       38 
42 
     | 
    
         
             
                      end
         
     | 
| 
       39 
43 
     | 
    
         | 
| 
       40 
44 
     | 
    
         
             
                      def number_to_non_number?(old_value, new_value_before_type_cast)
         
     | 
| 
       41 
     | 
    
         
            -
                        old_value != nil &&  
     | 
| 
      
 45 
     | 
    
         
            +
                        old_value != nil && !new_value_before_type_cast.is_a?(::Numeric) &&
         
     | 
| 
      
 46 
     | 
    
         
            +
                          non_numeric_string?(new_value_before_type_cast.to_s)
         
     | 
| 
       42 
47 
     | 
    
         
             
                      end
         
     | 
| 
       43 
48 
     | 
    
         | 
| 
       44 
49 
     | 
    
         
             
                      def non_numeric_string?(value)
         
     | 
| 
         @@ -7,7 +7,7 @@ module ActiveModel 
     | 
|
| 
       7 
7 
     | 
    
         
             
              module Type
         
     | 
| 
       8 
8 
     | 
    
         
             
                module Helpers # :nodoc: all
         
     | 
| 
       9 
9 
     | 
    
         
             
                  module TimeValue
         
     | 
| 
       10 
     | 
    
         
            -
                    def  
     | 
| 
      
 10 
     | 
    
         
            +
                    def serialize_cast_value(value)
         
     | 
| 
       11 
11 
     | 
    
         
             
                      value = apply_seconds_precision(value)
         
     | 
| 
       12 
12 
     | 
    
         | 
| 
       13 
13 
     | 
    
         
             
                      if value.acts_like?(:time)
         
     | 
| 
         @@ -69,20 +69,36 @@ module ActiveModel 
     | 
|
| 
       69 
69 
     | 
    
         
             
                        \z
         
     | 
| 
       70 
70 
     | 
    
         
             
                      /x
         
     | 
| 
       71 
71 
     | 
    
         | 
| 
       72 
     | 
    
         
            -
                       
     | 
| 
       73 
     | 
    
         
            -
                         
     | 
| 
       74 
     | 
    
         
            -
             
     | 
| 
       75 
     | 
    
         
            -
             
     | 
| 
       76 
     | 
    
         
            -
             
     | 
| 
       77 
     | 
    
         
            -
             
     | 
| 
       78 
     | 
    
         
            -
             
     | 
| 
      
 72 
     | 
    
         
            +
                      if RUBY_VERSION >= "3.2"
         
     | 
| 
      
 73 
     | 
    
         
            +
                        def fast_string_to_time(string)
         
     | 
| 
      
 74 
     | 
    
         
            +
                          return unless ISO_DATETIME.match?(string)
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                          if is_utc?
         
     | 
| 
      
 77 
     | 
    
         
            +
                            # XXX: Wrapping the Time object with Time.at because Time.new with `in:` in Ruby 3.2.0 used to return an invalid Time object
         
     | 
| 
      
 78 
     | 
    
         
            +
                            # see: https://bugs.ruby-lang.org/issues/19292
         
     | 
| 
      
 79 
     | 
    
         
            +
                            ::Time.at(::Time.new(string, in: "UTC"))
         
     | 
| 
      
 80 
     | 
    
         
            +
                          else
         
     | 
| 
      
 81 
     | 
    
         
            +
                            ::Time.new(string)
         
     | 
| 
      
 82 
     | 
    
         
            +
                          end
         
     | 
| 
      
 83 
     | 
    
         
            +
                        rescue ArgumentError
         
     | 
| 
      
 84 
     | 
    
         
            +
                          nil
         
     | 
| 
       79 
85 
     | 
    
         
             
                        end
         
     | 
| 
      
 86 
     | 
    
         
            +
                      else
         
     | 
| 
      
 87 
     | 
    
         
            +
                        def fast_string_to_time(string)
         
     | 
| 
      
 88 
     | 
    
         
            +
                          return unless ISO_DATETIME =~ string
         
     | 
| 
       80 
89 
     | 
    
         | 
| 
       81 
     | 
    
         
            -
             
     | 
| 
       82 
     | 
    
         
            -
                           
     | 
| 
       83 
     | 
    
         
            -
             
     | 
| 
      
 90 
     | 
    
         
            +
                          usec = $7.to_i
         
     | 
| 
      
 91 
     | 
    
         
            +
                          usec_len = $7&.length
         
     | 
| 
      
 92 
     | 
    
         
            +
                          if usec_len&.< 6
         
     | 
| 
      
 93 
     | 
    
         
            +
                            usec *= 10**(6 - usec_len)
         
     | 
| 
      
 94 
     | 
    
         
            +
                          end
         
     | 
| 
       84 
95 
     | 
    
         | 
| 
       85 
     | 
    
         
            -
             
     | 
| 
      
 96 
     | 
    
         
            +
                          if $8
         
     | 
| 
      
 97 
     | 
    
         
            +
                            offset = $8 == "Z" ? 0 : $8.to_i * 3600 + $9.to_i * 60
         
     | 
| 
      
 98 
     | 
    
         
            +
                          end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                          new_time($1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i, usec, offset)
         
     | 
| 
      
 101 
     | 
    
         
            +
                        end
         
     | 
| 
       86 
102 
     | 
    
         
             
                      end
         
     | 
| 
       87 
103 
     | 
    
         
             
                  end
         
     | 
| 
       88 
104 
     | 
    
         
             
                end
         
     |