activemodel 5.2.0.beta2 → 5.2.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: f8bb0c3867c3dfe9215c08be8eb1e993ade817b4
4
- data.tar.gz: 13b15b80b683e29fc4b3b603afd762a90264b8a8
2
+ SHA256:
3
+ metadata.gz: 666a46bf39ff339f606b0d60219d61138a7de2def4808f6135255ee2a2b43ff0
4
+ data.tar.gz: 5de9942d5e2dfd21df46a9ac538bc83b4bc879c57884e3f26192f4204dac6d33
5
5
  SHA512:
6
- metadata.gz: 753ce129d560dc612f06f6e159c7ad2300181f9d28391e50c1697b310c377c76385fe0db72edfcb31961731b568eff6bb4d8a35cb4b988145718d41f538b4c36
7
- data.tar.gz: ca6bbdaa75becdb24782a026c82fc88d68f15da756914639ff26c31b390496758833f76bdf7d5725be7dc397a9d2bc166ef107624f044e0977b0e1b7465dd4d2
6
+ metadata.gz: f1f362e75e4a2cf7f08d2a89c2c8465516a72f014fc9d5d230a5cbc18195a4c734deb1b0c5bdede79d7126c7450154218b33824b5ab7b778ce033a800f156c68
7
+ data.tar.gz: b00a94be4f5c30d482412abfb0e395c46804195b6c64ab57ba0f4cb4f01481bf2ff6ae4b32f0b51177859b496f8253413bbe8672602390f80b71df7a31b8a500
@@ -1,3 +1,16 @@
1
+ ## Rails 5.2.0.rc1 (January 30, 2018) ##
2
+
3
+ * Models using the attributes API with a proc default can now be marshalled.
4
+
5
+ Fixes #31216.
6
+
7
+ *Sean Griffin*
8
+
9
+ * Fix to working before/after validation callbacks on multiple contexts.
10
+
11
+ *Yoshiyuki Hirano*
12
+
13
+
1
14
  ## Rails 5.2.0.beta2 (November 28, 2017) ##
2
15
 
3
16
  * No changes.
@@ -1,4 +1,4 @@
1
- Copyright (c) 2004-2017 David Heinemeier Hansson
1
+ Copyright (c) 2004-2018 David Heinemeier Hansson
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -251,11 +251,11 @@ Active Model is released under the MIT license:
251
251
 
252
252
  == Support
253
253
 
254
- API documentation is at
254
+ API documentation is at:
255
255
 
256
256
  * http://api.rubyonrails.org
257
257
 
258
- Bug reports can be filed for the Ruby on Rails project here:
258
+ Bug reports for the Ruby on Rails project can be filed here:
259
259
 
260
260
  * https://github.com/rails/rails/issues
261
261
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  #--
4
- # Copyright (c) 2004-2017 David Heinemeier Hansson
4
+ # Copyright (c) 2004-2018 David Heinemeier Hansson
5
5
  #
6
6
  # Permission is hereby granted, free of charge, to any person obtaining
7
7
  # a copy of this software and associated documentation files (the
@@ -233,6 +233,10 @@ module ActiveModel
233
233
  false
234
234
  end
235
235
 
236
+ def forgetting_assignment
237
+ dup
238
+ end
239
+
236
240
  def with_type(type)
237
241
  self.class.new(name, type)
238
242
  end
@@ -22,6 +22,28 @@ module ActiveModel
22
22
  self.class.new(name, user_provided_value, type, original_attribute)
23
23
  end
24
24
 
25
+ def marshal_dump
26
+ result = [
27
+ name,
28
+ value_before_type_cast,
29
+ type,
30
+ original_attribute,
31
+ ]
32
+ result << value if defined?(@value)
33
+ result
34
+ end
35
+
36
+ def marshal_load(values)
37
+ name, user_provided_value, type, original_attribute, value = values
38
+ @name = name
39
+ @user_provided_value = user_provided_value
40
+ @type = type
41
+ @original_attribute = original_attribute
42
+ if values.length == 5
43
+ @value = value
44
+ end
45
+ end
46
+
25
47
  protected
26
48
 
27
49
  attr_reader :user_provided_value
@@ -35,6 +35,10 @@ module ActiveModel
35
35
  end
36
36
  end
37
37
 
38
+ def changed_attribute_names
39
+ attr_names.select { |attr| changed?(attr) }
40
+ end
41
+
38
42
  def any_changes?
39
43
  attr_names.any? { |attr| changed?(attr) }
40
44
  end
@@ -109,8 +113,5 @@ module ActiveModel
109
113
 
110
114
  def original_value(*)
111
115
  end
112
-
113
- def force_change(*)
114
- end
115
116
  end
116
117
  end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/core_ext/object/deep_dup"
3
4
  require "active_model/attribute_set/builder"
4
5
  require "active_model/attribute_set/yaml_encoder"
5
6
 
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/object/deep_dup"
4
3
  require "active_model/attribute_set"
5
4
  require "active_model/attribute/user_provided_default"
6
5
 
@@ -24,7 +23,7 @@ module ActiveModel
24
23
  end
25
24
  self.attribute_types = attribute_types.merge(name => type)
26
25
  define_default_attribute(name, options.fetch(:default, NO_DEFAULT_PROVIDED), type)
27
- define_attribute_methods(name)
26
+ define_attribute_method(name)
28
27
  end
29
28
 
30
29
  private
@@ -3,6 +3,7 @@
3
3
  require "active_support/hash_with_indifferent_access"
4
4
  require "active_support/core_ext/object/duplicable"
5
5
  require "active_model/attribute_mutation_tracker"
6
+ require "active_model/attribute_set"
6
7
 
7
8
  module ActiveModel
8
9
  # == Active \Model \Dirty
@@ -142,9 +143,8 @@ module ActiveModel
142
143
  end
143
144
 
144
145
  def changes_applied # :nodoc:
145
- @previously_changed = changes
146
+ _prepare_changes
146
147
  @mutations_before_last_save = mutations_from_database
147
- @attributes_changed_by_setter = ActiveSupport::HashWithIndifferentAccess.new
148
148
  forget_attribute_assignments
149
149
  @mutations_from_database = nil
150
150
  end
@@ -155,7 +155,7 @@ module ActiveModel
155
155
  # person.name = 'bob'
156
156
  # person.changed? # => true
157
157
  def changed?
158
- changed_attributes.present?
158
+ mutations_from_database.any_changes?
159
159
  end
160
160
 
161
161
  # Returns an array with the name of the attributes with unsaved changes.
@@ -164,24 +164,24 @@ module ActiveModel
164
164
  # person.name = 'bob'
165
165
  # person.changed # => ["name"]
166
166
  def changed
167
- changed_attributes.keys
167
+ mutations_from_database.changed_attribute_names
168
168
  end
169
169
 
170
170
  # Handles <tt>*_changed?</tt> for +method_missing+.
171
171
  def attribute_changed?(attr, from: OPTION_NOT_GIVEN, to: OPTION_NOT_GIVEN) # :nodoc:
172
- !!changes_include?(attr) &&
172
+ !!mutations_from_database.changed?(attr) &&
173
173
  (to == OPTION_NOT_GIVEN || to == _read_attribute(attr)) &&
174
- (from == OPTION_NOT_GIVEN || from == changed_attributes[attr])
174
+ (from == OPTION_NOT_GIVEN || from == attribute_was(attr))
175
175
  end
176
176
 
177
177
  # Handles <tt>*_was</tt> for +method_missing+.
178
178
  def attribute_was(attr) # :nodoc:
179
- attribute_changed?(attr) ? changed_attributes[attr] : _read_attribute(attr)
179
+ mutations_from_database.original_value(attr)
180
180
  end
181
181
 
182
182
  # Handles <tt>*_previously_changed?</tt> for +method_missing+.
183
183
  def attribute_previously_changed?(attr) #:nodoc:
184
- previous_changes_include?(attr)
184
+ mutations_before_last_save.changed?(attr)
185
185
  end
186
186
 
187
187
  # Restore all previous data of the provided attributes.
@@ -191,15 +191,12 @@ module ActiveModel
191
191
 
192
192
  # Clears all dirty data: current changes and previous changes.
193
193
  def clear_changes_information
194
- @previously_changed = ActiveSupport::HashWithIndifferentAccess.new
195
194
  @mutations_before_last_save = nil
196
- @attributes_changed_by_setter = ActiveSupport::HashWithIndifferentAccess.new
197
195
  forget_attribute_assignments
198
196
  @mutations_from_database = nil
199
197
  end
200
198
 
201
199
  def clear_attribute_changes(attr_names)
202
- attributes_changed_by_setter.except!(*attr_names)
203
200
  attr_names.each do |attr_name|
204
201
  clear_attribute_change(attr_name)
205
202
  end
@@ -212,13 +209,7 @@ module ActiveModel
212
209
  # person.name = 'robert'
213
210
  # person.changed_attributes # => {"name" => "bob"}
214
211
  def changed_attributes
215
- # This should only be set by methods which will call changed_attributes
216
- # multiple times when it is known that the computed value cannot change.
217
- if defined?(@cached_changed_attributes)
218
- @cached_changed_attributes
219
- else
220
- attributes_changed_by_setter.reverse_merge(mutations_from_database.changed_values).freeze
221
- end
212
+ mutations_from_database.changed_values.freeze
222
213
  end
223
214
 
224
215
  # Returns a hash of changed attributes indicating their original
@@ -228,9 +219,8 @@ module ActiveModel
228
219
  # person.name = 'bob'
229
220
  # person.changes # => { "name" => ["bill", "bob"] }
230
221
  def changes
231
- cache_changed_attributes do
232
- ActiveSupport::HashWithIndifferentAccess[changed.map { |attr| [attr, attribute_change(attr)] }]
233
- end
222
+ _prepare_changes
223
+ mutations_from_database.changes
234
224
  end
235
225
 
236
226
  # Returns a hash of attributes that were changed before the model was saved.
@@ -240,8 +230,7 @@ module ActiveModel
240
230
  # person.save
241
231
  # person.previous_changes # => {"name" => ["bob", "robert"]}
242
232
  def previous_changes
243
- @previously_changed ||= ActiveSupport::HashWithIndifferentAccess.new
244
- @previously_changed.merge(mutations_before_last_save.changes)
233
+ mutations_before_last_save.changes
245
234
  end
246
235
 
247
236
  def attribute_changed_in_place?(attr_name) # :nodoc:
@@ -257,11 +246,17 @@ module ActiveModel
257
246
  unless defined?(@mutations_from_database)
258
247
  @mutations_from_database = nil
259
248
  end
260
- @mutations_from_database ||= if defined?(@attributes)
261
- ActiveModel::AttributeMutationTracker.new(@attributes)
262
- else
263
- NullMutationTracker.instance
249
+
250
+ unless defined?(@attributes)
251
+ @_pseudo_attributes = true
252
+ @attributes = AttributeSet.new(
253
+ Hash.new { |h, attr|
254
+ h[attr] = Attribute.with_cast_value(attr, _clone_attribute(attr), Type.default_value)
255
+ }
256
+ )
264
257
  end
258
+
259
+ @mutations_from_database ||= ActiveModel::AttributeMutationTracker.new(@attributes)
265
260
  end
266
261
 
267
262
  def forget_attribute_assignments
@@ -272,68 +267,45 @@ module ActiveModel
272
267
  @mutations_before_last_save ||= ActiveModel::NullMutationTracker.instance
273
268
  end
274
269
 
275
- def cache_changed_attributes
276
- @cached_changed_attributes = changed_attributes
277
- yield
278
- ensure
279
- clear_changed_attributes_cache
280
- end
281
-
282
- def clear_changed_attributes_cache
283
- remove_instance_variable(:@cached_changed_attributes) if defined?(@cached_changed_attributes)
284
- end
285
-
286
- # Returns +true+ if attr_name is changed, +false+ otherwise.
287
- def changes_include?(attr_name)
288
- attributes_changed_by_setter.include?(attr_name) || mutations_from_database.changed?(attr_name)
289
- end
290
- alias attribute_changed_by_setter? changes_include?
291
-
292
- # Returns +true+ if attr_name were changed before the model was saved,
293
- # +false+ otherwise.
294
- def previous_changes_include?(attr_name)
295
- previous_changes.include?(attr_name)
296
- end
297
-
298
270
  # Handles <tt>*_change</tt> for +method_missing+.
299
271
  def attribute_change(attr)
300
- [changed_attributes[attr], _read_attribute(attr)] if attribute_changed?(attr)
272
+ [attribute_was(attr), _read_attribute(attr)] if attribute_changed?(attr)
301
273
  end
302
274
 
303
275
  # Handles <tt>*_previous_change</tt> for +method_missing+.
304
276
  def attribute_previous_change(attr)
305
- previous_changes[attr] if attribute_previously_changed?(attr)
277
+ mutations_before_last_save.change_to_attribute(attr)
306
278
  end
307
279
 
308
280
  # Handles <tt>*_will_change!</tt> for +method_missing+.
309
281
  def attribute_will_change!(attr)
310
- unless attribute_changed?(attr)
311
- begin
312
- value = _read_attribute(attr)
313
- value = value.duplicable? ? value.clone : value
314
- rescue TypeError, NoMethodError
315
- end
316
-
317
- set_attribute_was(attr, value)
282
+ attr = attr.to_s
283
+ mutations_from_database.force_change(attr).tap do
284
+ @attributes[attr] if defined?(@_pseudo_attributes)
318
285
  end
319
- mutations_from_database.force_change(attr)
320
286
  end
321
287
 
322
288
  # Handles <tt>restore_*!</tt> for +method_missing+.
323
289
  def restore_attribute!(attr)
324
290
  if attribute_changed?(attr)
325
- __send__("#{attr}=", changed_attributes[attr])
291
+ __send__("#{attr}=", attribute_was(attr))
326
292
  clear_attribute_changes([attr])
327
293
  end
328
294
  end
329
295
 
330
- def attributes_changed_by_setter
331
- @attributes_changed_by_setter ||= ActiveSupport::HashWithIndifferentAccess.new
296
+ def _prepare_changes
297
+ if defined?(@_pseudo_attributes)
298
+ changed.each do |attr|
299
+ @attributes.write_from_user(attr, _read_attribute(attr))
300
+ end
301
+ end
332
302
  end
333
303
 
334
- # Force an attribute to have a particular "before" value
335
- def set_attribute_was(attr, old_value)
336
- attributes_changed_by_setter[attr] = old_value
304
+ def _clone_attribute(attr)
305
+ value = _read_attribute(attr)
306
+ value.duplicable? ? value.clone : value
307
+ rescue TypeError, NoMethodError
308
+ value
337
309
  end
338
310
  end
339
311
  end
@@ -10,7 +10,7 @@ module ActiveModel
10
10
  MAJOR = 5
11
11
  MINOR = 2
12
12
  TINY = 0
13
- PRE = "beta2"
13
+ PRE = "rc1"
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
16
  end
@@ -29,7 +29,7 @@ module ActiveModel
29
29
  # <tt>to_key</tt> returns an Enumerable of all (primary) key attributes
30
30
  # of the model, and is used to a generate unique DOM id for the object.
31
31
  def test_to_key
32
- assert model.respond_to?(:to_key), "The model should respond to to_key"
32
+ assert_respond_to model, :to_key
33
33
  def model.persisted?() false end
34
34
  assert model.to_key.nil?, "to_key should return nil when `persisted?` returns false"
35
35
  end
@@ -44,7 +44,7 @@ module ActiveModel
44
44
  # tests for this behavior in lint because it doesn't make sense to force
45
45
  # any of the possible implementation strategies on the implementer.
46
46
  def test_to_param
47
- assert model.respond_to?(:to_param), "The model should respond to to_param"
47
+ assert_respond_to model, :to_param
48
48
  def model.to_key() [1] end
49
49
  def model.persisted?() false end
50
50
  assert model.to_param.nil?, "to_param should return nil when `persisted?` returns false"
@@ -56,7 +56,7 @@ module ActiveModel
56
56
  # <tt>to_partial_path</tt> is used for looking up partials. For example,
57
57
  # a BlogPost model might return "blog_posts/blog_post".
58
58
  def test_to_partial_path
59
- assert model.respond_to?(:to_partial_path), "The model should respond to to_partial_path"
59
+ assert_respond_to model, :to_partial_path
60
60
  assert_kind_of String, model.to_partial_path
61
61
  end
62
62
 
@@ -68,7 +68,7 @@ module ActiveModel
68
68
  # will route to the create action. If it is persisted, a form for the
69
69
  # object will route to the update action.
70
70
  def test_persisted?
71
- assert model.respond_to?(:persisted?), "The model should respond to persisted?"
71
+ assert_respond_to model, :persisted?
72
72
  assert_boolean model.persisted?, "persisted?"
73
73
  end
74
74
 
@@ -79,14 +79,14 @@ module ActiveModel
79
79
  #
80
80
  # Check ActiveModel::Naming for more information.
81
81
  def test_model_naming
82
- assert model.class.respond_to?(:model_name), "The model class should respond to model_name"
82
+ assert_respond_to model.class, :model_name
83
83
  model_name = model.class.model_name
84
- assert model_name.respond_to?(:to_str)
85
- assert model_name.human.respond_to?(:to_str)
86
- assert model_name.singular.respond_to?(:to_str)
87
- assert model_name.plural.respond_to?(:to_str)
84
+ assert_respond_to model_name, :to_str
85
+ assert_respond_to model_name.human, :to_str
86
+ assert_respond_to model_name.singular, :to_str
87
+ assert_respond_to model_name.plural, :to_str
88
88
 
89
- assert model.respond_to?(:model_name), "The model instance should respond to model_name"
89
+ assert_respond_to model, :model_name
90
90
  assert_equal model.model_name, model.class.model_name
91
91
  end
92
92
 
@@ -100,13 +100,13 @@ module ActiveModel
100
100
  # If localization is used, the strings should be localized for the current
101
101
  # locale. If no error is present, the method should return an empty array.
102
102
  def test_errors_aref
103
- assert model.respond_to?(:errors), "The model should respond to errors"
103
+ assert_respond_to model, :errors
104
104
  assert model.errors[:hello].is_a?(Array), "errors#[] should return an Array"
105
105
  end
106
106
 
107
107
  private
108
108
  def model
109
- assert @model.respond_to?(:to_model), "The object should respond to to_model"
109
+ assert_respond_to @model, :to_model
110
110
  @model.to_model
111
111
  end
112
112
 
@@ -24,7 +24,7 @@ module ActiveModel
24
24
  class << self
25
25
  attr_accessor :registry # :nodoc:
26
26
 
27
- # Add a new type to the registry, allowing it to be get through ActiveModel::Type#lookup
27
+ # Add a new type to the registry, allowing it to be gotten through ActiveModel::Type#lookup
28
28
  def register(type_name, klass = nil, **options, &block)
29
29
  registry.register(type_name, klass, **options, &block)
30
30
  end
@@ -164,14 +164,14 @@ module ActiveModel
164
164
 
165
165
  if options.key?(:on)
166
166
  options = options.dup
167
+ options[:on] = Array(options[:on])
167
168
  options[:if] = Array(options[:if])
168
169
  options[:if].unshift ->(o) {
169
- !(Array(options[:on]) & Array(o.validation_context)).empty?
170
+ !(options[:on] & Array(o.validation_context)).empty?
170
171
  }
171
172
  end
172
173
 
173
- args << options
174
- set_callback(:validate, *args, &block)
174
+ set_callback(:validate, *args, options, &block)
175
175
  end
176
176
 
177
177
  # List all validators that are being used to validate the model using
@@ -54,15 +54,18 @@ module ActiveModel
54
54
  # person.valid? # => true
55
55
  # person.name # => "bob"
56
56
  def before_validation(*args, &block)
57
- options = args.last
58
- if options.is_a?(Hash) && options[:on]
59
- options[:if] = Array(options[:if])
57
+ options = args.extract_options!
58
+
59
+ if options.key?(:on)
60
+ options = options.dup
60
61
  options[:on] = Array(options[:on])
62
+ options[:if] = Array(options[:if])
61
63
  options[:if].unshift ->(o) {
62
- options[:on].include? o.validation_context
64
+ !(options[:on] & Array(o.validation_context)).empty?
63
65
  }
64
66
  end
65
- set_callback(:validation, :before, *args, &block)
67
+
68
+ set_callback(:validation, :before, *args, options, &block)
66
69
  end
67
70
 
68
71
  # Defines a callback that will get called right after validation.
@@ -93,15 +96,18 @@ module ActiveModel
93
96
  # person.status # => true
94
97
  def after_validation(*args, &block)
95
98
  options = args.extract_options!
99
+ options = options.dup
96
100
  options[:prepend] = true
97
- options[:if] = Array(options[:if])
98
- if options[:on]
101
+
102
+ if options.key?(:on)
99
103
  options[:on] = Array(options[:on])
104
+ options[:if] = Array(options[:if])
100
105
  options[:if].unshift ->(o) {
101
- options[:on].include? o.validation_context
106
+ !(options[:on] & Array(o.validation_context)).empty?
102
107
  }
103
108
  end
104
- set_callback(:validation, :after, *(args << options), &block)
109
+
110
+ set_callback(:validation, :after, *args, options, &block)
105
111
  end
106
112
  end
107
113
 
@@ -154,7 +154,7 @@ module ActiveModel
154
154
  # When creating custom validators, it might be useful to be able to specify
155
155
  # additional default keys. This can be done by overwriting this method.
156
156
  def _validates_default_keys
157
- [:if, :unless, :on, :allow_blank, :allow_nil , :strict]
157
+ [:if, :unless, :on, :allow_blank, :allow_nil, :strict]
158
158
  end
159
159
 
160
160
  def _parse_validates_options(options)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activemodel
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.2.0.beta2
4
+ version: 5.2.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-11-28 00:00:00.000000000 Z
11
+ date: 2018-01-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 5.2.0.beta2
19
+ version: 5.2.0.rc1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 5.2.0.beta2
26
+ version: 5.2.0.rc1
27
27
  description: A toolkit for building modeling frameworks like Active Record. Rich support
28
28
  for attributes, callbacks, validations, serialization, internationalization, and
29
29
  testing.
@@ -100,8 +100,8 @@ homepage: http://rubyonrails.org
100
100
  licenses:
101
101
  - MIT
102
102
  metadata:
103
- source_code_uri: https://github.com/rails/rails/tree/v5.2.0.beta2/activemodel
104
- changelog_uri: https://github.com/rails/rails/blob/v5.2.0.beta2/activemodel/CHANGELOG.md
103
+ source_code_uri: https://github.com/rails/rails/tree/v5.2.0.rc1/activemodel
104
+ changelog_uri: https://github.com/rails/rails/blob/v5.2.0.rc1/activemodel/CHANGELOG.md
105
105
  post_install_message:
106
106
  rdoc_options: []
107
107
  require_paths:
@@ -118,7 +118,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
118
118
  version: 1.3.1
119
119
  requirements: []
120
120
  rubyforge_project:
121
- rubygems_version: 2.6.12
121
+ rubygems_version: 2.7.3
122
122
  signing_key:
123
123
  specification_version: 4
124
124
  summary: A toolkit for building modeling frameworks (part of Rails).