Created
May 14, 2014 05:11
-
-
Save dplummer/ef07153749bb8b48fb54 to your computer and use it in GitHub Desktop.
Delay and prevent multiple touches
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module DeferTouching | |
def self.defer_touching(*klasses, &block) | |
to_touch = Set.new | |
old_methods = klasses.inject({}) do |acc, klass| | |
acc[klass] = klass.instance_method(:touch) | |
acc | |
end | |
klasses.each do |klass| | |
klass.send(:define_method, :touch) do | |
to_touch << self | |
end | |
end | |
res = nil | |
begin | |
res = block.call | |
ensure | |
old_methods.each do |klass, meth| | |
klass.send(:define_method, :touch, meth) | |
end | |
end | |
to_touch.each do |record| | |
begin | |
record.touch | |
rescue ActiveRecord::StaleObjectError | |
record.reload | |
retry | |
end | |
end | |
res | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'spec_helper' | |
describe DeferTouching do | |
DeferTestError = Class.new(StandardError) | |
class DeferMe | |
attr_reader :touch_count | |
def initialize | |
@touch_count = 0 | |
end | |
def touch | |
@touch_count += 1 | |
end | |
end | |
class DeferMeToo < DeferMe | |
end | |
class DontDeferMeBro | |
attr_reader :touch_count | |
def initialize | |
@touch_count = 0 | |
end | |
def touch | |
@touch_count += 1 | |
end | |
end | |
let(:defer_me) { DeferMe.new } | |
let(:defer_me_too) { DeferMeToo.new } | |
let(:dont_defer) { DontDeferMeBro.new } | |
subject { DeferTouching } | |
it "only defers the classes specified" do | |
DeferTouching.defer_touching(DeferMe, DeferMeToo) do | |
dont_defer.touch | |
dont_defer.touch | |
end | |
dont_defer.touch_count.should == 2 | |
end | |
it "defers touching inside the block only" do | |
DeferTouching.defer_touching(DeferMe, DeferMeToo) do | |
defer_me.touch | |
defer_me_too.touch | |
defer_me.touch_count.should == 0 | |
defer_me.touch_count.should == 0 | |
end | |
defer_me.touch_count.should == 1 | |
defer_me.touch_count.should == 1 | |
end | |
it "turns multiple touch calls into one" do | |
DeferTouching.defer_touching(DeferMe, DeferMeToo) do | |
defer_me.touch | |
defer_me.touch | |
end | |
defer_me.touch_count.should == 1 | |
end | |
it "stops deferring after the block"do | |
DeferTouching.defer_touching(DeferMe, DeferMeToo) do | |
defer_me.touch | |
end | |
defer_me.touch | |
defer_me.touch | |
defer_me.touch_count.should == 3 | |
end | |
context "an exception is raised within the block" do | |
def exploding_touch | |
DeferTouching.defer_touching(DeferMe) do | |
defer_me.touch | |
raise DeferTestError | |
end | |
end | |
it "raises the error" do | |
expect { exploding_touch }.to raise_error(DeferTestError) | |
end | |
it "does not touch the classes" do | |
begin | |
exploding_touch | |
rescue DeferTestError | |
end | |
defer_me.touch_count.should == 0 | |
end | |
it "redefines the correct touch method on the klass" do | |
begin | |
exploding_touch | |
rescue DeferTestError | |
end | |
defer_me.touch | |
defer_me.touch_count.should == 1 | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment