From 5310c90de3f39a96fe4d5465d442918dfe030d3f Mon Sep 17 00:00:00 2001 From: technoweenie Date: Mon, 2 Jan 2006 18:36:36 +0000 Subject: [PATCH] added ability to share a mixin with versioned class. changed the dynamic version model to MyModel::Version. closes [12] and [13] git-svn-id: http://svn.techno-weenie.net/projects/plugins/acts_as_versioned@553 567b1171-46fb-0310-a4c9-b4bef9110e78 --- CHANGELOG | 5 ++++ Rakefile | 2 +- lib/acts_as_versioned.rb | 54 ++++++++++++++++++++++++++++++++++------ test/fixtures/page.rb | 23 +++++++++++------ test/versioned_test.rb | 14 ++++++++++- 5 files changed, 82 insertions(+), 16 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 31e7dbc..64e9a6c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,8 @@ +*0.3* + +* (2 Jan 2005) added ability to share a mixin with versioned class +* (2 Jan 2005) changed the dynamic version model to MyModel::Version + *0.2.4* * (27 Nov 2005) added note about possible destructive behavior of if_changed? [Michael Schuerig] diff --git a/Rakefile b/Rakefile index 6888b53..746bc08 100644 --- a/Rakefile +++ b/Rakefile @@ -9,7 +9,7 @@ require 'rake/testtask' require 'rake/contrib/rubyforgepublisher' PKG_NAME = 'acts_as_versioned' -PKG_VERSION = '0.2.3' +PKG_VERSION = '0.3' PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}" PROD_HOST = "technoweenie@bidwell.textdrive.com" RUBY_FORGE_PROJECT = 'ar-versioned' diff --git a/lib/acts_as_versioned.rb b/lib/acts_as_versioned.rb index 7bf86f5..683ed66 100644 --- a/lib/acts_as_versioned.rb +++ b/lib/acts_as_versioned.rb @@ -80,12 +80,40 @@ module ClassMethods # # * if_changed - Simple way of specifying attributes that are required to be changed before saving a model. This takes # either a symbol or array of symbols. WARNING - This will attempt to overwrite any attribute setters you may have. - # Add this instead: + # Use this instead if you want to write your own attribute setters (and ignore if_changed): # # def name=(new_name) # write_changed_attribute :name, new_name # end # + # * extend - Lets you specify a module to be mixed in both the original and versioned models. You can also just pass a block + # to create an anonymous mixin: + # + # class Auction + # acts_as_versioned do + # def started? + # !started_at.nil? + # end + # end + # end + # + # or... + # + # module AuctionExtension + # def started? + # !started_at.nil? + # end + # end + # class Auction + # acts_as_versioned :extend => AuctionExtension + # end + # + # Example code: + # + # @auction = Auction.find(1) + # @auction.started? + # @auction.versions.first.started? + # # == Database Schema # # The model that you're versioning needs to have a 'version' attribute. The model is versioned @@ -110,7 +138,7 @@ module ClassMethods # end # end # - def acts_as_versioned(options = {}) + def acts_as_versioned(options = {}, &extension) # don't allow multiple calls return if self.included_modules.include?(ActiveRecord::Acts::Versioned::ActMethods) @@ -121,7 +149,7 @@ def acts_as_versioned(options = {}) attr_accessor :changed_attributes end - self.versioned_class_name = options[:class_name] || "#{self.to_s.demodulize}Version" + self.versioned_class_name = options[:class_name] || "Version" self.versioned_foreign_key = options[:foreign_key] || self.to_s.foreign_key self.versioned_table_name = options[:table_name] || "#{table_name_prefix}#{Inflector.underscore(Inflector.demodulize(class_name_of_active_record_descendant(self)))}_versions#{table_name_suffix}" self.versioned_inheritance_column = options[:inheritance_column] || "versioned_#{inheritance_column}" @@ -130,9 +158,18 @@ def acts_as_versioned(options = {}) self.max_version_limit = options[:limit].to_i self.version_condition = options[:if] || true + if block_given? + extension_module_name = "#{self.to_s}#{versioned_class_name}Extension" + silence_warnings do + Object.const_set(extension_module_name, Module.new(&extension)) + end + + options[:extend] = extension_module_name.constantize + end + class_eval do has_many :versions, - :class_name => "ActiveRecord::Acts::Versioned::#{versioned_class_name}", + :class_name => "#{self.to_s}::#{versioned_class_name}", :foreign_key => "#{versioned_foreign_key}", :order => 'version' before_save :set_new_version @@ -150,16 +187,19 @@ def acts_as_versioned(options = {}) end end end + + include options[:extend] if options[:extend].is_a?(Module) end # create the dynamic versioned model # maybe if i sit down long enough i can think up a better way to do this. dynamic_model = <<-EOV - class ActiveRecord::Acts::Versioned::#{versioned_class_name} < ActiveRecord::Base + class #{self.to_s}::#{versioned_class_name} < ActiveRecord::Base set_table_name "#{versioned_table_name}" belongs_to :#{self.to_s.demodulize.underscore}, :class_name => "#{self.to_s}" EOV + dynamic_model += %Q{include #{options[:extend].to_s}\n} if options[:extend].is_a?(Module) dynamic_model += %Q{set_sequence_name "#{version_sequence_name}"\n} if version_sequence_name eval dynamic_model + 'end' @@ -355,7 +395,7 @@ def versioned_columns # Returns an instance of the dynamic versioned model def versioned_class - "ActiveRecord::Acts::Versioned::#{versioned_class_name}".constantize + "#{self.to_s}::#{versioned_class_name}".constantize end # An array of fields that are not saved in the versioned table @@ -404,4 +444,4 @@ def drop_versioned_table end end -ActiveRecord::Base.class_eval { include ActiveRecord::Acts::Versioned } \ No newline at end of file +ActiveRecord::Base.send :include, ActiveRecord::Acts::Versioned \ No newline at end of file diff --git a/test/fixtures/page.rb b/test/fixtures/page.rb index a5bc8f2..58f417c 100644 --- a/test/fixtures/page.rb +++ b/test/fixtures/page.rb @@ -1,11 +1,19 @@ class Page < ActiveRecord::Base - cattr_accessor :feeling_good - @@feeling_good = true - - acts_as_versioned :if => :feeling_good? + acts_as_versioned :if => :feeling_good? do + def self.included(base) + base.cattr_accessor :feeling_good + base.feeling_good = true + end - def feeling_good? - @@feeling_good == true + def feeling_good? + @@feeling_good == true + end + end +end + +module LockedPageExtension + def hello_world + 'hello_world' end end @@ -17,7 +25,8 @@ class LockedPage < ActiveRecord::Base :class_name => 'LockedPageRevision', :version_column => :lock_version, :limit => 2, - :if_changed => :title + :if_changed => :title, + :extend => LockedPageExtension end class SpecialLockedPage < LockedPage diff --git a/test/versioned_test.rb b/test/versioned_test.rb index 3bf71f9..0a75d27 100644 --- a/test/versioned_test.rb +++ b/test/versioned_test.rb @@ -24,10 +24,22 @@ def test_rollback_with_version_number end def test_versioned_class_name - assert_equal 'PageVersion', Page.versioned_class_name + assert_equal 'Version', Page.versioned_class_name assert_equal 'LockedPageRevision', LockedPage.versioned_class_name end + def test_versioned_class + assert_equal Page::Version, Page.versioned_class + assert_equal LockedPage::LockedPageRevision, LockedPage.versioned_class + end + + def test_special_methods + assert_nothing_raised { pages(:welcome).feeling_good? } + assert_nothing_raised { pages(:welcome).versions.first.feeling_good? } + assert_nothing_raised { locked_pages(:welcome).hello_world } + assert_nothing_raised { locked_pages(:welcome).versions.first.hello_world } + end + def test_rollback_with_version_class p = pages(:welcome) assert_equal 24, p.version