module ActiveModel::Dirty

def attribute_change(attr)

Handles *_change for +method_missing+.
def attribute_change(attr)
  [changed_attributes[attr], __send__(attr)] if attribute_changed?(attr)
end

def attribute_changed?(attr, from: OPTION_NOT_GIVEN, to: OPTION_NOT_GIVEN) # :nodoc:

:nodoc:
Handles *_changed? for +method_missing+.
def attribute_changed?(attr, from: OPTION_NOT_GIVEN, to: OPTION_NOT_GIVEN) # :nodoc:
  !!changes_include?(attr) &&
    (to == OPTION_NOT_GIVEN || to == __send__(attr)) &&
    (from == OPTION_NOT_GIVEN || from == changed_attributes[attr])
end

def attribute_previous_change(attr)

Handles *_previous_change for +method_missing+.
def attribute_previous_change(attr)
  previous_changes[attr] if attribute_previously_changed?(attr)
end

def attribute_previously_changed?(attr) #:nodoc:

:nodoc:
Handles *_previously_changed? for +method_missing+.
def attribute_previously_changed?(attr) #:nodoc:
  previous_changes_include?(attr)
end

def attribute_was(attr) # :nodoc:

:nodoc:
Handles *_was for +method_missing+.
def attribute_was(attr) # :nodoc:
  attribute_changed?(attr) ? changed_attributes[attr] : __send__(attr)
end

def attribute_will_change!(attr)

Handles *_will_change! for +method_missing+.
def attribute_will_change!(attr)
  return if attribute_changed?(attr)
  begin
    value = __send__(attr)
    value = value.duplicable? ? value.clone : value
  rescue TypeError, NoMethodError
  end
  set_attribute_was(attr, value)
end

def changed

person.changed # => ["name"]
person.name = 'bob'
person.changed # => []

Returns an array with the name of the attributes with unsaved changes.
def changed
  changed_attributes.keys
end

def changed?

person.changed? # => true
person.name = 'bob'
person.changed? # => false

Returns +true+ if any of the attributes have unsaved changes, +false+ otherwise.
def changed?
  changed_attributes.present?
end

def changed_attributes

person.changed_attributes # => {"name" => "bob"}
person.name = 'robert'
person.name # => "bob"

values like attr => original value.
Returns a hash of the attributes with unsaved changes indicating their original
def changed_attributes
  @changed_attributes ||= ActiveSupport::HashWithIndifferentAccess.new
end

def changes

person.changes # => { "name" => ["bill", "bob"] }
person.name = 'bob'
person.changes # => {}

and new values like attr => [original value, new value].
Returns a hash of changed attributes indicating their original
def changes
  ActiveSupport::HashWithIndifferentAccess[changed.map { |attr| [attr, attribute_change(attr)] }]
end

def changes_applied # :doc:

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

def changes_include?(attr_name)

Returns +true+ if attr_name is changed, +false+ otherwise.
def changes_include?(attr_name)
  attributes_changed_by_setter.include?(attr_name)
end

def clear_attribute_changes(attributes) # :doc:

:doc:
Remove changes information for the provided attributes.
def clear_attribute_changes(attributes) # :doc:
  attributes_changed_by_setter.except!(*attributes)
end

def clear_changes_information # :doc:

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

def previous_changes

person.previous_changes # => {"name" => ["bob", "robert"]}
person.save
person.name = 'robert'
person.name # => "bob"

Returns a hash of attributes that were changed before the model was saved.
def previous_changes
  @previously_changed ||= ActiveSupport::HashWithIndifferentAccess.new
end

def previous_changes_include?(attr_name)

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

def restore_attribute!(attr)

Handles restore_*! for +method_missing+.
def restore_attribute!(attr)
  if attribute_changed?(attr)
    __send__("#{attr}=", changed_attributes[attr])
    clear_attribute_changes([attr])
  end
end

def restore_attributes(attributes = changed)

Restore all previous data of the provided attributes.
def restore_attributes(attributes = changed)
  attributes.each { |attr| restore_attribute! attr }
end

def set_attribute_was(attr, old_value)

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