/usr/lib/ruby/vendor_ruby/active_model/dirty.rb is in ruby-activemodel-3.2 3.2.16-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | require 'active_model/attribute_methods'
require 'active_support/hash_with_indifferent_access'
require 'active_support/core_ext/object/duplicable'
module ActiveModel
# == Active Model Dirty
#
# Provides a way to track changes in your object in the same way as
# Active Record does.
#
# The requirements for implementing ActiveModel::Dirty are:
#
# * <tt>include ActiveModel::Dirty</tt> in your object
# * Call <tt>define_attribute_methods</tt> passing each method you want to
# track
# * Call <tt>attr_name_will_change!</tt> before each change to the tracked
# attribute
#
# If you wish to also track previous changes on save or update, you need to
# add
#
# @previously_changed = changes
#
# inside of your save or update method.
#
# A minimal implementation could be:
#
# class Person
#
# include ActiveModel::Dirty
#
# define_attribute_methods [:name]
#
# def name
# @name
# end
#
# def name=(val)
# name_will_change! unless val == @name
# @name = val
# end
#
# def save
# @previously_changed = changes
# @changed_attributes.clear
# end
#
# end
#
# == Examples:
#
# A newly instantiated object is unchanged:
# person = Person.find_by_name('Uncle Bob')
# person.changed? # => false
#
# Change the name:
# person.name = 'Bob'
# person.changed? # => true
# person.name_changed? # => true
# person.name_was # => 'Uncle Bob'
# person.name_change # => ['Uncle Bob', 'Bob']
# person.name = 'Bill'
# person.name_change # => ['Uncle Bob', 'Bill']
#
# Save the changes:
# person.save
# person.changed? # => false
# person.name_changed? # => false
#
# Assigning the same value leaves the attribute unchanged:
# person.name = 'Bill'
# person.name_changed? # => false
# person.name_change # => nil
#
# Which attributes have changed?
# person.name = 'Bob'
# person.changed # => ['name']
# person.changes # => { 'name' => ['Bill', 'Bob'] }
#
# If an attribute is modified in-place then make use of <tt>[attribute_name]_will_change!</tt>
# to mark that the attribute is changing. Otherwise ActiveModel can't track changes to
# in-place attributes.
#
# person.name_will_change!
# person.name << 'y'
# person.name_change # => ['Bill', 'Billy']
module Dirty
extend ActiveSupport::Concern
include ActiveModel::AttributeMethods
included do
attribute_method_suffix '_changed?', '_change', '_will_change!', '_was'
attribute_method_affix :prefix => 'reset_', :suffix => '!'
end
# Returns true if any attribute have unsaved changes, false otherwise.
# person.changed? # => false
# person.name = 'bob'
# person.changed? # => true
def changed?
changed_attributes.any?
end
# List of attributes with unsaved changes.
# person.changed # => []
# person.name = 'bob'
# person.changed # => ['name']
def changed
changed_attributes.keys
end
# Map of changed attrs => [original value, new value].
# person.changes # => {}
# person.name = 'bob'
# person.changes # => { 'name' => ['bill', 'bob'] }
def changes
HashWithIndifferentAccess[changed.map { |attr| [attr, attribute_change(attr)] }]
end
# Map of attributes that were changed when the model was saved.
# person.name # => 'bob'
# person.name = 'robert'
# person.save
# person.previous_changes # => {'name' => ['bob, 'robert']}
def previous_changes
@previously_changed
end
# Map of change <tt>attr => original value</tt>.
def changed_attributes
@changed_attributes ||= {}
end
private
# Handle <tt>*_changed?</tt> for +method_missing+.
def attribute_changed?(attr)
changed_attributes.include?(attr)
end
# Handle <tt>*_change</tt> for +method_missing+.
def attribute_change(attr)
[changed_attributes[attr], __send__(attr)] if attribute_changed?(attr)
end
# Handle <tt>*_was</tt> for +method_missing+.
def attribute_was(attr)
attribute_changed?(attr) ? changed_attributes[attr] : __send__(attr)
end
# Handle <tt>*_will_change!</tt> for +method_missing+.
def attribute_will_change!(attr)
begin
value = __send__(attr)
value = value.duplicable? ? value.clone : value
rescue TypeError, NoMethodError
end
changed_attributes[attr] = value unless changed_attributes.include?(attr)
end
# Handle <tt>reset_*!</tt> for +method_missing+.
def reset_attribute!(attr)
__send__("#{attr}=", changed_attributes[attr]) if attribute_changed?(attr)
end
end
end
|