perform_later 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -141,4 +141,12 @@ Be as descriptive as you can in the pull request description, just to be clear w
141
141
 
142
142
  ## Author
143
143
 
144
- Avi Tzurel ([@kensodev](http://twitter.com/kensodev)) http://www.kensodev.com
144
+ Avi Tzurel ([@kensodev](http://twitter.com/kensodev)) http://www.kensodev.com
145
+
146
+ ## Contributors
147
+
148
+ * Felipe Lima ([@felipecsl](http://twitter.com/felipecsl))
149
+ http://blog.felipel.com/
150
+
151
+ Felipe did awesome work on making sure `perform_later` can work with any args and any number of args passed into the methods.
152
+ Felipe now has commit rights to the repo.
@@ -1,13 +1,13 @@
1
1
  module ObjectPerformLater
2
2
  def perform_later(queue, method, *args)
3
- return self.send(method, *args) unless PerformLater.config.enabled?
3
+ return perform_now(method, args) unless PerformLater.config.enabled?
4
4
 
5
5
  worker = PerformLater::Workers::Objects::Worker
6
6
  perform_later_enqueue(worker, queue, method, args)
7
7
  end
8
8
 
9
9
  def perform_later!(queue, method, *args)
10
- return self.send(method, *args) unless PerformLater.config.enabled?
10
+ return perform_now(method, args) unless PerformLater.config.enabled?
11
11
 
12
12
  return "EXISTS!" if loner_exists(method, args)
13
13
 
@@ -16,16 +16,21 @@ module ObjectPerformLater
16
16
  end
17
17
 
18
18
  private
19
- def loner_exists(method, args)
19
+ def loner_exists(method, *args)
20
20
  digest = PerformLater::PayloadHelper.get_digest(self.name, method, args)
21
+
21
22
  return true unless Resque.redis.get(digest).blank?
22
23
  Resque.redis.set(digest, 'EXISTS')
23
24
  return false
24
25
  end
25
26
 
26
- def perform_later_enqueue(worker, queue, method, *args)
27
+ def perform_later_enqueue(worker, queue, method, args)
27
28
  args = PerformLater::ArgsParser.args_to_resque(args)
28
- Resque::Job.create(queue, worker, self.name, method, *args)
29
+ args.size == 1 ? Resque::Job.create(queue, worker, self.name, method, args.first) : Resque::Job.create(queue, worker, self.name, method, *args)
30
+ end
31
+
32
+ def perform_now(method, args)
33
+ args.size == 1 ? send(method, args.first) : send(method, *args)
29
34
  end
30
35
  end
31
36
 
@@ -1,30 +1,22 @@
1
+ require 'json'
2
+
1
3
  module PerformLater
2
4
  class ArgsParser
3
- APP_ROOT = File.expand_path((defined?(Rails) && Rails.root.to_s.length > 0) ? Rails.root : ".") unless defined?(APP_ROOT)
4
-
5
5
  # inspired by DelayedJob
6
6
  CLASS_STRING_FORMAT = /^CLASS\:([A-Z][\w\:]+)$/
7
7
  AR_STRING_FORMAT = /^AR\:([A-Z][\w\:]+)\:(\d+)$/
8
8
  YAML_STRING_FORMAT = /\A---/
9
9
 
10
- def self.args_to_resque(*args)
11
- args = args.flatten.map { |o|
12
- case o
13
- when ActiveRecord::Base
14
- "AR:#{o.class.name}:#{o.id}"
15
- when Class, Module
16
- "CLASS:#{o.name}"
17
- when Hash
18
- o.to_yaml
19
- else
20
- o
21
- end
22
- } if args
10
+ def self.args_to_resque(args)
11
+ return nil unless args
12
+ return arg_to_resque(args) unless args.is_a?(Array)
13
+ return args.map { |o| arg_to_resque o }
23
14
  end
24
15
 
25
- def self.args_from_resque(*args)
26
- args = args.flatten.map { |o|
16
+ def self.args_from_resque(args)
17
+ args = args.map { |o|
27
18
  if o
19
+ o = args_from_resque(o) if o.is_a?(Array)
28
20
  case o
29
21
  when CLASS_STRING_FORMAT then $1.constantize
30
22
  when AR_STRING_FORMAT then $1.constantize.find_by_id($2)
@@ -32,18 +24,22 @@ module PerformLater
32
24
  else o
33
25
  end
34
26
  end
35
- } if args
27
+ } if args
36
28
  end
37
29
 
38
- private
39
- def self.env_str
40
- if defined? Rails
41
- Rails.env.to_s
42
- elsif defined? Rack
43
- Rack.env.to_s
44
- else
45
- 'production'
46
- end
30
+ private
31
+
32
+ def self.arg_to_resque(arg)
33
+ case arg
34
+ when ActiveRecord::Base
35
+ "AR:#{arg.class.name}:#{arg.id}"
36
+ when Class, Module
37
+ "CLASS:#{arg.name}"
38
+ when Hash
39
+ arg.to_yaml
40
+ else
41
+ arg
47
42
  end
43
+ end
48
44
  end
49
45
  end
@@ -1,3 +1,3 @@
1
1
  module PerformLater
2
- VERSION = "1.1.1"
2
+ VERSION = "1.2.0"
3
3
  end
@@ -2,7 +2,7 @@ module PerformLater
2
2
  module Workers
3
3
  module ActiveRecord
4
4
  class LoneWorker
5
- def self.perform(klass, id, method, args)
5
+ def self.perform(klass, id, method, *args)
6
6
  # Remove the loner flag from redis
7
7
  digest = PerformLater::PayloadHelper.get_digest(klass, method, args)
8
8
  Resque.redis.del(digest)
@@ -11,7 +11,12 @@ module PerformLater
11
11
  runner_klass = eval(klass)
12
12
 
13
13
  record = runner_klass.where(:id => id).first
14
- record.send(method, *args) if record
14
+
15
+ if args.length > 0
16
+ record.send(method, *args) if record
17
+ else
18
+ record.send(method) if record
19
+ end
15
20
  end
16
21
  end
17
22
  end
@@ -7,7 +7,12 @@ module PerformLater
7
7
  runner_klass = eval(klass)
8
8
 
9
9
  record = runner_klass.where(:id => id).first
10
- record.send(method, *args) if record
10
+
11
+ if args.length > 0
12
+ record.send(method, *args) if record
13
+ else
14
+ record.send(method) if record
15
+ end
11
16
  end
12
17
  end
13
18
  end
@@ -8,7 +8,12 @@ module PerformLater
8
8
  Resque.redis.del(digest)
9
9
 
10
10
  args = PerformLater::ArgsParser.args_from_resque(args)
11
- klass_name.constantize.send(method, *args)
11
+
12
+ if args.length > 0
13
+ klass_name.constantize.send(method, *args)
14
+ else
15
+ klass_name.constantize.send(method)
16
+ end
12
17
  end
13
18
  end
14
19
  end
@@ -3,8 +3,17 @@ module PerformLater
3
3
  module Objects
4
4
  class Worker
5
5
  def self.perform(klass_name, method, *args)
6
- args = PerformLater::ArgsParser.args_from_resque(args)
7
- klass_name.constantize.send(method, *args)
6
+ arguments = PerformLater::ArgsParser.args_from_resque(args)
7
+
8
+ if arguments.any?
9
+ if arguments.size == 1
10
+ klass_name.constantize.send(method, arguments.first)
11
+ else
12
+ klass_name.constantize.send(method, *arguments)
13
+ end
14
+ else
15
+ klass_name.constantize.send(method)
16
+ end
8
17
  end
9
18
  end
10
19
  end
@@ -19,7 +19,7 @@ module Resque::Plugins::Later::Method
19
19
  Resque.redis.set(digest, 'EXISTS')
20
20
  end
21
21
 
22
- Resque::Job.create(queue, klass, send(:class).name, send(:id), "now_#{method_name}", args)
22
+ Resque::Job.create(queue, klass, send(:class).name, send(:id), "now_#{method_name}", *args)
23
23
  end
24
24
  end
25
25
  end
@@ -41,7 +41,7 @@ module Resque::Plugins::Later::Method
41
41
  end
42
42
 
43
43
  private
44
- def loner_exists(method, *args)
44
+ def loner_exists(method, args)
45
45
  args = PerformLater::ArgsParser.args_to_resque(args)
46
46
  digest = PerformLater::PayloadHelper.get_digest(self.class.name, method, args)
47
47
 
@@ -51,8 +51,8 @@ module Resque::Plugins::Later::Method
51
51
  return false
52
52
  end
53
53
 
54
- def enqueue_in_resque_or_send(worker, queue, method, *args)
54
+ def enqueue_in_resque_or_send(worker, queue, method, args)
55
55
  args = PerformLater::ArgsParser.args_to_resque(args)
56
- Resque::Job.create(queue, worker, self.class.name, self.id, method, *args)
56
+ Resque::Job.create(queue, worker, self.class.name, self.id, method, *args)
57
57
  end
58
58
  end
@@ -2,16 +2,16 @@ module Resque
2
2
  module Mailer
3
3
  module ClassMethods
4
4
  def perform(action, *args)
5
- args = ResquePerformLater.args_from_resque(args)
5
+ args = PerformLater::ArgsParser.args_from_resque(args)
6
6
  self.send(:new, action, *args).message.deliver
7
7
  end
8
8
  end
9
9
 
10
10
  class MessageDecoy
11
11
  def deliver
12
- args = ResquePerformLater.args_to_resque(@args)
12
+ args = PerformLater::ArgsParser.args_to_resque(@args)
13
13
  resque.enqueue(@mailer_class, @method_name, *args)
14
14
  end
15
15
  end
16
16
  end
17
- end
17
+ end
@@ -13,9 +13,17 @@ class DummyClass
13
13
  user
14
14
  end
15
15
 
16
+ def self.do_something_with_multiple_args(a, b)
17
+ "#{a}, #{b}"
18
+ end
19
+
16
20
  def self.do_something_with_optional_hash(options = {})
17
21
  options.blank?
18
22
  end
23
+
24
+ def self.do_something_with_array(arr)
25
+ arr
26
+ end
19
27
  end
20
28
 
21
29
  describe ObjectPerformLater do
@@ -48,10 +56,38 @@ describe ObjectPerformLater do
48
56
  Resque.peek(:generic, 0, 20).length.should == 1
49
57
  end
50
58
 
59
+ describe "When Enabled" do
60
+ it "should pass no values" do
61
+ PerformLater.config.stub!(:enabled?).and_return(true)
62
+ Resque::Job.should_receive(:create).with(:generic, PerformLater::Workers::Objects::Worker, "DummyClass", :do_something_with_array)
63
+ DummyClass.perform_later(:generic, :do_something_with_array)
64
+ end
65
+
66
+ it "should pass the correct value (array)" do
67
+ PerformLater.config.stub!(:enabled?).and_return(true)
68
+ Resque::Job.should_receive(:create).with(:generic, PerformLater::Workers::Objects::Worker, "DummyClass", :do_something_with_array, [1,2,3,4,5])
69
+ DummyClass.perform_later(:generic, :do_something_with_array, [1,2,3,4,5])
70
+ end
71
+
72
+ it "should pass multiple args" do
73
+ PerformLater.config.stub!(:enabled?).and_return(true)
74
+ Resque::Job.should_receive(:create).with(:generic, PerformLater::Workers::Objects::Worker, "DummyClass", :do_something_with_multiple_args, 1, 2)
75
+ DummyClass.perform_later(:generic, :do_something_with_multiple_args, 1, 2)
76
+ end
77
+
78
+ it "should pass AR and hash" do
79
+ u = User.create
80
+ PerformLater.config.stub!(:enabled?).and_return(true)
81
+ Resque::Job.should_receive(:create).with(:generic, PerformLater::Workers::Objects::Worker, "DummyClass", :do_something_with_multiple_args, "AR:User:2", "---\n:a: 2\n")
82
+ DummyClass.perform_later(:generic, :do_something_with_multiple_args, u, {a: 2})
83
+ end
84
+ end
85
+
51
86
  describe :perform_later do
52
87
  before(:each) do
53
88
  PerformLater.config.stub!(:enabled?).and_return(false)
54
89
  end
90
+
55
91
  it "should pass the correct value (String)" do
56
92
  DummyClass.perform_later(:generic, :do_something_with_string, "Avi Tzurel").should == "Avi Tzurel"
57
93
  end
@@ -64,6 +100,15 @@ describe ObjectPerformLater do
64
100
  it "should pass the correct value (optional hash)" do
65
101
  DummyClass.perform_later(:generic, :do_something_with_optional_hash).should == true
66
102
  end
103
+
104
+ it "should pass multiple args" do
105
+ DummyClass.perform_later(:generic, :do_something_with_multiple_args, 1, 2).should == "1, 2"
106
+ end
107
+
108
+ it "should pass AR and hash" do
109
+ u = User.create
110
+ DummyClass.perform_later(:generic, :do_something_with_multiple_args, u, {a: 2}).should == "#{u}, {:a=>2}"
111
+ end
67
112
  end
68
113
 
69
114
  describe :perform_later! do
@@ -82,5 +127,14 @@ describe ObjectPerformLater do
82
127
  it "should pass the correct value (optional hash)" do
83
128
  DummyClass.perform_later!(:generic, :do_something_with_optional_hash).should == true
84
129
  end
130
+
131
+ it "should pass multiple args" do
132
+ DummyClass.perform_later!(:generic, :do_something_with_multiple_args, 1, 2).should == "1, 2"
133
+ end
134
+
135
+ it "should pass AR and hash" do
136
+ u = User.create
137
+ DummyClass.perform_later!(:generic, :do_something_with_multiple_args, u, {a: 2}).should == "#{u}, {:a=>2}"
138
+ end
85
139
  end
86
140
  end
@@ -5,11 +5,37 @@ describe PerformLater::ArgsParser do
5
5
  let(:user) { User.create }
6
6
 
7
7
  context "args to resque" do
8
+
9
+ it "should convert array of hashes correctly" do
10
+ arr = [
11
+ { something: "aaa" },
12
+ { something: "bbb" },
13
+ { something: "ccc" },
14
+ { something: "ddd" },
15
+ { something: "eee" }
16
+ ]
17
+ subject.args_to_resque(arr).class.should == Array
18
+ end
19
+
20
+ it "should translate array of hashes back and forth again" do
21
+ arr = [
22
+ { something: "aaa" },
23
+ { something: "bbb" },
24
+ { something: "ccc" },
25
+ { something: "ddd" },
26
+ { something: "eee" }
27
+ ]
28
+ to_resque = subject.args_to_resque(arr).to_json
29
+ a = JSON.parse(to_resque)
30
+ from_resque = subject.args_from_resque(a)
31
+
32
+ from_resque.should == arr
33
+ end
34
+
8
35
  it "should convert the AR object to the proper string" do
9
36
  user_id = user.id
10
37
 
11
- subject.args_to_resque(user).length.should == 1
12
- subject.args_to_resque(user)[0].should == "AR:User:#{user_id}"
38
+ subject.args_to_resque(user).should == "AR:User:#{user_id}"
13
39
  end
14
40
 
15
41
  it "should convert a hash into YAML string so that Resque will be able to JSON convert it" do
@@ -19,24 +45,24 @@ describe PerformLater::ArgsParser do
19
45
 
20
46
  it "should be able to load a yaml from the string and translate it into the same hash again" do
21
47
  hash = { name: "something", other: "something else" }
22
- yaml = subject.args_to_resque(hash)[0]
48
+ yaml = subject.args_to_resque(hash)
23
49
 
24
50
  loaded_yaml = YAML.load(yaml)
25
-
51
+
26
52
  loaded_yaml[:name].should == "something"
27
53
  loaded_yaml[:other].should == "something else"
28
54
  end
29
55
 
30
56
  it "should convert a class to the proper string representation" do
31
57
  klass = User
32
- subject.args_to_resque(klass)[0].should == "CLASS:User"
58
+ subject.args_to_resque(klass).should == "CLASS:User"
33
59
  end
34
60
  end
35
61
 
36
62
  context "args from resque" do
37
63
  it "should give me a hash back when I pass a yaml representation of it" do
38
64
  hash = { name: "something", other: "something else" }
39
- yaml = hash.to_yaml
65
+ yaml = *hash.to_yaml
40
66
 
41
67
  args = subject.args_from_resque(yaml)
42
68
  args[0].class.name.should == "Hash"
@@ -45,7 +71,8 @@ describe PerformLater::ArgsParser do
45
71
  end
46
72
 
47
73
  it "Should give me a user model back when I pass the proper string" do
48
- args = subject.args_from_resque("AR:User:#{user.id}")
74
+ args_input = *"AR:User:#{user.id}"
75
+ args = subject.args_from_resque(args_input)
49
76
  args[0].should == user
50
77
  end
51
78
  end
@@ -14,7 +14,6 @@ describe PerformLater::PayloadHelper do
14
14
  }.to_s)
15
15
 
16
16
  args = PerformLater::ArgsParser.args_to_resque(user)
17
- puts args
18
17
  subject.get_digest("DummyClass", :some_method, args).should == digest
19
18
  end
20
19
  end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe PerformLater::Workers::ActiveRecord::Worker do
4
+
5
+ end
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+
3
+ class DummyClass
4
+ def self.do_somthing_with_array_of_hashes(arr)
5
+ arr[0][:foo]
6
+ end
7
+
8
+ def self.do_something_without_args
9
+ true
10
+ end
11
+
12
+ def self.identity_function(data)
13
+ data
14
+ end
15
+
16
+ def self.join(arg1, arg2)
17
+ "#{arg1}|#{arg2}"
18
+ end
19
+ end
20
+
21
+ describe PerformLater::Workers::Objects::Worker do
22
+ subject { PerformLater::Workers::Objects::Worker }
23
+
24
+ it "should pass an array of hashes into the method" do
25
+ arr = [
26
+ { foo: "bar" },
27
+ { bar: "foo" }
28
+ ]
29
+ arr = PerformLater::ArgsParser.args_to_resque(arr)
30
+ subject.perform("DummyClass", :do_somthing_with_array_of_hashes, arr).should == "bar"
31
+ end
32
+
33
+ it "should pass no args to the method" do
34
+ subject.perform("DummyClass", :do_something_without_args).should == true
35
+ end
36
+
37
+ it "should pass a single argument (user)" do
38
+ user = User.create
39
+ args = PerformLater::ArgsParser.args_to_resque(user)
40
+ subject.perform("DummyClass", :identity_function, args).should == user
41
+ end
42
+
43
+ it "should pass an array with one entry" do
44
+ users = [User.create]
45
+ args = PerformLater::ArgsParser.args_to_resque(users)
46
+ subject.perform("DummyClass", :identity_function, args).should == users
47
+ end
48
+
49
+ it "should pass multi dimension arrays" do
50
+ data = [1, 2, User.create, ["a", "b", "c"]]
51
+ args = PerformLater::ArgsParser.args_to_resque(data)
52
+ subject.perform("DummyClass", :identity_function, args).should == data
53
+ end
54
+
55
+ it 'should pass AR and hash' do
56
+ user = User.create
57
+ arr = {
58
+ something_a: "aaa",
59
+ something_b: "bbb"
60
+ }
61
+ arg1 = PerformLater::ArgsParser.args_to_resque(user)
62
+ arg2 = PerformLater::ArgsParser.args_to_resque(arr)
63
+ subject.perform("DummyClass", :join, arg1, arg2).split("|")[1].should == "{:something_a=>\"aaa\", :something_b=>\"bbb\"}"
64
+ end
65
+ end
@@ -52,6 +52,20 @@ describe Resque::Plugins::Later::Method do
52
52
  end
53
53
  end
54
54
 
55
+ context 'arguments to Resque' do
56
+ it 'should send no args to resque' do
57
+ user = User.create
58
+ Resque::Job.should_receive(:create).with(:generic, PerformLater::Workers::ActiveRecord::Worker, 'User', user.id, :lonely_long_running_method)
59
+ user.perform_later(:generic, :lonely_long_running_method)
60
+ end
61
+
62
+ it 'should send 1 arg to resque' do
63
+ user = User.create
64
+ Resque::Job.should_receive(:create).with(:generic, PerformLater::Workers::ActiveRecord::LoneWorker, 'User', user.id, :lonely_long_running_method, 1)
65
+ user.perform_later!(:generic, :lonely_long_running_method, 1)
66
+ end
67
+ end
68
+
55
69
  it "shold define the correct method on the user model" do
56
70
  user = User.create
57
71
  user.should respond_to(:long_running_method)
@@ -73,8 +87,4 @@ describe Resque::Plugins::Later::Method do
73
87
  user.perform_later!(:generic, :method_with_integer_option, 1)
74
88
  end
75
89
  end
76
-
77
-
78
-
79
-
80
90
  end
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: perform_later
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-05-23 00:00:00.000000000 Z
12
+ date: 2012-05-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -205,6 +205,8 @@ files:
205
205
  - spec/lib/perform_later/args_parser_spec.rb
206
206
  - spec/lib/perform_later/config_spec.rb
207
207
  - spec/lib/perform_later/payload_helper_spec.rb
208
+ - spec/lib/perform_later/workers/active_record/worker_spec.rb
209
+ - spec/lib/perform_later/workers/objects/worker_spec.rb
208
210
  - spec/lib/perform_later_spec.rb
209
211
  - spec/lib/resque/plugins/later/method_spec.rb
210
212
  - spec/spec_helper.rb
@@ -242,6 +244,8 @@ test_files:
242
244
  - spec/lib/perform_later/args_parser_spec.rb
243
245
  - spec/lib/perform_later/config_spec.rb
244
246
  - spec/lib/perform_later/payload_helper_spec.rb
247
+ - spec/lib/perform_later/workers/active_record/worker_spec.rb
248
+ - spec/lib/perform_later/workers/objects/worker_spec.rb
245
249
  - spec/lib/perform_later_spec.rb
246
250
  - spec/lib/resque/plugins/later/method_spec.rb
247
251
  - spec/spec_helper.rb