<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -1,6 +1,9 @@
  acts_as_audited ChangeLog
 -------------------------------------------------------------------------------
 
+0.4 - 2007-06-17
+* Added support getting previous revisions
+
 0.3 - 2006-11-17
 * Replaced use of singleton User.current_user with cache sweeper implementation
   for auditing the user that made the change</diff>
      <filename>CHANGELOG</filename>
    </modified>
    <modified>
      <diff>@@ -42,8 +42,12 @@ Auditing with user support depends on Rails' caching mechanisms, therefore audit
 
 == Upgrading
 
-Those upgrading from version 0.2 need to add 2 fields the audits table:
+To upgrade from an older version, add a migration with:
 
+  # to version 0.3
   add_column :audits, :user_type, :string
   add_column :audits, :username, :string
 
+  # to version 0.4
+  add_column :audits, :version, :integer, :default =&gt; 0
+</diff>
      <filename>README</filename>
    </modified>
    <modified>
      <diff>@@ -8,6 +8,7 @@ class &lt;%= class_name %&gt; &lt; ActiveRecord::Migration
       t.column :username, :string
       t.column :action, :string
       t.column :changes, :text
+      t.column :version, :integer, :default =&gt; 0
       t.column :created_at, :datetime
     end
     </diff>
      <filename>generators/audited_migration/templates/migration.rb</filename>
    </modified>
    <modified>
      <diff>@@ -68,7 +68,7 @@ module CollectiveIdea #:nodoc:
           class_eval do
             extend CollectiveIdea::Acts::Audited::SingletonMethods
 
-            has_many :audits, :as =&gt; :auditable
+            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)
             
@@ -76,6 +76,8 @@ module CollectiveIdea #:nodoc:
             after_update :audit_update
             after_destroy :audit_destroy
             after_save :clear_changed_attributes
+            
+            attr_accessor :version
 
             write_inheritable_attribute :auditing_enabled, true
           end
@@ -109,8 +111,46 @@ module CollectiveIdea #:nodoc:
         def without_auditing(&amp;block)
           self.class.without_auditing(&amp;block)
         end
-
+        
+        # Gets an array of the revisions available
+        #
+        #   user.revisions.each do |revision|
+        #     user.name
+        #     user.version
+        #   end
+        #
+        def revisions(from_version = 1)
+          changes(from_version) {|attributes| revision_with(attributes) }
+        end
+        
+        # Get a specific revision
+        def revision(version)
+          revision_with changes(version)
+        end
+        
         private
+        
+          def changes(from_version = 1)
+            from_version = audits.find(:first).version if from_version == :previous
+            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?
+            end
+            block_given? ? result : changes
+          end
+          
+          def revision_with(attributes)
+            returning self.dup do |revision|
+              revision.send :instance_variable_set, '@attributes', self.attributes_before_type_cast
+              revision.attributes = attributes
+            end
+          end
+          
           # Creates a new record in the audits table if applicable
           def audit_create
             write_audit(:create)</diff>
      <filename>lib/acts_as_audited.rb</filename>
    </modified>
    <modified>
      <diff>@@ -11,6 +11,7 @@
 class Audit &lt; ActiveRecord::Base
   belongs_to :auditable, :polymorphic =&gt; true
   belongs_to :user, :polymorphic =&gt; true
+  acts_as_list :column =&gt; :version, :scope =&gt; 'auditable_id = #{auditable_id} AND auditable_type = \'#{auditable_type}\''
   
   serialize :changes
   </diff>
      <filename>lib/audit.rb</filename>
    </modified>
    <modified>
      <diff>@@ -24,18 +24,18 @@ class ActsAsAuditedTest &lt; Test::Unit::TestCase
   end
 
   def test_doesnt_save_non_audited_columns
-    u = User.create(:name =&gt; 'Brandon')
+    u = create_user
     assert !u.audits.first.changes.include?('created_at'), 'created_at should not be audited'
     assert !u.audits.first.changes.include?('updated_at'), 'updated_at should not be audited'
     assert !u.audits.first.changes.include?('password'), 'password should not be audited'
   end
   
   def test_save_audit
-    u = User.new :name =&gt; 'Brandon', :username =&gt; 'brandon', :password =&gt; 'password'
-    assert_difference(Audit, :count) { u.save }
-    assert_difference(Audit, :count) { u.update_attribute(:name, &quot;Someone&quot;) }
-    assert_no_difference(Audit, :count) { u.save }
-    assert_difference(Audit, :count) { u.destroy }
+    u = nil
+    assert_difference(Audit, :count)    { u = create_user }
+    assert_difference(Audit, :count)    { assert u.update_attribute(:name, &quot;Someone&quot;) }
+    assert_no_difference(Audit, :count) { assert u.save }
+    assert_difference(Audit, :count)    { assert u.destroy }
   end
   
   def test_save_without_auditing
@@ -45,14 +45,14 @@ class ActsAsAuditedTest &lt; Test::Unit::TestCase
     end
   end
   
-  def test_without_auditing
+  def test_without_auditing_block
     assert_no_difference Audit, :count do
       User.without_auditing { User.create(:name =&gt; 'Brandon') }
     end
   end
   
   def test_changed?
-    u = User.create(:name =&gt; 'Brandon')
+    u = create_user
     assert !u.changed?
     u.name = &quot;Bobby&quot;
     assert u.changed?
@@ -60,7 +60,7 @@ class ActsAsAuditedTest &lt; Test::Unit::TestCase
     assert !u.changed?(:username)
   end
   
-  def test_calls_clear_changed_attributes_after_save
+  def test_clears_changed_attributes_after_save
     u = User.new(:name =&gt; 'Brandon')
     assert u.changed?
     u.save
@@ -68,8 +68,7 @@ class ActsAsAuditedTest &lt; Test::Unit::TestCase
   end
   
   def test_type_casting
-    u = User.create(:name =&gt; 'Brandon', :logins =&gt; 0, :activated =&gt; true)
-    
+    u = create_user(:logins =&gt; 0, :activated =&gt; true)
     assert_no_difference(Audit, :count) { u.update_attribute :logins, '0' }
     assert_no_difference(Audit, :count) { u.update_attribute :logins, 0 }
     assert_no_difference(Audit, :count) { u.update_attribute :activated, true }
@@ -77,19 +76,78 @@ class ActsAsAuditedTest &lt; Test::Unit::TestCase
   end
   
   def test_that_changes_is_a_hash
-    u = User.create(:name =&gt; 'Brandon')
+    u = create_user
     audit = Audit.find(u.audits.first.id)
     assert audit.changes.is_a?(Hash)
-    assert_equal 1, audit.changes.size
   end
   
-  def test_save_without_audited_modifications
-    u = User.create(:name =&gt; 'Brandon')
-    u = User.find(u.id) # reload
+  def test_save_without_modifications
+    u = create_user
+    u.reload
     assert_nothing_raised do
       assert !u.changed?
       u.save!
     end
   end
+  
+  def test_revisions_should_return_array
+    u = create_versions
+    assert_kind_of Array, u.revisions
+    u.revisions.each {|version| assert_kind_of User, version }
+  end
+  
+  def test_latest_revision_first
+    u = User.create(:name =&gt; 'Brandon')
+    assert_equal 1, u.revisions.size
+    assert_equal nil, 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
+  end
+  
+  def test_get_specific_revision
+    u = create_versions(5)
+    revision = u.revision(3)
+    assert_kind_of User, revision
+    assert_equal 3, revision.version
+    assert_equal 'Foobar 2', revision.name
+  end
+  
+  def test_get_previous_revision
+    u = create_versions(5)
+    revision = u.revision(:previous)
+    assert_equal 5, revision.version
+    assert_equal u.revision(5), revision
+  end
+  
+  def test_revision_marks_attributes_changed
+    u = create_versions(2)
+    assert u.revision(1).changed?(:name)
+  end
+
+  def test_save_revision_records_audit
+    u = create_versions(2)
+    assert_difference Audit, :count do
+      assert u.revision(1).save
+    end
+  end
+  
+private
+
+  def create_user(attrs = {})
+    User.create({:name =&gt; 'Brandon', :username =&gt; 'brandon', :password =&gt; 'password'}.merge(attrs))
+  end
+  
+  def create_versions(n = 2)
+    returning User.create(:name =&gt; 'Foobar 1') do |u|
+      (n - 1).times do |i|
+        u.update_attribute :name, &quot;Foobar #{i + 2}&quot;
+      end
+      u.reload
+    end
+    
+  end
 
 end</diff>
      <filename>test/acts_as_audited_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -17,6 +17,7 @@ ActiveRecord::Schema.define(:version =&gt; 0) do
     t.column :username, :string
     t.column :action, :string
     t.column :changes, :text
+    t.column :version, :integer, :default =&gt; 0
     t.column :created_at, :datetime
   end
   </diff>
      <filename>test/schema.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,10 @@
 $:.unshift(File.dirname(__FILE__) + '/../lib')
 
 require 'test/unit'
-require File.expand_path(File.join(File.dirname(__FILE__), '../../../../config/environment.rb'))
+require 'rubygems'
+require 'active_record'
+require File.dirname(__FILE__) + '/../init.rb'
+
 require 'active_record/fixtures'
 
 config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))</diff>
      <filename>test/test_helper.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>2cda452c9ea5e571509536f8e0cd8d92bbb4cd68</id>
    </parent>
  </parents>
  <author>
    <name>Brandon Keepers</name>
    <email>brandon@collectiveidea.com</email>
  </author>
  <url>http://github.com/airblade/acts_as_audited/commit/a60720a3845c8f7160ec12ec6cafc49e3af478a1</url>
  <id>a60720a3845c8f7160ec12ec6cafc49e3af478a1</id>
  <committed-date>2007-06-17T11:02:18-07:00</committed-date>
  <authored-date>2007-06-17T11:02:18-07:00</authored-date>
  <message>added revisioning support</message>
  <tree>97281bc9422f5485505820721842565101516669</tree>
  <committer>
    <name>Brandon Keepers</name>
    <email>brandon@collectiveidea.com</email>
  </committer>
</commit>
