resque_extensions 0.0.1
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/.gitignore +17 -0
- data/.rspec +2 -0
- data/Gemfile +12 -0
- data/Guardfile +24 -0
- data/LICENSE.txt +22 -0
- data/README.md +87 -0
- data/Rakefile +1 -0
- data/lib/resque_extensions.rb +22 -0
- data/lib/resque_extensions/async_method.rb +124 -0
- data/lib/resque_extensions/version.rb +3 -0
- data/resque_extensions.gemspec +22 -0
- data/spec/lib/resque_extensions/async_method_spec.rb +159 -0
- data/spec/lib/resque_extensions_spec.rb +61 -0
- data/spec/spec_helper.rb +51 -0
- metadata +79 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in resque_extensions.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
# this is just for our test project - we need activerecord
|
7
|
+
gem "guard-rspec"
|
8
|
+
gem "mocha"
|
9
|
+
gem "mock_redis"
|
10
|
+
gem "rails", "~> 3"
|
11
|
+
gem "rspec"
|
12
|
+
gem "sqlite3"
|
data/Guardfile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard 'rspec' do
|
5
|
+
watch(%r{^spec/.+_spec\.rb$})
|
6
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
7
|
+
watch('spec/spec_helper.rb') { "spec" }
|
8
|
+
|
9
|
+
# Rails example
|
10
|
+
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
11
|
+
watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
|
12
|
+
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
|
13
|
+
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
|
14
|
+
watch('config/routes.rb') { "spec/routing" }
|
15
|
+
watch('app/controllers/application_controller.rb') { "spec/controllers" }
|
16
|
+
|
17
|
+
# Capybara features specs
|
18
|
+
watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
|
19
|
+
|
20
|
+
# Turnip features and steps
|
21
|
+
watch(%r{^spec/acceptance/(.+)\.feature$})
|
22
|
+
watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
|
23
|
+
end
|
24
|
+
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Dan Langevin
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
# ResqueExtensions
|
2
|
+
|
3
|
+
Adds behavior to Resque to make it a bit more like Delayed::Job
|
4
|
+
|
5
|
+
To use, call `async` where you would have used `send_later`
|
6
|
+
|
7
|
+
ActiveRecord Objects are serialized with their class name and ID and pulled
|
8
|
+
out of the database when they are run.
|
9
|
+
|
10
|
+
## Usage
|
11
|
+
|
12
|
+
### Instance Method
|
13
|
+
@my_instance = MyClass.find(params[:id])
|
14
|
+
@my_instance.async(:expensive_method)
|
15
|
+
|
16
|
+
### Class Method
|
17
|
+
# This will store just the ID of the MyClass instance passed in and pull
|
18
|
+
# it out of the DB when the code is run
|
19
|
+
MyClass.async(:other_expensive_method, MyClass.find(1))
|
20
|
+
|
21
|
+
### Class Method on a class defined elsewhere
|
22
|
+
|
23
|
+
If you don't have access to the Class/Module you need (e.g. a Mailer that
|
24
|
+
is defined in a different codebase), you can use
|
25
|
+
`ResqueExtensions.enqueue_class_method`
|
26
|
+
|
27
|
+
ResqueExtensions.enqueue_class_method("MissingClass", :my_method, arg...)
|
28
|
+
|
29
|
+
### Serializing ActiveRecord objects
|
30
|
+
|
31
|
+
In Delayed::Job, you can enqueue whole objects or collections of objects,
|
32
|
+
which are then serialized by Marshal or YAML. This is problematic for
|
33
|
+
several reasons
|
34
|
+
|
35
|
+
1. Objects enqueued in one version of Ruby may not be able to be loaded in
|
36
|
+
another
|
37
|
+
2. The underlying data may have changed and we can have an invalid version
|
38
|
+
of the object when our job is performed
|
39
|
+
3. It is hard to debug jobs and determine exactly what they are doing because
|
40
|
+
Marshal and YAML are not particularly readable formats
|
41
|
+
|
42
|
+
To get around this ResqueExtensions serializes Classes and ActiveRecords in
|
43
|
+
a string format and then constantizes them or pulls them from the database
|
44
|
+
when the job is performed.
|
45
|
+
|
46
|
+
This allows us to enqueue jobs in a very flexible way. The following would
|
47
|
+
be converted to strings and the objects would be reified when the job is
|
48
|
+
performed.
|
49
|
+
|
50
|
+
my_instance.async(:my_method, other_instance, array_of_instances)
|
51
|
+
|
52
|
+
|
53
|
+
### Specifying a Queue
|
54
|
+
|
55
|
+
You can specify a queue to run this job in when you enqueue it as an optional
|
56
|
+
last argument
|
57
|
+
|
58
|
+
MyClass.async(
|
59
|
+
:other_expensive_method, MyClass.find(1), :queue => "custom-queue"
|
60
|
+
)
|
61
|
+
|
62
|
+
|
63
|
+
## Installation
|
64
|
+
|
65
|
+
Add this line to your application's Gemfile:
|
66
|
+
|
67
|
+
gem 'resque_extensions'
|
68
|
+
|
69
|
+
And then execute:
|
70
|
+
|
71
|
+
$ bundle
|
72
|
+
|
73
|
+
Or install it yourself as:
|
74
|
+
|
75
|
+
$ gem install resque_extensions
|
76
|
+
|
77
|
+
## Usage
|
78
|
+
|
79
|
+
TODO: Write usage instructions here
|
80
|
+
|
81
|
+
## Contributing
|
82
|
+
|
83
|
+
1. Fork it
|
84
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
85
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
86
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
87
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'resque'
|
2
|
+
|
3
|
+
require "resque_extensions/version"
|
4
|
+
require "resque_extensions/async_method"
|
5
|
+
|
6
|
+
module ResqueExtensions
|
7
|
+
|
8
|
+
def self.enqueue_class_method(klass, *args)
|
9
|
+
klass = "#{AsyncMethod::CLASS_PREFIX}#{klass}"
|
10
|
+
AsyncMethod.new(klass, *args).enqueue!
|
11
|
+
end
|
12
|
+
|
13
|
+
module ObjectMethods
|
14
|
+
# call this method asynchronously
|
15
|
+
def async(*args)
|
16
|
+
ResqueExtensions::AsyncMethod.new(self, *args).enqueue!
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
Object.send(:extend, ResqueExtensions::ObjectMethods)
|
22
|
+
Object.send(:include, ResqueExtensions::ObjectMethods)
|
@@ -0,0 +1,124 @@
|
|
1
|
+
module ResqueExtensions
|
2
|
+
class AsyncMethod
|
3
|
+
|
4
|
+
OPTIONAL_SETTINGS = [:queue]
|
5
|
+
|
6
|
+
ACTIVERECORD_PREFIX = "_ActiveRecord::"
|
7
|
+
CLASS_PREFIX = "_Class::"
|
8
|
+
|
9
|
+
|
10
|
+
attr_reader :args
|
11
|
+
|
12
|
+
def self.perform(*args)
|
13
|
+
data = self.reify_data(args)
|
14
|
+
caller = data.shift
|
15
|
+
# call the method with all the args
|
16
|
+
caller.send(*data)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Constructor
|
20
|
+
# @param [Object] caller The class or instance that is doing work
|
21
|
+
# @param [String, Symbol] method The method we are calling
|
22
|
+
# @param args Additional arguments we pass in
|
23
|
+
def initialize(caller, method, *args)
|
24
|
+
@caller = caller
|
25
|
+
@method = method
|
26
|
+
# set up our options
|
27
|
+
self.set_options(args)
|
28
|
+
# leftover args are assigned
|
29
|
+
@args = args
|
30
|
+
end
|
31
|
+
|
32
|
+
# Is the caller a class or an instance of
|
33
|
+
# a class
|
34
|
+
def class_method?
|
35
|
+
@caller.is_a?(Class)
|
36
|
+
end
|
37
|
+
|
38
|
+
def enqueue!
|
39
|
+
Resque::Job.create(
|
40
|
+
self.queue, self.class, *self.data_to_enqueue
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Is the caller an instance or a class
|
45
|
+
def instance_method?
|
46
|
+
!self.class_method?
|
47
|
+
end
|
48
|
+
|
49
|
+
# the queue for this job
|
50
|
+
def queue
|
51
|
+
@queue ||= "default"
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
protected
|
56
|
+
|
57
|
+
def self.reify_data(data)
|
58
|
+
# call recursively
|
59
|
+
if data.is_a?(Array)
|
60
|
+
data = data.collect{|d| self.reify_data(d)}
|
61
|
+
# call on values
|
62
|
+
elsif data.is_a?(Hash)
|
63
|
+
data.each_pair do |k,v|
|
64
|
+
data[k] = self.reify_data(v)
|
65
|
+
end
|
66
|
+
# our special ActiveRecord encoding
|
67
|
+
elsif data.to_s =~ /^#{ACTIVERECORD_PREFIX}/
|
68
|
+
# get our ActiveRecord back
|
69
|
+
data = data.split("::")
|
70
|
+
id = data.pop
|
71
|
+
class_name = data[1..-1].join("::")
|
72
|
+
data = Resque::Job.constantize(class_name).find(id)
|
73
|
+
# classes become strings prefixed by _Class
|
74
|
+
elsif data.to_s =~ /^#{CLASS_PREFIX}/
|
75
|
+
data = Resque::Job.constantize(data.gsub(/^#{CLASS_PREFIX}/,''))
|
76
|
+
end
|
77
|
+
# return data
|
78
|
+
data
|
79
|
+
end
|
80
|
+
|
81
|
+
def data_to_enqueue
|
82
|
+
self.prepare_data([@caller, @method, *@args])
|
83
|
+
end
|
84
|
+
|
85
|
+
# prepare our data for Redis
|
86
|
+
def prepare_data(data)
|
87
|
+
# call recursively
|
88
|
+
if data.is_a?(Array)
|
89
|
+
data = data.collect{|d| self.prepare_data(d)}
|
90
|
+
# call on values
|
91
|
+
elsif data.is_a?(Hash)
|
92
|
+
data.each_pair do |k,v|
|
93
|
+
data[k] = self.prepare_data(v)
|
94
|
+
end
|
95
|
+
# our special ActiveRecord encoding
|
96
|
+
elsif data.is_a?(ActiveRecord::Base)
|
97
|
+
data = "_ActiveRecord::#{data.class}::#{data.id}"
|
98
|
+
# classes become strings prefixed by _Class
|
99
|
+
elsif data.is_a?(Class)
|
100
|
+
data = "_Class::#{data.to_s}"
|
101
|
+
end
|
102
|
+
# return data
|
103
|
+
data
|
104
|
+
end
|
105
|
+
|
106
|
+
# set the options passed in as instance variables
|
107
|
+
def set_options(args)
|
108
|
+
if self.has_options?(args.last)
|
109
|
+
args.pop.each_pair do |key, val|
|
110
|
+
instance_variable_set("@#{key}", val)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# Is the given argument a hash of valid options
|
116
|
+
def has_options?(argument)
|
117
|
+
return false unless argument.is_a?(Hash)
|
118
|
+
# get our keys
|
119
|
+
keys = argument.keys.collect(&:to_sym)
|
120
|
+
# if we have overlaps, we've been passed options
|
121
|
+
return (keys & OPTIONAL_SETTINGS).length > 0
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'resque_extensions/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "resque_extensions"
|
8
|
+
gem.version = ResqueExtensions::VERSION
|
9
|
+
gem.authors = ["Dan Langevin"]
|
10
|
+
gem.email = ["dan.langevin@lifebooker.com"]
|
11
|
+
gem.description = %q{An extension to Resque that makes it act more like Delayed::Job}
|
12
|
+
gem.summary = %q{Resque extensions to add .async}
|
13
|
+
gem.homepage = "https://github.com/dlangevin/resque_extensions"
|
14
|
+
|
15
|
+
# works with resque before 2.0
|
16
|
+
gem.add_dependency "resque", "~> 1"
|
17
|
+
|
18
|
+
gem.files = `git ls-files`.split($/)
|
19
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
20
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
21
|
+
gem.require_paths = ["lib"]
|
22
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module ResqueExtensions
|
4
|
+
|
5
|
+
describe AsyncMethod do
|
6
|
+
|
7
|
+
context ".perform" do
|
8
|
+
|
9
|
+
it "deserializes and calls a method on the caller" do
|
10
|
+
async_method = AsyncMethod.new(MyClass, :my_class_method, "a")
|
11
|
+
async_method.enqueue!
|
12
|
+
|
13
|
+
# make sure we call the correct
|
14
|
+
MyClass.expects(:send).with("my_class_method", "a")
|
15
|
+
|
16
|
+
job = Resque.reserve("default")
|
17
|
+
job.perform
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
it "deserializes and calls a method on an ActiveRecord" do
|
22
|
+
|
23
|
+
my_instance = MyClass.create(:name => "Dan")
|
24
|
+
|
25
|
+
async_method = AsyncMethod.new(my_instance, :my_instance_method)
|
26
|
+
async_method.enqueue!
|
27
|
+
|
28
|
+
MyClass.expects(:find).with(my_instance.id.to_s).returns(my_instance)
|
29
|
+
my_instance.expects(:send).with("my_instance_method")
|
30
|
+
|
31
|
+
job = Resque.reserve("default")
|
32
|
+
job.perform
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
context "#initialize" do
|
40
|
+
|
41
|
+
it "initializes with a class" do
|
42
|
+
|
43
|
+
async_method = AsyncMethod.new(MyClass, :my_class_method)
|
44
|
+
async_method.should be_class_method
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
it "initializes with an instance" do
|
49
|
+
|
50
|
+
async_method = AsyncMethod.new(MyClass.new, :my_class_method)
|
51
|
+
async_method.should be_instance_method
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
context "#args" do
|
58
|
+
|
59
|
+
it "accepts a variable number of arguments" do
|
60
|
+
|
61
|
+
async_method = AsyncMethod.new(
|
62
|
+
MyClass, :my_class_method, :a, :b, "c"
|
63
|
+
)
|
64
|
+
async_method.args.should eql([:a, :b, "c"])
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
it "removes any options from the arguments" do
|
69
|
+
async_method = AsyncMethod.new(
|
70
|
+
MyClass, :my_class_method, :a, :b, {:queue => "test"}
|
71
|
+
)
|
72
|
+
async_method.args.should eql([:a, :b])
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
context "#enqueue" do
|
78
|
+
|
79
|
+
it "creates a new job for the class or instance" do
|
80
|
+
async_method = AsyncMethod.new(MyClass, :my_class_method)
|
81
|
+
async_method.enqueue!
|
82
|
+
|
83
|
+
job = Resque.reserve("default")
|
84
|
+
|
85
|
+
job.payload.should eql({
|
86
|
+
"class" => "ResqueExtensions::AsyncMethod",
|
87
|
+
"args" => ["_Class::MyClass", "my_class_method"]
|
88
|
+
})
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
it "serializes ActiveRecords passed in as the caller" do
|
93
|
+
|
94
|
+
my_instance = MyClass.create(:name => "Dan")
|
95
|
+
|
96
|
+
async_method = AsyncMethod.new(my_instance, :my_instance_method)
|
97
|
+
async_method.enqueue!
|
98
|
+
|
99
|
+
job = Resque.reserve("default")
|
100
|
+
|
101
|
+
job.payload.should eql({
|
102
|
+
"class" => "ResqueExtensions::AsyncMethod",
|
103
|
+
"args" => [
|
104
|
+
"_ActiveRecord::MyClass::#{my_instance.id}",
|
105
|
+
"my_instance_method"
|
106
|
+
]
|
107
|
+
})
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
it "serializes ActiveRecords passed in as arguments" do
|
112
|
+
|
113
|
+
my_instance = MyClass.create(:name => "Dan")
|
114
|
+
|
115
|
+
async_method = AsyncMethod.new(
|
116
|
+
MyClass,
|
117
|
+
:my_class_method,
|
118
|
+
[my_instance],
|
119
|
+
my_instance,
|
120
|
+
{:a => my_instance}
|
121
|
+
)
|
122
|
+
async_method.enqueue!
|
123
|
+
|
124
|
+
instance_string = "_ActiveRecord::MyClass::#{my_instance.id}"
|
125
|
+
|
126
|
+
|
127
|
+
job = Resque.reserve("default")
|
128
|
+
|
129
|
+
job.payload.should eql({
|
130
|
+
"class" => "ResqueExtensions::AsyncMethod",
|
131
|
+
"args" => [
|
132
|
+
"_Class::MyClass",
|
133
|
+
"my_class_method",
|
134
|
+
[instance_string],
|
135
|
+
instance_string,
|
136
|
+
{"a" => instance_string}
|
137
|
+
]
|
138
|
+
})
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
context "#queue" do
|
145
|
+
|
146
|
+
it "sets the queue if it is passed as an argument" do
|
147
|
+
|
148
|
+
async_method = AsyncMethod.new(
|
149
|
+
MyClass, :my_class_method, :queue => "test"
|
150
|
+
)
|
151
|
+
async_method.queue.should eql("test")
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ResqueExtensions do
|
4
|
+
|
5
|
+
context ".enqueue_class_method" do
|
6
|
+
|
7
|
+
it "enqueues a class method from a string" do
|
8
|
+
ResqueExtensions.enqueue_class_method(
|
9
|
+
"MyClass", :my_class_method
|
10
|
+
)
|
11
|
+
MyClass.expects(:send).with("my_class_method")
|
12
|
+
|
13
|
+
job = Resque.reserve("default")
|
14
|
+
job.perform
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
context "ObjectMethods" do
|
20
|
+
|
21
|
+
context ".async" do
|
22
|
+
|
23
|
+
it "enqueues a class method resque" do
|
24
|
+
|
25
|
+
MyClass.async(:my_class_method, "a", "b", "c")
|
26
|
+
|
27
|
+
MyClass.expects(:send).with("my_class_method", "a", "b", "c")
|
28
|
+
|
29
|
+
job = Resque.reserve("default")
|
30
|
+
job.perform
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
context "#async" do
|
36
|
+
|
37
|
+
it "enqueues an instance method resque" do
|
38
|
+
|
39
|
+
my_class = MyClass.create(:name => "test")
|
40
|
+
|
41
|
+
my_class.async(:my_instance_method, {:a => my_class})
|
42
|
+
|
43
|
+
MyClass.stubs(:find).with(my_class.id.to_s).returns(my_class)
|
44
|
+
|
45
|
+
my_class.expects(:send)
|
46
|
+
.with(
|
47
|
+
"my_instance_method",
|
48
|
+
has_entries("a" => instance_of(MyClass))
|
49
|
+
)
|
50
|
+
|
51
|
+
job = Resque.reserve("default")
|
52
|
+
job.perform
|
53
|
+
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
|
2
|
+
require 'resque_extensions'
|
3
|
+
|
4
|
+
require 'active_record'
|
5
|
+
require 'mock_redis'
|
6
|
+
require 'resque'
|
7
|
+
|
8
|
+
|
9
|
+
Bundler.setup
|
10
|
+
|
11
|
+
ActiveRecord::Base.establish_connection(
|
12
|
+
:adapter => "sqlite3",
|
13
|
+
:database => File.dirname(__FILE__) + "/../tmp/test.sqlite"
|
14
|
+
)
|
15
|
+
|
16
|
+
Resque.redis = MockRedis.new
|
17
|
+
|
18
|
+
# This code will be run each time you run your specs.
|
19
|
+
Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each {|f| require f}
|
20
|
+
|
21
|
+
RSpec.configure do |config|
|
22
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
23
|
+
config.run_all_when_everything_filtered = true
|
24
|
+
config.mock_with :mocha
|
25
|
+
|
26
|
+
config.before(:each) do
|
27
|
+
Resque.redis = MockRedis.new
|
28
|
+
end
|
29
|
+
|
30
|
+
config.before(:all) do
|
31
|
+
|
32
|
+
ActiveRecord::Base.connection.create_table(:my_classes, :force => true) do |t|
|
33
|
+
|
34
|
+
t.string(:name)
|
35
|
+
t.timestamps
|
36
|
+
end
|
37
|
+
|
38
|
+
MyClass = Class.new(ActiveRecord::Base) do
|
39
|
+
def my_instance_method(*args)
|
40
|
+
return args
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.my_class_method(*args)
|
44
|
+
return args
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
metadata
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: resque_extensions
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Dan Langevin
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-06-04 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: resque
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1'
|
30
|
+
description: An extension to Resque that makes it act more like Delayed::Job
|
31
|
+
email:
|
32
|
+
- dan.langevin@lifebooker.com
|
33
|
+
executables: []
|
34
|
+
extensions: []
|
35
|
+
extra_rdoc_files: []
|
36
|
+
files:
|
37
|
+
- .gitignore
|
38
|
+
- .rspec
|
39
|
+
- Gemfile
|
40
|
+
- Guardfile
|
41
|
+
- LICENSE.txt
|
42
|
+
- README.md
|
43
|
+
- Rakefile
|
44
|
+
- lib/resque_extensions.rb
|
45
|
+
- lib/resque_extensions/async_method.rb
|
46
|
+
- lib/resque_extensions/version.rb
|
47
|
+
- resque_extensions.gemspec
|
48
|
+
- spec/lib/resque_extensions/async_method_spec.rb
|
49
|
+
- spec/lib/resque_extensions_spec.rb
|
50
|
+
- spec/spec_helper.rb
|
51
|
+
homepage: https://github.com/dlangevin/resque_extensions
|
52
|
+
licenses: []
|
53
|
+
post_install_message:
|
54
|
+
rdoc_options: []
|
55
|
+
require_paths:
|
56
|
+
- lib
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
requirements: []
|
70
|
+
rubyforge_project:
|
71
|
+
rubygems_version: 1.8.24
|
72
|
+
signing_key:
|
73
|
+
specification_version: 3
|
74
|
+
summary: Resque extensions to add .async
|
75
|
+
test_files:
|
76
|
+
- spec/lib/resque_extensions/async_method_spec.rb
|
77
|
+
- spec/lib/resque_extensions_spec.rb
|
78
|
+
- spec/spec_helper.rb
|
79
|
+
has_rdoc:
|