Skip to content

Commit

Permalink
Fix hooks on PerformableMethod and PerformableMailer [Closes #113]
Browse files Browse the repository at this point in the history
  • Loading branch information
bkeepers committed Sep 9, 2010
1 parent 2cc1573 commit e132b5d
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 37 deletions.
1 change: 1 addition & 0 deletions lib/delayed/backend/base.rb
Expand Up @@ -61,6 +61,7 @@ def name
end

def payload_object=(object)
@payload_object = object
self.handler = object.to_yaml
end

Expand Down
11 changes: 4 additions & 7 deletions lib/delayed/message_sending.rb
Expand Up @@ -10,10 +10,7 @@ def initialize(payload_class, target, options)
end

def method_missing(method, *args)
Job.create({
:payload_object => @payload_class.new(@target, method.to_sym, args),
:priority => ::Delayed::Worker.default_priority
}.merge(@options))
Job.enqueue({:payload_object => @payload_class.new(@target, method.to_sym, args)}.merge(@options))
end
end

Expand All @@ -22,7 +19,7 @@ def delay(options = {})
DelayProxy.new(PerformableMethod, self, options)
end
alias __delay__ delay

def send_later(method, *args)
warn "[DEPRECATION] `object.send_later(:method)` is deprecated. Use `object.delay.method"
__delay__.__send__(method, *args)
Expand All @@ -32,7 +29,7 @@ def send_at(time, method, *args)
warn "[DEPRECATION] `object.send_at(time, :method)` is deprecated. Use `object.delay(:run_at => time).method"
__delay__(:run_at => time).__send__(method, *args)
end

module ClassMethods
def handle_asynchronously(method)
aliased_method, punctuation = method.to_s.sub(/([?!=])$/, ''), $1
Expand All @@ -43,5 +40,5 @@ def handle_asynchronously(method)
alias_method_chain method, :delay
end
end
end
end
end
2 changes: 1 addition & 1 deletion lib/delayed/performable_mailer.rb
Expand Up @@ -3,7 +3,7 @@
module Delayed
class PerformableMailer < PerformableMethod
def perform
object.send(method, *args).deliver
object.send(method_name, *args).deliver
end
end
end
Expand Down
32 changes: 17 additions & 15 deletions lib/delayed/performable_method.rb
@@ -1,27 +1,29 @@
module Delayed
class PerformableMethod < Struct.new(:object, :method, :args)
def initialize(object, method, args)
raise NoMethodError, "undefined method `#{method}' for #{object.inspect}" unless object.respond_to?(method, true)
class PerformableMethod < Struct.new(:object, :method_name, :args)
delegate :method, :to => :object

self.object = object
self.args = args
self.method = method.to_sym
def initialize(object, method_name, args)
raise NoMethodError, "undefined method `#{method_name}' for #{object.inspect}" unless object.respond_to?(method_name, true)

self.object = object
self.args = args
self.method_name = method_name.to_sym
end

def display_name
"#{object.class}##{method}"
"#{object.class}##{method_name}"
end

def perform
object.send(method, *args) if object
object.send(method_name, *args) if object
end

def method_missing(symbol, *args)
object.respond_to?(symbol) ? object.send(symbol, *args) : super
object.send(symbol, *args)
end

def respond_to?(symbol, include_private=false)
object.respond_to?(symbol, include_private) || super
end
super || object.respond_to?(symbol, include_private)
end
end
end
8 changes: 4 additions & 4 deletions spec/message_sending_spec.rb
Expand Up @@ -7,18 +7,18 @@ def tell!(arg)
end
handle_asynchronously :tell!
end

it "should alias original method" do
Story.new.should respond_to(:tell_without_delay!)
Story.new.should respond_to(:tell_with_delay!)
end

it "should create a PerformableMethod" do
story = Story.create!
lambda {
job = story.tell!(1)
job.payload_object.class.should == Delayed::PerformableMethod
job.payload_object.method.should == :tell_without_delay!
job.payload_object.method_name.should == :tell_without_delay!
job.payload_object.args.should == [1]
}.should change { Delayed::Job.count }
end
Expand All @@ -29,7 +29,7 @@ def tell!(arg)
lambda {
job = "hello".delay.count('l')
job.payload_object.class.should == Delayed::PerformableMethod
job.payload_object.method.should == :count
job.payload_object.method_name.should == :count
job.payload_object.args.should == ['l']
}.should change { Delayed::Job.count }.by(1)
end
Expand Down
8 changes: 4 additions & 4 deletions spec/performable_mailer_spec.rb
Expand Up @@ -13,20 +13,20 @@ def signup(email)
lambda {
job = MyMailer.delay.signup('john@example.com')
job.payload_object.class.should == Delayed::PerformableMailer
job.payload_object.method.should == :signup
job.payload_object.method_name.should == :signup
job.payload_object.args.should == ['john@example.com']
}.should change { Delayed::Job.count }.by(1)
end
end

describe "delay on a mail object" do
it "should raise an exception" do
lambda {
MyMailer.signup('john@example.com').delay
}.should raise_error(RuntimeError)
end
end

describe Delayed::PerformableMailer do
describe "perform" do
before do
Expand All @@ -42,5 +42,5 @@ def signup(email)
end
end
end

end
29 changes: 23 additions & 6 deletions spec/performable_method_spec.rb
Expand Up @@ -5,36 +5,36 @@
before do
@method = Delayed::PerformableMethod.new("foo", :count, ['o'])
end

context "with the persisted record cannot be found" do
before do
@method.object = nil
end

it "should be a no-op if object is nil" do
lambda { @method.perform }.should_not raise_error
end
end

it "should call the method on the object" do
@method.object.should_receive(:count).with('o')
@method.perform
end

it "should respond to failure when implemented and target object is called via object.delay.do_something" do
@method = Delayed::PerformableMethod.new(OnPermanentFailureJob.new, :perform, [])
@method.respond_to?(:failure).should be_true
@method.object.should_receive(:failure)
@method.failure
end
end
end

it "should raise a NoMethodError if target method doesn't exist" do
lambda {
Delayed::PerformableMethod.new(Object, :method_that_does_not_exist, [])
}.should raise_error(NoMethodError)
end

it "should not raise NoMethodError if target method is private" do
clazz = Class.new do
def private_method
Expand All @@ -45,4 +45,21 @@ def private_method
Delayed::PerformableMethod.new(clazz.new, :private_method, [])
}.should_not raise_error(NoMethodError)
end

describe "hooks" do
%w(enqueue before after success).each do |hook|
it "should delegate #{hook} hook to object" do
story = Story.new
story.should_receive(hook).with(an_instance_of(Delayed::Job))
story.delay.tell.invoke_job
end
end

it "should delegate error hook to object" do
story = Story.new
story.should_receive(:error).with(an_instance_of(Delayed::Job), an_instance_of(RuntimeError))
story.should_receive(:tell).and_raise(RuntimeError)
lambda { story.delay.tell.invoke_job }.should raise_error
end
end
end

0 comments on commit e132b5d

Please sign in to comment.