activemodel 7.1.5.2 → 8.1.2.1

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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +21 -281
  3. data/README.rdoc +10 -10
  4. data/lib/active_model/attribute/user_provided_default.rb +10 -0
  5. data/lib/active_model/attribute.rb +10 -2
  6. data/lib/active_model/attribute_assignment.rb +26 -3
  7. data/lib/active_model/attribute_methods.rb +42 -43
  8. data/lib/active_model/attribute_mutation_tracker.rb +5 -5
  9. data/lib/active_model/attribute_registration.rb +62 -22
  10. data/lib/active_model/attribute_set.rb +1 -1
  11. data/lib/active_model/attributes/normalization.rb +192 -0
  12. data/lib/active_model/attributes.rb +13 -0
  13. data/lib/active_model/callbacks.rb +1 -1
  14. data/lib/active_model/conversion.rb +1 -1
  15. data/lib/active_model/dirty.rb +16 -9
  16. data/lib/active_model/error.rb +3 -2
  17. data/lib/active_model/errors.rb +1 -4
  18. data/lib/active_model/gem_version.rb +3 -3
  19. data/lib/active_model/lint.rb +7 -3
  20. data/lib/active_model/model.rb +2 -2
  21. data/lib/active_model/naming.rb +0 -1
  22. data/lib/active_model/nested_error.rb +1 -3
  23. data/lib/active_model/railtie.rb +8 -4
  24. data/lib/active_model/secure_password.rb +62 -5
  25. data/lib/active_model/serialization.rb +21 -21
  26. data/lib/active_model/translation.rb +22 -5
  27. data/lib/active_model/type/big_integer.rb +21 -0
  28. data/lib/active_model/type/boolean.rb +1 -0
  29. data/lib/active_model/type/date.rb +1 -0
  30. data/lib/active_model/type/date_time.rb +8 -0
  31. data/lib/active_model/type/decimal.rb +1 -0
  32. data/lib/active_model/type/float.rb +9 -8
  33. data/lib/active_model/type/helpers/immutable.rb +13 -0
  34. data/lib/active_model/type/helpers/time_value.rb +12 -15
  35. data/lib/active_model/type/helpers/timezone.rb +5 -1
  36. data/lib/active_model/type/helpers.rb +1 -0
  37. data/lib/active_model/type/immutable_string.rb +2 -0
  38. data/lib/active_model/type/integer.rb +31 -19
  39. data/lib/active_model/type/registry.rb +2 -3
  40. data/lib/active_model/type/string.rb +4 -0
  41. data/lib/active_model/type/value.rb +4 -4
  42. data/lib/active_model/validations/acceptance.rb +1 -1
  43. data/lib/active_model/validations/callbacks.rb +11 -1
  44. data/lib/active_model/validations/comparison.rb +1 -1
  45. data/lib/active_model/validations/validates.rb +8 -3
  46. data/lib/active_model/validations.rb +57 -32
  47. data/lib/active_model.rb +6 -0
  48. metadata +10 -8
@@ -20,16 +20,15 @@ module ActiveModel
20
20
  registrations[type_name] = block
21
21
  end
22
22
 
23
- def lookup(symbol, *args)
23
+ def lookup(symbol, ...)
24
24
  registration = registrations[symbol]
25
25
 
26
26
  if registration
27
- registration.call(symbol, *args)
27
+ registration.call(symbol, ...)
28
28
  else
29
29
  raise ArgumentError, "Unknown type #{symbol.inspect}"
30
30
  end
31
31
  end
32
- ruby2_keywords(:lookup)
33
32
 
34
33
  private
35
34
  attr_reader :registrations
@@ -19,6 +19,10 @@ module ActiveModel
19
19
  end
20
20
  end
21
21
 
22
+ def mutable? # :nodoc:
23
+ true
24
+ end
25
+
22
26
  def to_immutable_string
23
27
  ImmutableString.new(
24
28
  true: @true,
@@ -25,7 +25,7 @@ module ActiveModel
25
25
  # by the database. For example a boolean type can return +true+ if the
26
26
  # value parameter is a Ruby boolean, but may return +false+ if the value
27
27
  # parameter is some other object.
28
- def serializable?(value)
28
+ def serializable?(value, &)
29
29
  true
30
30
  end
31
31
 
@@ -114,8 +114,8 @@ module ActiveModel
114
114
  false
115
115
  end
116
116
 
117
- def map(value) # :nodoc:
118
- yield value
117
+ def map(value, &) # :nodoc:
118
+ value
119
119
  end
120
120
 
121
121
  def ==(other)
@@ -138,7 +138,7 @@ module ActiveModel
138
138
  end
139
139
 
140
140
  def mutable? # :nodoc:
141
- false
141
+ true
142
142
  end
143
143
 
144
144
  def as_json(*)
@@ -24,7 +24,7 @@ module ActiveModel
24
24
  Array(options[:accept]).include?(value)
25
25
  end
26
26
 
27
- class LazilyDefineAttributes < Module
27
+ class LazilyDefineAttributes < Module # :nodoc:
28
28
  def initialize(attributes)
29
29
  @attributes = attributes.map(&:to_s)
30
30
  end
@@ -101,11 +101,21 @@ module ActiveModel
101
101
  options[:on] = Array(options[:on])
102
102
  options[:if] = [
103
103
  ->(o) {
104
- !(options[:on] & Array(o.validation_context)).empty?
104
+ options[:on].intersect?(Array(o.validation_context))
105
105
  },
106
106
  *options[:if]
107
107
  ]
108
108
  end
109
+
110
+ if options.key?(:except_on)
111
+ options[:except_on] = Array(options[:except_on])
112
+ options[:unless] = [
113
+ ->(o) {
114
+ options[:except_on].intersect?(Array(o.validation_context))
115
+ },
116
+ *options[:unless]
117
+ ]
118
+ end
109
119
  end
110
120
  end
111
121
 
@@ -10,7 +10,7 @@ module ActiveModel
10
10
  include ResolveValue
11
11
 
12
12
  def check_validity!
13
- unless (options.keys & COMPARE_CHECKS.keys).any?
13
+ unless options.keys.intersect?(COMPARE_CHECKS.keys)
14
14
  raise ArgumentError, "Expected one of :greater_than, :greater_than_or_equal_to, "\
15
15
  ":equal_to, :less_than, :less_than_or_equal_to, or :other_than option to be supplied."
16
16
  end
@@ -10,7 +10,7 @@ module ActiveModel
10
10
  # validators can be overridden inside specific classes by creating
11
11
  # custom validator classes in their place such as PresenceValidator.
12
12
  #
13
- # Examples of using the default \Rails validators:
13
+ # Examples of using the default Rails validators:
14
14
  #
15
15
  # validates :username, absence: true
16
16
  # validates :terms, acceptance: true
@@ -78,7 +78,12 @@ module ActiveModel
78
78
  # or an array of symbols. (e.g. <tt>on: :create</tt> or
79
79
  # <tt>on: :custom_validation_context</tt> or
80
80
  # <tt>on: [:create, :custom_validation_context]</tt>)
81
- # * <tt>:if</tt> - Specifies a method, proc, or string to call to determine
81
+ # * <tt>:except_on</tt> - Specifies the contexts where this validation is not active.
82
+ # Runs in all validation contexts by default +nil+. You can pass a symbol
83
+ # or an array of symbols. (e.g. <tt>except: :create</tt> or
84
+ # <tt>except_on: :custom_validation_context</tt> or
85
+ # <tt>except_on: [:create, :custom_validation_context]</tt>)
86
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine
82
87
  # if the validation should occur (e.g. <tt>if: :allow_validation</tt>,
83
88
  # or <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>). The method,
84
89
  # proc or string should return or evaluate to a +true+ or +false+ value.
@@ -155,7 +160,7 @@ module ActiveModel
155
160
  # When creating custom validators, it might be useful to be able to specify
156
161
  # additional default keys. This can be done by overwriting this method.
157
162
  def _validates_default_keys
158
- [:if, :unless, :on, :allow_blank, :allow_nil, :strict]
163
+ [:if, :unless, :on, :allow_blank, :allow_nil, :strict, :except_on]
159
164
  end
160
165
 
161
166
  def _parse_validates_options(options)
@@ -45,27 +45,6 @@ module ActiveModel
45
45
  extend HelperMethods
46
46
  include HelperMethods
47
47
 
48
- ##
49
- # :method: validation_context
50
- # Returns the context when running validations.
51
- #
52
- # This is useful when running validations except a certain context (opposite to the +on+ option).
53
- #
54
- # class Person
55
- # include ActiveModel::Validations
56
- #
57
- # attr_accessor :name
58
- # validates :name, presence: true, if: -> { validation_context != :custom }
59
- # end
60
- #
61
- # person = Person.new
62
- # person.valid? #=> false
63
- # person.valid?(:new) #=> false
64
- # person.valid?(:custom) #=> true
65
-
66
- ##
67
- attr_accessor :validation_context
68
- private :validation_context=
69
48
  define_callbacks :validate, scope: :name
70
49
 
71
50
  class_attribute :_validators, instance_writer: false, default: Hash.new { |h, k| h[k] = [] }
@@ -84,12 +63,18 @@ module ActiveModel
84
63
  # end
85
64
  # end
86
65
  #
87
- # Options:
66
+ # ==== Options
67
+ #
88
68
  # * <tt>:on</tt> - Specifies the contexts where this validation is active.
89
69
  # Runs in all validation contexts by default +nil+. You can pass a symbol
90
70
  # or an array of symbols. (e.g. <tt>on: :create</tt> or
91
71
  # <tt>on: :custom_validation_context</tt> or
92
72
  # <tt>on: [:create, :custom_validation_context]</tt>)
73
+ # * <tt>:except_on</tt> - Specifies the contexts where this validation is not active.
74
+ # Runs in all validation contexts by default +nil+. You can pass a symbol
75
+ # or an array of symbols. (e.g. <tt>except: :create</tt> or
76
+ # <tt>except_on: :custom_validation_context</tt> or
77
+ # <tt>except_on: [:create, :custom_validation_context]</tt>)
93
78
  # * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+.
94
79
  # * <tt>:allow_blank</tt> - Skip validation if attribute is blank.
95
80
  # * <tt>:if</tt> - Specifies a method, proc, or string to call to determine
@@ -105,7 +90,7 @@ module ActiveModel
105
90
  validates_with BlockValidator, _merge_attributes(attr_names), &block
106
91
  end
107
92
 
108
- VALID_OPTIONS_FOR_VALIDATE = [:on, :if, :unless, :prepend].freeze # :nodoc:
93
+ VALID_OPTIONS_FOR_VALIDATE = [:on, :if, :unless, :prepend, :except_on].freeze # :nodoc:
109
94
 
110
95
  # Adds a validation method or block to the class. This is useful when
111
96
  # overriding the +validate+ instance method becomes too unwieldy and
@@ -150,20 +135,26 @@ module ActiveModel
150
135
  # Note that the return value of validation methods is not relevant.
151
136
  # It's not possible to halt the validate callback chain.
152
137
  #
153
- # Options:
138
+ # ==== Options
139
+ #
154
140
  # * <tt>:on</tt> - Specifies the contexts where this validation is active.
155
141
  # Runs in all validation contexts by default +nil+. You can pass a symbol
156
142
  # or an array of symbols. (e.g. <tt>on: :create</tt> or
157
143
  # <tt>on: :custom_validation_context</tt> or
158
144
  # <tt>on: [:create, :custom_validation_context]</tt>)
159
- # * <tt>:if</tt> - Specifies a method, proc, or string to call to determine
145
+ # * <tt>:except_on</tt> - Specifies the contexts where this validation is not active.
146
+ # Runs in all validation contexts by default +nil+. You can pass a symbol
147
+ # or an array of symbols. (e.g. <tt>except: :create</tt> or
148
+ # <tt>except_on: :custom_validation_context</tt> or
149
+ # <tt>except_on: [:create, :custom_validation_context]</tt>)
150
+ # * <tt>:if</tt> - Specifies a method or proc to call to determine
160
151
  # if the validation should occur (e.g. <tt>if: :allow_validation</tt>,
161
- # or <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>). The method,
162
- # proc or string should return or evaluate to a +true+ or +false+ value.
163
- # * <tt>:unless</tt> - Specifies a method, proc, or string to call to
152
+ # or <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>). The method or
153
+ # proc should return or evaluate to a +true+ or +false+ value.
154
+ # * <tt>:unless</tt> - Specifies a method or proc to call to
164
155
  # determine if the validation should not occur (e.g. <tt>unless: :skip_validation</tt>,
165
156
  # or <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>). The
166
- # method, proc, or string should return or evaluate to a +true+ or +false+
157
+ # method or proc should return or evaluate to a +true+ or +false+
167
158
  # value.
168
159
  #
169
160
  # NOTE: Calling +validate+ multiple times on the same method will overwrite previous definitions.
@@ -183,6 +174,15 @@ module ActiveModel
183
174
  options = options.merge(if: [predicate_for_validation_context(options[:on]), *options[:if]])
184
175
  end
185
176
 
177
+ if options.key?(:except_on)
178
+ options = options.dup
179
+ options[:except_on] = Array(options[:except_on])
180
+ options[:unless] = [
181
+ ->(o) { options[:except_on].intersect?(Array(o.validation_context)) },
182
+ *options[:unless]
183
+ ]
184
+ end
185
+
186
186
  set_callback(:validate, *args, options, &block)
187
187
  end
188
188
 
@@ -361,15 +361,23 @@ module ActiveModel
361
361
  # person.valid? # => true
362
362
  # person.valid?(:new) # => false
363
363
  def valid?(context = nil)
364
- current_context, self.validation_context = validation_context, context
364
+ current_context = validation_context
365
+ context_for_validation.context = context
365
366
  errors.clear
366
367
  run_validations!
367
368
  ensure
368
- self.validation_context = current_context
369
+ context_for_validation.context = current_context
369
370
  end
370
371
 
371
372
  alias_method :validate, :valid?
372
373
 
374
+ def freeze
375
+ errors
376
+ context_for_validation
377
+
378
+ super
379
+ end
380
+
373
381
  # Performs the opposite of <tt>valid?</tt>. Returns +true+ if errors were
374
382
  # added, +false+ otherwise.
375
383
  #
@@ -430,11 +438,24 @@ module ActiveModel
430
438
  # end
431
439
  alias :read_attribute_for_validation :send
432
440
 
441
+ # Returns the context when running validations.
442
+ def validation_context
443
+ context_for_validation.context
444
+ end
445
+
433
446
  private
447
+ def validation_context=(context)
448
+ context_for_validation.context = context
449
+ end
450
+
451
+ def context_for_validation
452
+ @context_for_validation ||= ValidationContext.new
453
+ end
454
+
434
455
  def init_internals
435
456
  super
436
457
  @errors = nil
437
- @validation_context = nil
458
+ @context_for_validation = nil
438
459
  end
439
460
 
440
461
  def run_validations!
@@ -466,6 +487,10 @@ module ActiveModel
466
487
  super(I18n.t(:"#{@model.class.i18n_scope}.errors.messages.model_invalid", errors: errors, default: :"errors.messages.model_invalid"))
467
488
  end
468
489
  end
490
+
491
+ class ValidationContext # :nodoc:
492
+ attr_accessor :context
493
+ end
469
494
  end
470
495
 
471
496
  Dir[File.expand_path("validations/*.rb", __dir__)].each { |file| require file }
data/lib/active_model.rb CHANGED
@@ -56,6 +56,12 @@ module ActiveModel
56
56
  autoload :Validations
57
57
  autoload :Validator
58
58
 
59
+ module Attributes
60
+ extend ActiveSupport::Autoload
61
+
62
+ autoload :Normalization
63
+ end
64
+
59
65
  eager_autoload do
60
66
  autoload :Errors
61
67
  autoload :Error
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activemodel
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.1.5.2
4
+ version: 8.1.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - '='
17
17
  - !ruby/object:Gem::Version
18
- version: 7.1.5.2
18
+ version: 8.1.2.1
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - '='
24
24
  - !ruby/object:Gem::Version
25
- version: 7.1.5.2
25
+ version: 8.1.2.1
26
26
  description: A toolkit for building modeling frameworks like Active Record. Rich support
27
27
  for attributes, callbacks, validations, serialization, internationalization, and
28
28
  testing.
@@ -47,6 +47,7 @@ files:
47
47
  - lib/active_model/attribute_set/builder.rb
48
48
  - lib/active_model/attribute_set/yaml_encoder.rb
49
49
  - lib/active_model/attributes.rb
50
+ - lib/active_model/attributes/normalization.rb
50
51
  - lib/active_model/callbacks.rb
51
52
  - lib/active_model/conversion.rb
52
53
  - lib/active_model/deprecator.rb
@@ -75,6 +76,7 @@ files:
75
76
  - lib/active_model/type/float.rb
76
77
  - lib/active_model/type/helpers.rb
77
78
  - lib/active_model/type/helpers/accepts_multiparameter_time.rb
79
+ - lib/active_model/type/helpers/immutable.rb
78
80
  - lib/active_model/type/helpers/mutable.rb
79
81
  - lib/active_model/type/helpers/numeric.rb
80
82
  - lib/active_model/type/helpers/time_value.rb
@@ -111,10 +113,10 @@ licenses:
111
113
  - MIT
112
114
  metadata:
113
115
  bug_tracker_uri: https://github.com/rails/rails/issues
114
- changelog_uri: https://github.com/rails/rails/blob/v7.1.5.2/activemodel/CHANGELOG.md
115
- documentation_uri: https://api.rubyonrails.org/v7.1.5.2/
116
+ changelog_uri: https://github.com/rails/rails/blob/v8.1.2.1/activemodel/CHANGELOG.md
117
+ documentation_uri: https://api.rubyonrails.org/v8.1.2.1/
116
118
  mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
117
- source_code_uri: https://github.com/rails/rails/tree/v7.1.5.2/activemodel
119
+ source_code_uri: https://github.com/rails/rails/tree/v8.1.2.1/activemodel
118
120
  rubygems_mfa_required: 'true'
119
121
  rdoc_options: []
120
122
  require_paths:
@@ -123,14 +125,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
123
125
  requirements:
124
126
  - - ">="
125
127
  - !ruby/object:Gem::Version
126
- version: 2.7.0
128
+ version: 3.2.0
127
129
  required_rubygems_version: !ruby/object:Gem::Requirement
128
130
  requirements:
129
131
  - - ">="
130
132
  - !ruby/object:Gem::Version
131
133
  version: '0'
132
134
  requirements: []
133
- rubygems_version: 3.6.9
135
+ rubygems_version: 4.0.6
134
136
  specification_version: 4
135
137
  summary: A toolkit for building modeling frameworks (part of Rails).
136
138
  test_files: []