<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>lib/acts_as_audited/audit.rb</filename>
    </added>
    <added>
      <filename>lib/acts_as_audited/audit_sweeper.rb</filename>
    </added>
    <added>
      <filename>lib/acts_as_audited/dirty.rb</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -1,9 +1,9 @@
-require 'audit'
+require 'acts_as_audited/audit'
 require 'acts_as_audited'
 
 ActiveRecord::Base.send :include, CollectiveIdea::Acts::Audited
 
 if defined?(ActionController) and defined?(ActionController::Base)
-  require 'audit_sweeper'
+  require 'acts_as_audited/audit_sweeper'
   ActionController::Base.send :include, CollectiveIdea::ActionController::Audited
 end</diff>
      <filename>init.rb</filename>
    </modified>
    <modified>
      <diff>@@ -19,6 +19,12 @@
 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
+class Hash
+  def only(*keys)
+    reject {|k,| !keys.include? k }
+  end
+end
+
 module CollectiveIdea #:nodoc:
   module Acts #:nodoc:
     # Specify this act if you want changes to your model to be saved in an
@@ -31,7 +37,7 @@ module CollectiveIdea #:nodoc:
     # See &lt;tt&gt;CollectiveIdea::Acts::Audited::ClassMethods#acts_as_audited&lt;/tt&gt;
     # for configuration options
     module Audited #:nodoc:
-      CALLBACKS = [:clear_changed_attributes, :audit_create, :audit_update, :audit_destroy]
+      CALLBACKS = [:audit_create, :audit_update, :audit_destroy]
 
       def self.included(base) # :nodoc:
         base.extend ClassMethods
@@ -55,8 +61,6 @@ module CollectiveIdea #:nodoc:
           # don't allow multiple calls
           return if self.included_modules.include?(CollectiveIdea::Acts::Audited::InstanceMethods)
 
-          include CollectiveIdea::Acts::Audited::InstanceMethods
-          
           class_inheritable_reader :non_audited_columns
           class_inheritable_reader :auditing_enabled
 
@@ -64,31 +68,36 @@ module CollectiveIdea #:nodoc:
           except |= [options[:except]].flatten.collect(&amp;:to_s) if options[:except]
           write_inheritable_attribute :non_audited_columns, except
 
-          class_eval do
-            extend CollectiveIdea::Acts::Audited::SingletonMethods
-
-            has_many :audits, :as =&gt; :auditable, :order =&gt; 'audits.version desc'
-            attr_protected :audit_ids
-            Audit.audited_classes &lt;&lt; self unless Audit.audited_classes.include?(self)
-            
-            after_create :audit_create
-            after_update :audit_update
-            after_destroy :audit_destroy
-            after_save :clear_changed_attributes
-            
-            attr_accessor :version
-            
-            alias_method_chain :write_attribute, :auditing
+          has_many :audits, :as =&gt; :auditable, :order =&gt; 'audits.version desc'
+          attr_protected :audit_ids
+          Audit.audited_classes &lt;&lt; self
+          
+          after_create :audit_create
+          before_update :audit_update
+          after_destroy :audit_destroy
+          
+          attr_accessor :version
 
-            write_inheritable_attribute :auditing_enabled, true
+          extend CollectiveIdea::Acts::Audited::SingletonMethods
+          include CollectiveIdea::Acts::Audited::InstanceMethods
+          unless ActiveRecord.const_defined? 'Dirty'
+            require 'acts_as_audited/dirty'
+            include CollectiveIdea::Acts::Audited::Dirty
           end
+          
+          write_inheritable_attribute :auditing_enabled, true
         end
       end
     
       module InstanceMethods
         
-        def changed_attributes
-          @changed_attributes ||= {}
+        def changed_audited_attributes
+          attributes.only(*changed_attributes.keys).except(*non_audited_columns)
+        end
+        
+        # Returns the attributes that are audited
+        def audited_attributes
+          attributes.except(*non_audited_columns)
         end
         
         # Temporarily turns off auditing while saving.
@@ -96,17 +105,6 @@ module CollectiveIdea #:nodoc:
           without_auditing { save }
         end
       
-        # Returns an array of attribute keys that are audited.  See non_audited_columns
-        def audited_attributes
-          self.attributes.keys.select { |k| !self.non_audited_columns.include?(k) }
-        end
-        
-        # If called with no parameters, gets whether the current model has changed.
-        # If called with a single parameter, gets whether the parameter has changed.
-        def changed?(attr_name = nil)
-          attr_name ? changed_attributes.include?(attr_name.to_s) : !changed_attributes.empty?
-        end
-
         # Executes the block with the auditing callbacks disabled.
         #
         #   @foo.without_auditing do
@@ -125,37 +123,33 @@ module CollectiveIdea #:nodoc:
         #   end
         #
         def revisions(from_version = 1)
-          changes(from_version) {|attributes| revision_with(attributes) }
+          changes_from(from_version) {|attributes| revision_with(attributes) }
         end
         
         # Get a specific revision
         def revision(version)
-          revision_with changes(version)
+          revision_with changes_from(version)
         end
         
         def revision_at(date_or_time)
           audit = audits.find(:first, :conditions =&gt; [&quot;created_at &lt;= ?&quot;, date_or_time],
             :order =&gt; &quot;created_at DESC&quot;)
-          revision_with changes(audit.version) if audit
+          revision_with changes_from(audit.version) if audit
         end
 
       private
       
-        def changes(from_version = 1)
-          if from_version == :previous
+        def changes_from(version = 1, &amp;block)
+          if version == :previous
             last_audit = audits.find(:first)
-            from_version = last_audit ? last_audit.version : 1
+            version = last_audit ? last_audit.version : 1
           end
-          changes = {}
-          result = audits.find(:all, :conditions =&gt; ['version &gt;= ?', from_version]).collect do |audit|
-            attributes = (audit.changes || {}).inject({}) do |attrs, (name, values)|
-              attrs[name] = values.first
-              attrs
-            end
-            changes.merge!(attributes.merge!(:version =&gt; audit.version))
-            yield changes if block_given?
+          revisions = audits.find(:all, :conditions =&gt; ['version &gt;= ?', version])
+          if block
+            Audit.reconstruct_attributes(revisions, &amp;block)
+          else
+            Audit.reconstruct_attributes(revisions)
           end
-          block_given? ? result : changes
         end
         
         def revision_with(attributes)
@@ -165,49 +159,29 @@ module CollectiveIdea #:nodoc:
           end
         end
         
-        # Creates a new record in the audits table if applicable
         def audit_create
-          write_audit(:create)
+          write_audit(:create, audited_attributes)
         end
 
         def audit_update
-          write_audit(:update) if changed?
+          changes = changed_audited_attributes
+          write_audit(:update, changes) unless changes.empty?
         end
 
         def audit_destroy
           write_audit(:destroy)
         end
       
-        def write_audit(action = :update, user = nil)
-          self.audits.create :changes =&gt; changed_attributes, :action =&gt; action.to_s, :user =&gt; user
-        end
-
-        # clears current changed attributes.  Called after save.
-        def clear_changed_attributes
-          @changed_attributes = {}
-        end
-        
-        # overload write_attribute to save changes to audited attributes
-        def write_attribute_with_auditing(attr_name, attr_value)
-          attr_name = attr_name.to_s
-          if audited_attributes.include?(attr_name)
-            # get original value
-            old_value = changed_attributes[attr_name] ?
-              changed_attributes[attr_name].first : self[attr_name]
-            write_attribute_without_auditing(attr_name, attr_value)
-            new_value = self[attr_name]
-            
-            changed_attributes[attr_name] = [old_value, new_value] if new_value != old_value
-          else
-            write_attribute_without_auditing(attr_name, attr_value)
-          end
+        def write_audit(action, attributes = {}, user = nil)
+          self.audits.create :action =&gt; action.to_s, :user =&gt; user,
+            :changes =&gt; attributes
         end
 
         CALLBACKS.each do |attr_name| 
           alias_method &quot;orig_#{attr_name}&quot;.to_sym, attr_name
         end
         
-        def empty_callback() end #:nodoc:
+        def empty_callback; end #:nodoc:
 
       end # InstanceMethods
       
@@ -230,8 +204,8 @@ module CollectiveIdea #:nodoc:
         end
         
         def disable_auditing
-          class_eval do 
-            CALLBACKS.each do |attr_name| 
+          class_eval do
+            CALLBACKS.each do |attr_name|
               alias_method attr_name, :empty_callback
             end
           end</diff>
      <filename>lib/acts_as_audited.rb</filename>
    </modified>
    <modified>
      <diff>@@ -2,19 +2,17 @@ require File.join(File.dirname(__FILE__), 'test_helper')
 
 class ActsAsAuditedTest &lt; Test::Unit::TestCase
   
-  def test_acts_as_authenticated_declaration
-    [:non_audited_columns, :audited_columns, :without_auditing].each do |m|
-      assert User.respond_to?(m), &quot;User class should respond to #{m}.&quot;
-    end
-
-    u = User.new
-    [:audits, :save_without_auditing, :without_auditing, :audited_attributes, :changed?].each do |m|
-      assert u.respond_to?(m), &quot;User object should respond to #{m}.&quot;
-    end
+  def test_acts_as_authenticated_declaration_includes_instance_methods
+    assert_kind_of CollectiveIdea::Acts::Audited::InstanceMethods, User.new
   end
   
+  def test_acts_as_authenticated_declaration_extends_singleton_methods
+    assert_kind_of CollectiveIdea::Acts::Audited::SingletonMethods, User
+  end
+
   def test_audited_attributes
-    assert_equal ['name', 'username', 'logins', 'activated'].sort, User.new.audited_attributes.sort
+    attrs = {'name' =&gt; nil, 'username' =&gt; nil, 'logins' =&gt; 0, 'activated' =&gt; nil}
+    assert_equal attrs, User.new.audited_attributes
   end
   
   def test_non_audited_columns
@@ -56,8 +54,8 @@ class ActsAsAuditedTest &lt; Test::Unit::TestCase
     assert !u.changed?
     u.name = &quot;Bobby&quot;
     assert u.changed?
-    assert u.changed?(:name)
-    assert !u.changed?(:username)
+    assert u.name_changed?
+    assert !u.username_changed?
   end
   
   def test_clears_changed_attributes_after_save
@@ -99,12 +97,12 @@ class ActsAsAuditedTest &lt; Test::Unit::TestCase
   def test_latest_revision_first
     u = User.create(:name =&gt; 'Brandon')
     assert_equal 1, u.revisions.size
-    assert_equal nil, u.revisions[0].name
+    assert_equal 'Brandon', u.revisions[0].name
     
     u.update_attribute :name, 'Foobar'
     assert_equal 2, u.revisions.size
-    assert_equal 'Brandon', u.revisions[0].name
-    assert_equal nil, u.revisions[1].name
+    assert_equal 'Foobar', u.revisions[0].name
+    assert_equal 'Brandon', u.revisions[1].name
   end
   
   def test_revisions_without_changes
@@ -132,7 +130,7 @@ class ActsAsAuditedTest &lt; Test::Unit::TestCase
     revision = u.revision(3)
     assert_kind_of User, revision
     assert_equal 3, revision.version
-    assert_equal 'Foobar 2', revision.name
+    assert_equal 'Foobar 3', revision.name
   end
   
   def test_get_previous_revision
@@ -144,7 +142,7 @@ class ActsAsAuditedTest &lt; Test::Unit::TestCase
   
   def test_revision_marks_attributes_changed
     u = create_versions(2)
-    assert u.revision(1).changed?(:name)
+    assert u.revision(1).name_changed?
   end
 
   def test_save_revision_records_audit</diff>
      <filename>test/acts_as_audited_test.rb</filename>
    </modified>
  </modified>
  <removed type="array">
    <removed>
      <filename>lib/audit.rb</filename>
    </removed>
    <removed>
      <filename>lib/audit_sweeper.rb</filename>
    </removed>
  </removed>
  <parents type="array">
    <parent>
      <id>6f0df7c01fc96dcbcbab16ec4f4a24a8322cb99e</id>
    </parent>
  </parents>
  <author>
    <name>Brandon Keepers</name>
    <email>brandon@collectiveidea.com</email>
  </author>
  <url>http://github.com/airblade/acts_as_audited/commit/45a276c406e46b432d5c0c0a03fa70c88f0a3869</url>
  <id>45a276c406e46b432d5c0c0a03fa70c88f0a3869</id>
  <committed-date>2008-05-17T21:56:58-07:00</committed-date>
  <authored-date>2008-04-19T15:22:58-07:00</authored-date>
  <message>refactoring to make compatible with dirty tracking in edge rails and to stop storing both old and new values in a single audit</message>
  <tree>92543f9ef3779881e0e65f15a79e162c3fc79c27</tree>
  <committer>
    <name>Brandon Keepers</name>
    <email>brandon@collectiveidea.com</email>
  </committer>
</commit>
