Skip to content

Commit

Permalink
Refactor Dirty module a bit
Browse files Browse the repository at this point in the history
  • Loading branch information
andrykonchin committed Jan 13, 2023
1 parent b759272 commit da97dac
Showing 1 changed file with 42 additions and 44 deletions.
86 changes: 42 additions & 44 deletions lib/dynamoid/dirty.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,18 @@ module Dirty
module ClassMethods
def update_fields(*)
super.tap do |model|
model.send(:clear_changes_information) if model
model.clear_changes_information if model
end
end

def upsert(*)
super.tap do |model|
model.send(:clear_changes_information) if model
model.clear_changes_information if model
end
end

def from_database(*)
super.tap do |m|
m.send(:clear_changes_information)
end
super.tap(&:clear_changes_information)
end
end

Expand Down Expand Up @@ -110,7 +108,7 @@ def changed
#
# @return [ActiveSupport::HashWithIndifferentAccess]
def changes
ActiveSupport::HashWithIndifferentAccess[changed.map { |attr| [attr, attribute_change(attr)] }]
ActiveSupport::HashWithIndifferentAccess[changed.map { |name| [name, attribute_change(name)] }]
end

# Returns a hash of attributes that were changed before the model was saved.
Expand Down Expand Up @@ -138,22 +136,22 @@ def changed_attributes
end

# Clear all dirty data: current changes and previous changes.
def clear_changes_information # :doc:
def clear_changes_information
@previously_changed = ActiveSupport::HashWithIndifferentAccess.new
@changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
end

# Removes current changes and makes them accessible through +previous_changes+.
def changes_applied # :doc:
# Clears dirty data and moves +changes+ to +previous_changes+.
def changes_applied
@previously_changed = changes
@changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
end

# Remove changes information for the provided attributes.
#
# @param attributes [Array[String]] - a list of attributes to clear changes for
def clear_attribute_changes(attributes)
attributes_changed_by_setter.except!(*attributes)
def clear_attribute_changes(names)
attributes_changed_by_setter.except!(*names)
end

# Handle <tt>*_changed?</tt> for +method_missing+.
Expand All @@ -164,14 +162,14 @@ def clear_attribute_changes(attributes)
# person.attribute_changed?(:name, from: 'Alice', to: 'Bod')
#
# @private
# @param attr [Symbol] attribute name
# @param name [Symbol] attribute name
# @param options [Hash] conditions on +from+ and +to+ value (optional)
# @option options [Symbol] :from previous attribute value
# @option options [Symbol] :to current attribute value
def attribute_changed?(attr, options = {})
result = changes_include?(attr)
result &&= options[:to] == __send__(attr) if options.key?(:to)
result &&= options[:from] == changed_attributes[attr] if options.key?(:from)
def attribute_changed?(name, options = {})
result = changes_include?(name)
result &&= options[:to] == read_attribute(name) if options.key?(:to)
result &&= options[:from] == changed_attributes[name] if options.key?(:from)
result
end

Expand All @@ -182,16 +180,16 @@ def attribute_changed?(attr, options = {})
# person.attribute_was(:name) # => "Alice"
#
# @private
# @param attr [Symbol] attribute name
def attribute_was(attr)
attribute_changed?(attr) ? changed_attributes[attr] : __send__(attr)
# @param name [Symbol] attribute name
def attribute_was(name)
attribute_changed?(name) ? changed_attributes[name] : read_attribute(name)
end

# Restore all previous data of the provided attributes.
#
# @param attributes [Array[Symbol]] a list of attribute names
def restore_attributes(attributes = changed)
attributes.each { |attr| restore_attribute! attr }
def restore_attributes(names = changed)
names.each { |name| restore_attribute! name }
end

# Handles <tt>*_previously_changed?</tt> for +method_missing+.
Expand All @@ -202,10 +200,10 @@ def restore_attributes(attributes = changed)
# person.attribute_changed?(:name) # => true
#
# @private
# @param attr [Symbol] attribute name
# @param name [Symbol] attribute name
# @return [true|false]
def attribute_previously_changed?(attr)
previous_changes_include?(attr)
def attribute_previously_changed?(name)
previous_changes_include?(name)
end

# Handles <tt>*_previous_change</tt> for +method_missing+.
Expand All @@ -216,59 +214,59 @@ def attribute_previously_changed?(attr)
# person.attribute_previously_changed(:name) # => ["Alice", "Bob"]
#
# @private
# @param attr [Symbol]
# @param name [Symbol]
# @return [Array]
def attribute_previous_change(attr)
previous_changes[attr] if attribute_previously_changed?(attr)
def attribute_previous_change(name)
previous_changes[name] if attribute_previously_changed?(name)
end

private

def changes_include?(attr_name)
attributes_changed_by_setter.include?(attr_name)
def changes_include?(name)
attributes_changed_by_setter.include?(name)
end
alias attribute_changed_by_setter? changes_include?


# Handle <tt>*_change</tt> for +method_missing+.
def attribute_change(attr)
[changed_attributes[attr], __send__(attr)] if attribute_changed?(attr)
def attribute_change(name)
[changed_attributes[name], read_attribute(name)] if attribute_changed?(name)
end

# Handle <tt>*_will_change!</tt> for +method_missing+.
def attribute_will_change!(attr)
return if attribute_changed?(attr)
def attribute_will_change!(name)
return if attribute_changed?(name)

begin
value = __send__(attr)
value = read_attribute(name)
value = value.duplicable? ? value.clone : value
rescue TypeError, NoMethodError
end

set_attribute_was(attr, value)
set_attribute_was(name, value)
end

# Handle <tt>restore_*!</tt> for +method_missing+.
def restore_attribute!(attr)
if attribute_changed?(attr)
__send__("#{attr}=", changed_attributes[attr])
clear_attribute_changes([attr])
def restore_attribute!(name)
if attribute_changed?(name)
write_attribute(name, changed_attributes[name])
clear_attribute_changes([name])
end
end

# Returns +true+ if attr_name were changed before the model was saved,
# Returns +true+ if name were changed before the model was saved,
# +false+ otherwise.
def previous_changes_include?(attr_name)
previous_changes.include?(attr_name)
def previous_changes_include?(name)
previous_changes.include?(name)
end

# This is necessary because `changed_attributes` might be overridden in
# other implemntations (e.g. in `ActiveRecord`)
alias attributes_changed_by_setter changed_attributes

# Force an attribute to have a particular "before" value
def set_attribute_was(attr, old_value)
attributes_changed_by_setter[attr] = old_value
def set_attribute_was(name, old_value)
attributes_changed_by_setter[name] = old_value
end
end
end

0 comments on commit da97dac

Please sign in to comment.