1
1
# frozen_string_literal: true
2
- # rubocop:todo all
3
2
4
3
module Mongoid
5
-
6
4
# Defines behavior for dirty tracking.
7
5
module Changeable
8
6
extend ActiveSupport ::Concern
@@ -53,12 +51,10 @@ def changed_attributes
53
51
#
54
52
# @return [ Hash<String, Array<Object, Object> ] The changes.
55
53
def changes
56
- _changes = { }
57
- changed . each do |attr |
54
+ changed . each_with_object ( { } ) do |attr , changes |
58
55
change = attribute_change ( attr )
59
- _changes [ attr ] = change if change
60
- end
61
- _changes . with_indifferent_access
56
+ changes [ attr ] = change if change
57
+ end . with_indifferent_access
62
58
end
63
59
64
60
# Call this method after save, so the changes can be properly switched.
@@ -120,15 +116,15 @@ def remove_change(name)
120
116
def setters
121
117
mods = { }
122
118
changes . each_pair do |name , changes |
123
- if changes
124
- old , new = changes
125
- field = fields [ name ]
126
- key = atomic_attribute_name ( name )
127
- if field && field . resizable?
128
- field . add_atomic_changes ( self , name , key , mods , new , old )
129
- else
130
- mods [ key ] = new unless atomic_unsets . include? ( key )
131
- end
119
+ next unless changes
120
+
121
+ old , new = changes
122
+ field = fields [ name ]
123
+ key = atomic_attribute_name ( name )
124
+ if field &. resizable?
125
+ field . add_atomic_changes ( self , name , key , mods , new , old )
126
+ else
127
+ mods [ key ] = new unless atomic_unsets . include? ( key )
132
128
end
133
129
end
134
130
mods
@@ -164,24 +160,19 @@ def saved_change_to_attribute(attr)
164
160
# in an attribute during the save that triggered the callbacks to run.
165
161
#
166
162
# @param [ String ] attr The name of the attribute.
167
- # @param **kwargs The optional keyword arguments.
168
- #
169
- # @option **kwargs [ Object ] :from The object the attribute was changed from.
170
- # @option **kwargs [ Object ] :to The object the attribute was changed to.
163
+ # @param [ Object ] from The object the attribute was changed from (optional).
164
+ # @param [ Object ] to The object the attribute was changed to (optional).
171
165
#
172
166
# @return [ true | false ] Whether the attribute has changed during the last save.
173
- def saved_change_to_attribute? ( attr , ** kwargs )
167
+ def saved_change_to_attribute? ( attr , from : Utils :: PLACEHOLDER , to : Utils :: PLACEHOLDER )
174
168
changes = saved_change_to_attribute ( attr )
175
169
return false unless changes . is_a? ( Array )
176
- if kwargs . key? ( :from ) && kwargs . key? ( :to )
177
- changes . first == kwargs [ :from ] && changes . last == kwargs [ :to ]
178
- elsif kwargs . key? ( :from )
179
- changes . first == kwargs [ :from ]
180
- elsif kwargs . key? ( :to )
181
- changes . last == kwargs [ :to ]
182
- else
183
- true
184
- end
170
+
171
+ return true if Utils . placeholder? ( from ) && Utils . placeholder? ( to )
172
+ return changes . first == from if Utils . placeholder? ( to )
173
+ return changes . last == to if Utils . placeholder? ( from )
174
+
175
+ changes . first == from && changes . last == to
185
176
end
186
177
187
178
# Returns whether this attribute change the next time we save.
@@ -227,31 +218,48 @@ def attributes_before_last_save
227
218
# @return [ Array<Object> ] The old and new values.
228
219
def attribute_change ( attr )
229
220
attr = database_field_name ( attr )
230
- [ changed_attributes [ attr ] , attributes [ attr ] ] if attribute_changed? ( attr )
221
+ [ changed_attributes [ attr ] , attributes [ attr ] ] if attribute_changed? ( attr )
222
+ end
223
+
224
+ # A class for representing the default value that an attribute was changed
225
+ # from or to.
226
+ #
227
+ # @api private
228
+ class Anything
229
+ # `Anything` objects are always equal to everything. This simplifies
230
+ # the logic for asking whether an attribute has changed or not. If the
231
+ # `from` or `to` value is a `Anything` (because it was not
232
+ # explicitly given), any comparison with it will suggest the value has
233
+ # not changed.
234
+ #
235
+ # @param [ Object ] _other The object being compared with this object.
236
+ #
237
+ # @return [ true ] Always returns true.
238
+ def ==( _other )
239
+ true
240
+ end
231
241
end
232
242
243
+ # a singleton object to represent an optional `to` or `from` value
244
+ # that was not explicitly provided to #attribute_changed?
245
+ ATTRIBUTE_UNCHANGED = Anything . new
246
+
233
247
# Determine if a specific attribute has changed.
234
248
#
235
249
# @example Has the attribute changed?
236
250
# model.attribute_changed?("name")
237
251
#
238
252
# @param [ String ] attr The name of the attribute.
239
- # @param **kwargs The optional keyword arguments.
240
- #
241
- # @option **kwargs [ Object ] :from The object the attribute was changed from.
242
- # @option **kwargs [ Object ] :to The object the attribute was changed to.
253
+ # @param [ Object ] from The object the attribute was changed from (optional).
254
+ # @param [ Object ] to The object the attribute was changed to (optional).
243
255
#
244
256
# @return [ true | false ] Whether the attribute has changed.
245
- def attribute_changed? ( attr , ** kwargs )
257
+ def attribute_changed? ( attr , from : ATTRIBUTE_UNCHANGED , to : ATTRIBUTE_UNCHANGED )
246
258
attr = database_field_name ( attr )
247
259
return false unless changed_attributes . key? ( attr )
248
260
return false if changed_attributes [ attr ] == attributes [ attr ]
249
- if kwargs . key? ( :from )
250
- return false if changed_attributes [ attr ] != kwargs [ :from ]
251
- end
252
- if kwargs . key? ( :to )
253
- return false if attributes [ attr ] != kwargs [ :to ]
254
- end
261
+ return false if from != changed_attributes [ attr ]
262
+ return false if to != attributes [ attr ]
255
263
256
264
true
257
265
end
@@ -265,8 +273,8 @@ def attribute_changed?(attr, **kwargs)
265
273
#
266
274
# @return [ true | false ] If the attribute differs.
267
275
def attribute_changed_from_default? ( attr )
268
- field = fields [ attr ]
269
- return false unless field
276
+ return false unless ( field = fields [ attr ] )
277
+
270
278
attributes [ attr ] != field . eval_default ( self )
271
279
end
272
280
@@ -309,9 +317,9 @@ def attribute_previously_was(attr)
309
317
#
310
318
# @return [ Object ] The old value.
311
319
def attribute_will_change! ( attr )
312
- unless changed_attributes . key? ( attr )
313
- changed_attributes [ attr ] = read_raw_attribute ( attr ) . __deep_copy__
314
- end
320
+ return if changed_attributes . key? ( attr )
321
+
322
+ changed_attributes [ attr ] = read_raw_attribute ( attr ) . __deep_copy__
315
323
end
316
324
317
325
# Set the attribute back to its old value.
@@ -329,7 +337,7 @@ def reset_attribute!(attr)
329
337
330
338
def reset_attribute_to_default! ( attr )
331
339
attr = database_field_name ( attr )
332
- if field = fields [ attr ]
340
+ if ( field = fields [ attr ] )
333
341
__send__ ( "#{ attr } =" , field . eval_default ( self ) )
334
342
else
335
343
__send__ ( "#{ attr } =" , nil )
@@ -340,8 +348,8 @@ def reset_attributes_before_type_cast
340
348
@attributes_before_type_cast = @attributes . dup
341
349
end
342
350
351
+ # Class-level methods for changeable objects.
343
352
module ClassMethods
344
-
345
353
private
346
354
347
355
# Generate all the dirty methods needed for the attribute.
@@ -495,7 +503,7 @@ def create_dirty_reset_to_default(name, meth)
495
503
def create_dirty_previously_changed? ( name , meth )
496
504
generated_methods . module_eval do
497
505
re_define_method ( "#{ meth } _previously_changed?" ) do
498
- previous_changes . keys . include ?( name )
506
+ previous_changes . key ?( name )
499
507
end
500
508
end
501
509
end
0 commit comments