perform_later 1.1.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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