resque_extensions 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|