diff --git a/CHANGES b/CHANGES index 8106488..c31e135 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,8 @@ +0.9.1 - 24-01-2008 + +Improved implementation of revert_to_version with further tests. +Provided clean aliases for methods in VersionProxy. + 0.9 - 24-01-2008 Added an :exclude option (default: []) diff --git a/README b/README index 8b62a6e..86fe49c 100644 --- a/README +++ b/README @@ -1,7 +1,7 @@ SimplyVersioned =============== -Release: 0.9 +Release: 0.9.1 Date: 24-01-2008 Author: Matt Mower @@ -43,7 +43,7 @@ Usage If you do not specify a limit then old versions are never automatically deleted. You can manually delete them like this: - thing.versions.clean_old_version( 10 ) + thing.versions.purge( 10 ) which would delete all the but the last ten versions. @@ -91,7 +91,16 @@ Usage 7. Revert to a previous version thing.revert_to_version( 5 ) + + If a specific reversion needs to avoid overwriting some column values pass + an :except option, e.g. + thing.revert_to_version( 1, :except => [:name,:age] ) + + The revert_to_version method also takes an existing Version instance, e.g. + + version = thing.versions.find( ... ) + thing.revert_to_version( version ) 8. Traverse versions diff --git a/lib/simply_versioned.rb b/lib/simply_versioned.rb index 7f180b9..0f12946 100644 --- a/lib/simply_versioned.rb +++ b/lib/simply_versioned.rb @@ -1,4 +1,4 @@ -# SimplyVersioned 0.9 +# SimplyVersioned 0.9.1 # # Simple ActiveRecord versioning # Copyright (c) 2007,2008 Matt Mower @@ -16,7 +16,7 @@ def initialize( keys ) super( "Keys: #{keys.join( "," )} are not known by SimplyVersioned" ) end end - + module ClassMethods # Marks this ActiveRecord model as being versioned. Calls to +create+ or +save+ will, @@ -76,27 +76,29 @@ def versioning_enabled? # Methods that will be defined on the ActiveRecord model being versioned module InstanceMethods - # Revert this model instance to the attributes it had at the specified version number. + # Revert the attributes of this model to their values as of an earlier version. + # + # Pass either a Version instance or a version number. # # options: # +except+ specify a list of attributes that are not restored (default: created_at, updated_at) # def revert_to_version( version, options = {} ) - version = if version.kind_of?( Version ) - version - else - version = self.versions.find( :first, :conditions => { :number => Integer( version ) } ) - end - options.reverse_merge!({ :except => [:created_at,:updated_at] }) - reversion_data = YAML::load( version.yaml ) - reversion_data.delete_if { |key,value| options[:except].include? key.to_sym } - reversion_data.each do |key,value| - self.__send__( "#{key}=", value ) + version = if version.kind_of?( Version ) + version + elsif version.kind_of?( Fixnum ) + self.versions.find_by_number( version ) end + + raise "Invalid version (#{version.inspect}) specified!" unless version + + options[:except] = options[:except].map( &:to_s ) + + self.update_attributes( YAML::load( version.yaml ).except( *options[:except] ) ) end # Invoke the supplied block passing the receiver as the sole block argument with @@ -139,16 +141,19 @@ module VersionsProxyMethods def get_version( number ) find_by_number( number ) end + alias_method :get, :get_version # Get the first Version corresponding to this model. def first_version find( :first, :order => 'number ASC' ) end + alias_method :first, :first_version # Get the current Version corresponding to this model. def current_version find( :first, :order => 'number DESC' ) end + alias_method :current, :current_version # If the model instance has more versions than the limit specified, delete all excess older versions. def clean_old_versions( versions_to_keep ) @@ -156,16 +161,19 @@ def clean_old_versions( versions_to_keep ) version.destroy end end + alias_method :purge, :clean_old_versions # Return the Version for this model with the next higher version def next_version( number ) find( :first, :order => 'number ASC', :conditions => [ "number > ?", number ] ) end + alias_method :next, :next_version # Return the Version for this model with the next lower version def previous_version( number ) find( :first, :order => 'number DESC', :conditions => [ "number < ?", number ] ) end + alias_method :previous, :previous_version end def self.included( receiver ) diff --git a/lib/version.rb b/lib/version.rb index bc26a59..ba9aa7a 100644 --- a/lib/version.rb +++ b/lib/version.rb @@ -1,4 +1,4 @@ -# SimplyVersioned 0.9 +# SimplyVersioned 0.9.1 # # Simple ActiveRecord versioning # Copyright (c) 2007,2008 Matt Mower diff --git a/test/simply_versioned_test.rb b/test/simply_versioned_test.rb index 818f17d..34a42a6 100644 --- a/test/simply_versioned_test.rb +++ b/test/simply_versioned_test.rb @@ -96,13 +96,17 @@ def test_should_get_versions anthony.save! assert_equal 35, anthony.versions.get_version(1).model.age + assert_equal 35, anthony.versions.get(1).model.age + assert_equal 36, anthony.versions.get_version(2).model.age + assert_equal 36, anthony.versions.get(2).model.age end def test_should_version_on_create anthony = Aardvark.create!( :name => 'Anthony', :age => 35 ) assert_equal 1, anthony.versions.count assert_equal 1, anthony.versions.current_version.number + assert_equal 1, anthony.versions.current.number end def test_should_version_on_save @@ -125,7 +129,9 @@ def test_should_trim_versions assert_equal 3, anthony.versions.count assert_equal 36, anthony.versions.first_version.model.age + assert_equal 36, anthony.versions.first.model.age assert_equal 38, anthony.versions.current_version.model.age + assert_equal 38, anthony.versions.current.model.age end def test_should_revert @@ -149,6 +155,25 @@ def test_should_revert_except assert_equal 35, anthony.age end + def test_should_raise_on_reversion_to_bad_version + anthony = Aardvark.create!( :name => 'Anthony', :age => 35 ) # v1 + anthony.name = "Tony" + anthony.age = 45 + anthony.save! # v2 + + assert_raise RuntimeError do + anthony.revert_to_version( -1 ) + end + + assert_raise RuntimeError do + anthony.revert_to_version( "a" ) + end + + assert_raise RuntimeError do + anthony.revert_to_version( nil ) + end + end + def test_should_delete_dependent_versions anthony = Aardvark.create!( :name => 'Anthony', :age => 35 ) # v1 anthony.age += 1