Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Adding a class level method 'skip_version' that will allow skipping v…

…ersions across multiple models
  • Loading branch information...
commit 4fa33c602872b69dcd985768e25c4ccce68c6508 1 parent 6adf025
@adamcooper adamcooper authored
Showing with 95 additions and 38 deletions.
  1. +69 −37 lib/vestal_versions/control.rb
  2. +26 −1 spec/vestal_versions/control_spec.rb
View
106 lib/vestal_versions/control.rb
@@ -4,6 +4,11 @@ module VestalVersions
module Control
extend ActiveSupport::Concern
+ included do
+ class_attribute :_skip_version, :instance_writer => false
+ end
+
+
# Control blocks are called on ActiveRecord::Base instances as to not cause any conflict with
# other instances of the versioned class whose behavior could be inadvertently altered within
# a control block.
@@ -24,7 +29,7 @@ module InstanceMethods
# end
# user.version # => 1
def skip_version
- with_version_flag(:skip_version) do
+ _with_version_flag(:_skip_version) do
yield if block_given?
save
end
@@ -34,18 +39,12 @@ def skip_version
# +skip_version!+ block is that the save automatically performed at the close of the block
# is a +save!+, meaning that an exception will be raised if the object cannot be saved.
def skip_version!
- with_version_flag(:skip_version) do
+ _with_version_flag(:_skip_version) do
yield if block_given?
save!
end
end
- # A convenience method for determining whether a versioned instance is set to skip its next
- # version creation.
- def skip_version?
- !!@skip_version
- end
-
# Merging versions with the +merge_version+ block will take all of the versions that would
# be created within the block and merge them into one version and pushing that single version
# onto the ActiveRecord::Base instance's version history. A new version will be created and
@@ -66,7 +65,7 @@ def skip_version?
#
# See VestalVersions::Changes for an explanation on how changes are appended.
def merge_version
- with_version_flag(:merge_version) do
+ _with_version_flag(:merge_version) do
yield if block_given?
end
save
@@ -76,7 +75,7 @@ def merge_version
# +merge_version!+ block is that the save automatically performed at the close of the block
# is a +save!+, meaning that an exception will be raised if the object cannot be saved.
def merge_version!
- with_version_flag(:merge_version) do
+ _with_version_flag(:merge_version) do
yield if block_given?
end
save!
@@ -109,11 +108,11 @@ def merge_version?
#
# See VestalVersions::Changes for an explanation on how changes are appended.
def append_version
- with_version_flag(:merge_version) do
+ _with_version_flag(:merge_version) do
yield if block_given?
end
- with_version_flag(:append_version) do
+ _with_version_flag(:append_version) do
save
end
end
@@ -122,11 +121,11 @@ def append_version
# +append_version!+ block is that the save automatically performed at the close of the block
# is a +save!+, meaning that an exception will be raised if the object cannot be saved.
def append_version!
- with_version_flag(:merge_version) do
+ _with_version_flag(:merge_version) do
yield if block_given?
end
- with_version_flag(:append_version) do
+ _with_version_flag(:append_version) do
save!
end
end
@@ -137,32 +136,65 @@ def append_version?
!!@append_version
end
- private
- # Used for each control block, the +with_version_flag+ method sets a given variable to
- # true and then executes the given block, ensuring that the variable is returned to a nil
- # value before returning. This is useful to be certain that one of the control flag
- # instance variables isn't inadvertently left in the "on" position by execution within the
- # block raising an exception.
- def with_version_flag(flag)
- begin
- instance_variable_set("@#{flag}", true)
- yield
- ensure
- instance_variable_set("@#{flag}", nil)
- end
- end
+ # Used for each control block, the +_with_version_flag+ method sets a given variable to
+ # true and then executes the given block, ensuring that the variable is returned to a nil
+ # value before returning. This is useful to be certain that one of the control flag
+ # instance variables isn't inadvertently left in the "on" position by execution within the
+ # block raising an exception.
+ def _with_version_flag(flag)
+ instance_variable_set("@#{flag}", true)
+ yield
+ ensure
+ remove_instance_variable("@#{flag}")
+ end
- # Overrides the basal +create_version?+ method to make sure that new versions are not
- # created when inside any of the control blocks (until the block terminates).
- def create_version?
- !skip_version? && !merge_version? && !append_version? && super
- end
+ # Overrides the basal +create_version?+ method to make sure that new versions are not
+ # created when inside any of the control blocks (until the block terminates).
+ def create_version?
+ !_skip_version? && !merge_version? && !append_version? && super
+ end
- # Overrides the basal +update_version?+ method to allow the last version of an versioned
- # ActiveRecord::Base instance to be updated at the end of an +append_version+ block.
- def update_version?
- append_version?
+ # Overrides the basal +update_version?+ method to allow the last version of an versioned
+ # ActiveRecord::Base instance to be updated at the end of an +append_version+ block.
+ def update_version?
+ append_version?
+ end
+
+ end
+ module ClassMethods
+ # The +skip_version+ block simply allows for updates to be made to an instance of a versioned
+ # ActiveRecord model while ignoring all new version creation. The <tt>:if</tt> and
+ # <tt>:unless</tt> conditions (if given) will not be evaulated inside a +skip_version+ block.
+ #
+ # When the block closes, the instance is automatically saved, so explicitly saving the
+ # object within the block is unnecessary.
+ #
+ # == Example
+ #
+ # user = User.find_by_first_name("Steve")
+ # user.version # => 1
+ # user.skip_version do
+ # user.first_name = "Stephen"
+ # end
+ # user.version # => 1
+ def skip_version
+ _with_version_flag(:_skip_version) do
+ yield if block_given?
end
+ end
+
+ # Used for each control block, the +with_version_flag+ method sets a given variable to
+ # true and then executes the given block, ensuring that the variable is returned to a nil
+ # value before returning. This is useful to be certain that one of the control flag
+ # instance variables isn't inadvertently left in the "on" position by execution within the
+ # block raising an exception.
+ def _with_version_flag(flag)
+ self.send("#{flag}=", true)
+ yield
+ ensure
+ self.send("#{flag}=", nil)
+ end
+
end
end
end
View
27 spec/vestal_versions/control_spec.rb
@@ -2,7 +2,7 @@
describe VestalVersions::Control do
let(:user){ User.create(:name => 'Steve Richert') }
-
+ let(:other_user){ User.create(:name => 'Michael Rossin') }
before do
@count = user.versions.count
end
@@ -23,6 +23,7 @@
user.versions.count.should == @count
end
+
end
shared_examples_for 'a version incrementer' do |method|
@@ -41,11 +42,35 @@
user.versions.count.should == @count + 1
end
+
end
it_should_behave_like 'a version preserver', :skip_version
it_should_behave_like 'a version incrementer', :merge_version
+ context "when operating on the class level" do
+ before do
+ @count = user.versions.count
+ @other_user_count = other_user.versions.count
+ end
+ it 'skip_version doesn\' create versions on multiple models' do
+ other_user_count = other_user.versions.count
+
+ User.skip_version do
+ user.update_attribute(:first_name, 'Stephen')
+ user.update_attribute(:last_name, 'Jobs')
+ user.update_attribute(:first_name, 'Steve')
+
+ other_user.update_attribute(:first_name, 'Stephen')
+ other_user.update_attribute(:last_name, 'Jobs')
+ other_user.update_attribute(:first_name, 'Steve')
+ end
+ user.versions.count.should == @count
+ other_user.versions.count.should == @other_user_count
+ end
+
+ end
+
context 'within a append_version block' do
context 'when no versions exist' do
Please sign in to comment.
Something went wrong with that request. Please try again.