sucker_punch-backgroundable 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.document +5 -0
- data/.rspec +2 -0
- data/.travis +7 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +17 -0
- data/Gemfile.lock +101 -0
- data/LICENSE.txt +8 -0
- data/README.md +150 -0
- data/Rakefile +50 -0
- data/VERSION +1 -0
- data/lib/sucker_punch/backgroundable/backgroundable.rb +155 -0
- data/lib/sucker_punch/backgroundable/config.rb +26 -0
- data/lib/sucker_punch/backgroundable/job.rb +36 -0
- data/lib/sucker_punch/backgroundable/util.rb +47 -0
- data/lib/sucker_punch-backgroundable.rb +6 -0
- data/spec/load_active_record.rb +32 -0
- data/spec/spec_helper.rb +29 -0
- data/spec/sucker_punch-backgroundable_spec.rb +158 -0
- data/spec/test_class.rb +54 -0
- data/spec/test_model.rb +29 -0
- metadata +178 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MGYyZWEyZWM0ZWJhMTFlNmI5MTFmZjRjOWQxYzk5NmY5ZDc2NTMwYQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
YjgyMzgyYTZlNzAzMWQwZTgzZjgwNTc4ZjRlMGJkNzcyODFjZTkwZA==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NTAyYzMxZDQxYmFkMzk2NzMwODFiYmI5NmMxYWZlYmU0OWVlNDZmOTQ5Njcz
|
10
|
+
MDkxZmFjOThjNjNjMDMwNmUyOWU1N2Y5YTY2Mzk0ZTMyZGY3YWI4ODJmMjM2
|
11
|
+
ZDVmNDk1NzBlMzliNzkxZGRkOTQwMmY1YThiOWI5ODBjMjZiYzU=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZTY0M2Q3MGMxMTJkZTY4ODQ3ZDc4N2M2NjE0YzNkZGQ4YTcyYzZlNjU3NTRm
|
14
|
+
MjdiOTBhMGE5ZDNlMDhkY2M4ZjYwMWEzYTliYzU5ZGMwYmNjODEwNzdkY2Uy
|
15
|
+
NmFiNzAyMGE2ZDRiNmNiNTE3NWZiNjZlOWUxZjQ2MDg3MzIzOWY=
|
data/.document
ADDED
data/.rspec
ADDED
data/.travis
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
# gem "activesupport", ">= 2.3.5"
|
5
|
+
gem "sucker_punch", ">= 1.0.0"
|
6
|
+
|
7
|
+
# Add dependencies to develop your gem here.
|
8
|
+
# Include everything needed to run rake, tests, features, etc.
|
9
|
+
group :development do
|
10
|
+
gem "rspec", "~> 2.8.0"
|
11
|
+
gem "rdoc", "~> 3.12"
|
12
|
+
gem "bundler", "~> 1.0"
|
13
|
+
gem "jeweler", "~> 2.0.1"
|
14
|
+
gem "simplecov", ">= 0"
|
15
|
+
gem "activerecord"
|
16
|
+
gem "sqlite3"
|
17
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
activemodel (4.1.0)
|
5
|
+
activesupport (= 4.1.0)
|
6
|
+
builder (~> 3.1)
|
7
|
+
activerecord (4.1.0)
|
8
|
+
activemodel (= 4.1.0)
|
9
|
+
activesupport (= 4.1.0)
|
10
|
+
arel (~> 5.0.0)
|
11
|
+
activesupport (4.1.0)
|
12
|
+
i18n (~> 0.6, >= 0.6.9)
|
13
|
+
json (~> 1.7, >= 1.7.7)
|
14
|
+
minitest (~> 5.1)
|
15
|
+
thread_safe (~> 0.1)
|
16
|
+
tzinfo (~> 1.1)
|
17
|
+
addressable (2.3.6)
|
18
|
+
arel (5.0.1.20140414130214)
|
19
|
+
builder (3.2.2)
|
20
|
+
celluloid (0.15.2)
|
21
|
+
timers (~> 1.1.0)
|
22
|
+
descendants_tracker (0.0.4)
|
23
|
+
thread_safe (~> 0.3, >= 0.3.1)
|
24
|
+
diff-lcs (1.1.3)
|
25
|
+
docile (1.1.3)
|
26
|
+
faraday (0.9.0)
|
27
|
+
multipart-post (>= 1.2, < 3)
|
28
|
+
git (1.2.6)
|
29
|
+
github_api (0.11.3)
|
30
|
+
addressable (~> 2.3)
|
31
|
+
descendants_tracker (~> 0.0.1)
|
32
|
+
faraday (~> 0.8, < 0.10)
|
33
|
+
hashie (>= 1.2)
|
34
|
+
multi_json (>= 1.7.5, < 2.0)
|
35
|
+
nokogiri (~> 1.6.0)
|
36
|
+
oauth2
|
37
|
+
hashie (2.1.1)
|
38
|
+
highline (1.6.21)
|
39
|
+
i18n (0.6.9)
|
40
|
+
jeweler (2.0.1)
|
41
|
+
builder
|
42
|
+
bundler (>= 1.0)
|
43
|
+
git (>= 1.2.5)
|
44
|
+
github_api
|
45
|
+
highline (>= 1.6.15)
|
46
|
+
nokogiri (>= 1.5.10)
|
47
|
+
rake
|
48
|
+
rdoc
|
49
|
+
json (1.8.1)
|
50
|
+
jwt (0.1.13)
|
51
|
+
multi_json (>= 1.5)
|
52
|
+
mini_portile (0.6.0)
|
53
|
+
minitest (5.3.4)
|
54
|
+
multi_json (1.10.0)
|
55
|
+
multi_xml (0.5.5)
|
56
|
+
multipart-post (2.0.0)
|
57
|
+
nokogiri (1.6.2.1)
|
58
|
+
mini_portile (= 0.6.0)
|
59
|
+
oauth2 (0.9.3)
|
60
|
+
faraday (>= 0.8, < 0.10)
|
61
|
+
jwt (~> 0.1.8)
|
62
|
+
multi_json (~> 1.3)
|
63
|
+
multi_xml (~> 0.5)
|
64
|
+
rack (~> 1.2)
|
65
|
+
rack (1.5.2)
|
66
|
+
rake (10.3.2)
|
67
|
+
rdoc (3.12.2)
|
68
|
+
json (~> 1.4)
|
69
|
+
rspec (2.8.0)
|
70
|
+
rspec-core (~> 2.8.0)
|
71
|
+
rspec-expectations (~> 2.8.0)
|
72
|
+
rspec-mocks (~> 2.8.0)
|
73
|
+
rspec-core (2.8.0)
|
74
|
+
rspec-expectations (2.8.0)
|
75
|
+
diff-lcs (~> 1.1.2)
|
76
|
+
rspec-mocks (2.8.0)
|
77
|
+
simplecov (0.8.2)
|
78
|
+
docile (~> 1.1.0)
|
79
|
+
multi_json
|
80
|
+
simplecov-html (~> 0.8.0)
|
81
|
+
simplecov-html (0.8.0)
|
82
|
+
sqlite3 (1.3.9)
|
83
|
+
sucker_punch (1.0.5)
|
84
|
+
celluloid (~> 0.15.2)
|
85
|
+
thread_safe (0.3.3)
|
86
|
+
timers (1.1.0)
|
87
|
+
tzinfo (1.1.0)
|
88
|
+
thread_safe (~> 0.1)
|
89
|
+
|
90
|
+
PLATFORMS
|
91
|
+
ruby
|
92
|
+
|
93
|
+
DEPENDENCIES
|
94
|
+
activerecord
|
95
|
+
bundler (~> 1.0)
|
96
|
+
jeweler (~> 2.0.1)
|
97
|
+
rdoc (~> 3.12)
|
98
|
+
rspec (~> 2.8.0)
|
99
|
+
simplecov
|
100
|
+
sqlite3
|
101
|
+
sucker_punch (>= 1.0.0)
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
Copyright (c) 2014 Michaël Van Damme
|
2
|
+
|
3
|
+
sucker_punch-backgroundable is an Open Source project licensed under the terms of
|
4
|
+
the LGPLv3 license. Please see <http://www.gnu.org/licenses/lgpl-3.0.html>
|
5
|
+
for the license text.
|
6
|
+
|
7
|
+
Parts of sucker_punch-backgroundable were taken from the TorqueBox project, which is
|
8
|
+
also licensed under LGPLv3 (see <http://torquebox.org/license/>).
|
data/README.md
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
# sucker_punch-backgroundable
|
2
|
+
[![Build Status](https://travis-ci.org/mvdamme/sucker_punch-backgroundable.png)](https://travis-ci.org/mvdamme/sucker_punch-backgroundable)
|
3
|
+
|
4
|
+
This gem allows you to background any method call with [SuckerPunch](https://github.com/brandonhilkert/sucker_punch) without
|
5
|
+
having to write a special job class.
|
6
|
+
It provides the same API as the Backgroundable module from [TorqueBox](http://torquebox.org/), and a large part of the code
|
7
|
+
comes directly from the TorqueBox project.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add the following to your Gemfile:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
gem 'sucker_punch-backgroundable'
|
15
|
+
```
|
16
|
+
|
17
|
+
And then execute:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
bundle install
|
21
|
+
```
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
Include the `SuckerPunch::Backgroundable` module in your class. Then you can use `always_background :method1, :method2, ...` to
|
26
|
+
cause the supplied methods to run asynchronously (in the background). Example:
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
class MyClass
|
30
|
+
SuckerPunch::Backgroundable
|
31
|
+
|
32
|
+
always_background :send_email
|
33
|
+
def send_email
|
34
|
+
# ...
|
35
|
+
end
|
36
|
+
|
37
|
+
always_background :calculate_statistics
|
38
|
+
def self.calculate_statistics
|
39
|
+
# ...
|
40
|
+
end
|
41
|
+
end
|
42
|
+
```
|
43
|
+
|
44
|
+
In this example, calls to instance method `send_email` and class method `calculate_statistics` will automatically run in the background:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
obj = MyClass.new
|
48
|
+
obj.send_email # returns immediately, method runs in the background
|
49
|
+
|
50
|
+
Myclass.calculate_statistics # returns immediately, method runs in the background
|
51
|
+
```
|
52
|
+
|
53
|
+
Methods that have not been marked with `always_background` can also be backgrounded when you call them:
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
class MyClass
|
57
|
+
SuckerPunch::Backgroundable
|
58
|
+
|
59
|
+
def notify
|
60
|
+
# ...
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
obj = MyClass.new
|
65
|
+
|
66
|
+
# This will run in the background (and return immediately)
|
67
|
+
obj.background.notify
|
68
|
+
|
69
|
+
# This will run the method normally (synchronously, returning after the method is finished)
|
70
|
+
obj.background.notify
|
71
|
+
```
|
72
|
+
|
73
|
+
It is also possible to specify a delay in seconds:
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
# This will return immediately and run the method in the background after a delay of 60 seconds
|
77
|
+
obj.later(60).notify
|
78
|
+
```
|
79
|
+
|
80
|
+
Both `background` and `later` also work with class methods (e.g. `MyClass.background.my_class_method(argument)`).
|
81
|
+
|
82
|
+
### Reloading
|
83
|
+
|
84
|
+
When backgrounding an instance method, the method is called on the object, but in a different thread (using SuckerPunch).
|
85
|
+
If you don't use the object anymore in the current thread, this is ok. If the object is still being used in the current thread,
|
86
|
+
it may be better to reload it from the data store (assuming a data store backed object) in the background thread to avoid any
|
87
|
+
threading issues. The gem can do this automatically, although currently only ActiveRecord is supported:
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
class MyModel < ActiveRecord::Base
|
91
|
+
SuckerPunch::Backgroundable
|
92
|
+
|
93
|
+
always_background :send_email, :reload => true
|
94
|
+
def send_email
|
95
|
+
# ...
|
96
|
+
end
|
97
|
+
end
|
98
|
+
```
|
99
|
+
|
100
|
+
Or, when using `background` or `later`:
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
obj.background(:reload => true).my_instance_method
|
104
|
+
obj.later(60, :reload => true).my_instance_method
|
105
|
+
```
|
106
|
+
|
107
|
+
It is also possible to specify the `reload` option globally by using an initializer:
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
SuckerPunch::Backgroundable.configure do |config|
|
111
|
+
config.reload = true
|
112
|
+
end
|
113
|
+
```
|
114
|
+
|
115
|
+
## Configuration
|
116
|
+
|
117
|
+
Apart from the `reload` option described above, there is only one other configuration setting:
|
118
|
+
|
119
|
+
```ruby
|
120
|
+
SuckerPunch::Backgroundable.configure do |config|
|
121
|
+
config.reload = true
|
122
|
+
config.workers = 4 # default is 2
|
123
|
+
end
|
124
|
+
```
|
125
|
+
|
126
|
+
The number of workers sets the number of background threads that SuckerPunch will use. The default (and minimum) is 2.
|
127
|
+
|
128
|
+
## Usage with ActiveRecord
|
129
|
+
|
130
|
+
When using this gem with ActiveRecord models, it is recommended to set the `reload` option to true (see above).
|
131
|
+
If you want sucker_punch-backgroundable to be available in all models you can use the following in an initializer:
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
ActiveRecord::Base.send(:include, SuckerPunch::Backgroundable)
|
135
|
+
```
|
136
|
+
|
137
|
+
## Contributing to sucker_punch-backgroundable
|
138
|
+
|
139
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
140
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
|
141
|
+
* Fork the project.
|
142
|
+
* Start a feature/bugfix branch.
|
143
|
+
* Commit and push until you are happy with your contribution.
|
144
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
145
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
146
|
+
|
147
|
+
## Copyright
|
148
|
+
|
149
|
+
Copyright (c) 2014 Michaël Van Damme. See LICENSE.txt for
|
150
|
+
further details.
|
data/Rakefile
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://guides.rubygems.org/specification-reference/ for more options
|
17
|
+
gem.name = "sucker_punch-backgroundable"
|
18
|
+
gem.homepage = "http://github.com/mvdamme/sucker_punch-backgroundable"
|
19
|
+
gem.license = "LGPL-3"
|
20
|
+
gem.summary = %Q{Easily execute an object's methods in the background with sucker_punch}
|
21
|
+
gem.description = %Q{This gem allows you to background any method call without having to write a special job class. Heavily inspired by the Backgroundable module in TorqueBox.}
|
22
|
+
gem.email = "michael.vandamme@vub.ac.be"
|
23
|
+
gem.authors = ["Michaël Van Damme"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
end
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
27
|
+
|
28
|
+
require 'rspec/core'
|
29
|
+
require 'rspec/core/rake_task'
|
30
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
31
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
32
|
+
end
|
33
|
+
|
34
|
+
desc "Code coverage detail"
|
35
|
+
task :simplecov do
|
36
|
+
ENV['COVERAGE'] = "true"
|
37
|
+
Rake::Task['spec'].execute
|
38
|
+
end
|
39
|
+
|
40
|
+
task :default => :spec
|
41
|
+
|
42
|
+
require 'rdoc/task'
|
43
|
+
Rake::RDocTask.new do |rdoc|
|
44
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
45
|
+
|
46
|
+
rdoc.rdoc_dir = 'rdoc'
|
47
|
+
rdoc.title = "sucker_punch-backgroundable #{version}"
|
48
|
+
rdoc.rdoc_files.include('README*')
|
49
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
50
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,155 @@
|
|
1
|
+
# The majority of this file (> 95%) was copied from the Backgroundable module in Torquebox
|
2
|
+
# (see https://github.com/torquebox/torquebox/blob/master/gems/messaging/lib/torquebox/messaging/backgroundable.rb).
|
3
|
+
# The code was slightly adapted so it works with Sucker Punch instead of Torquebox messaging.
|
4
|
+
|
5
|
+
module SuckerPunch
|
6
|
+
|
7
|
+
# Backgroundable provides mechanism for executing an object's
|
8
|
+
# methods asynchronously.
|
9
|
+
module Backgroundable
|
10
|
+
|
11
|
+
def self.included(base)
|
12
|
+
base.extend(BackgroundableClassMethods)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Allows you to background any method that has not been marked
|
16
|
+
# as a backgrounded method via {BackgroundableClassMethods#always_background}.
|
17
|
+
def background(options = { })
|
18
|
+
BackgroundProxy.new(self, options)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Allows you to background any method that has not been marked
|
22
|
+
# as a backgrounded method via {BackgroundableClassMethods#always_background}.
|
23
|
+
# The method will not be executed immediately, but only after 'seconds' seconds.
|
24
|
+
def later(seconds, options = { })
|
25
|
+
BackgroundProxy.new(self, options, seconds)
|
26
|
+
end
|
27
|
+
|
28
|
+
module BackgroundableClassMethods
|
29
|
+
|
30
|
+
# Marks methods to always be backgrounded. Takes one or more
|
31
|
+
# method symbols, and an optional options hash as the final
|
32
|
+
# argument.
|
33
|
+
def always_background(*methods)
|
34
|
+
options = methods.last.is_a?(Hash) ? methods.pop : {}
|
35
|
+
@__backgroundable_methods ||= {}
|
36
|
+
|
37
|
+
methods.each do |method|
|
38
|
+
method = method.to_s
|
39
|
+
if !@__backgroundable_methods[method]
|
40
|
+
@__backgroundable_methods[method] ||= { }
|
41
|
+
@__backgroundable_methods[method][:options] = options
|
42
|
+
if Util.singleton_methods_include?(self, method) ||
|
43
|
+
Util.instance_methods_include?(self, method)
|
44
|
+
__enable_backgrounding(method)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Allows you to background any method that has not been marked
|
51
|
+
# as a backgrounded method via {BackgroundableClassMethods#always_background}.
|
52
|
+
def background(options = { })
|
53
|
+
BackgroundProxy.new(self, options)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Allows you to background any method that has not been marked
|
57
|
+
# as a backgrounded method via {BackgroundableClassMethods#always_background}.
|
58
|
+
# The method will not be executed immediately, but only after 'seconds' seconds.
|
59
|
+
def later(seconds, options = { })
|
60
|
+
BackgroundProxy.new(self, options, seconds)
|
61
|
+
end
|
62
|
+
|
63
|
+
# @api private
|
64
|
+
def method_added(method)
|
65
|
+
super
|
66
|
+
__method_added(method)
|
67
|
+
end
|
68
|
+
|
69
|
+
# @api private
|
70
|
+
def singleton_method_added(method)
|
71
|
+
super
|
72
|
+
__method_added(method)
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def __method_added(method)
|
78
|
+
method = method.to_s
|
79
|
+
if @__backgroundable_methods &&
|
80
|
+
@__backgroundable_methods[method] &&
|
81
|
+
!@__backgroundable_methods[method][:backgrounding]
|
82
|
+
__enable_backgrounding(method)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def __enable_backgrounding(method)
|
87
|
+
singleton_method = Util.singleton_methods_include?(self, method)
|
88
|
+
singleton = (class << self; self; end)
|
89
|
+
|
90
|
+
if singleton_method
|
91
|
+
|
92
|
+
SuckerPunch.logger.
|
93
|
+
warn("always_background called for :#{method}, but :#{method} " +
|
94
|
+
"exists as both a class and instance method. Only the " +
|
95
|
+
"class method will be backgrounded.") if Util.instance_methods_include?(self, method)
|
96
|
+
|
97
|
+
privatize = Util.private_singleton_methods_include?(self, method)
|
98
|
+
protect = Util.protected_singleton_methods_include?(self, method) unless privatize
|
99
|
+
else
|
100
|
+
privatize = Util.private_instance_methods_include?(self, method)
|
101
|
+
protect = Util.protected_instance_methods_include?(self, method) unless privatize
|
102
|
+
end
|
103
|
+
|
104
|
+
async_method = "__async_#{method}"
|
105
|
+
sync_method = "__sync_#{method}"
|
106
|
+
|
107
|
+
@__backgroundable_methods[method][:backgrounding] = true
|
108
|
+
options = @__backgroundable_methods[method][:options]
|
109
|
+
|
110
|
+
(singleton_method ? singleton : self).class_eval do
|
111
|
+
define_method async_method do |*args|
|
112
|
+
# run sucker punch job asynchronously
|
113
|
+
Job.new.async.perform(self, sync_method, args, options)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
code = singleton_method ? "class << self" : ""
|
118
|
+
code << %Q{
|
119
|
+
alias_method :#{sync_method}, :#{method}
|
120
|
+
alias_method :#{method}, :#{async_method}
|
121
|
+
}
|
122
|
+
code << %Q{
|
123
|
+
#{privatize ? "private" : "protected"} :#{method}, :#{sync_method}, :#{async_method}
|
124
|
+
} if privatize || protect
|
125
|
+
code << "end" if singleton_method
|
126
|
+
|
127
|
+
class_eval code
|
128
|
+
ensure
|
129
|
+
@__backgroundable_methods[method][:backgrounding] = nil
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
# @api private
|
135
|
+
class BackgroundProxy
|
136
|
+
def initialize(receiver, options, seconds = 0)
|
137
|
+
@receiver = receiver
|
138
|
+
@options = options
|
139
|
+
@seconds = seconds
|
140
|
+
end
|
141
|
+
|
142
|
+
def method_missing(method, *args, &block)
|
143
|
+
@receiver.method_missing(method, *args, &block) unless @receiver.respond_to?(method)
|
144
|
+
raise ArgumentError.new("Backgrounding a method with a block argument is not supported.") if block_given?
|
145
|
+
if @seconds > 0
|
146
|
+
Job.new.async.later(@seconds, @receiver, method, args, @options)
|
147
|
+
else
|
148
|
+
Job.new.async.perform(@receiver, method, args, @options)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# configuration, see http://robots.thoughtbot.com/mygem-configure-block.
|
2
|
+
module SuckerPunch
|
3
|
+
module Backgroundable
|
4
|
+
class << self
|
5
|
+
attr_accessor :configuration
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.configure
|
9
|
+
self.configuration ||= Configuration.new
|
10
|
+
yield(configuration)
|
11
|
+
end
|
12
|
+
|
13
|
+
class Configuration
|
14
|
+
attr_accessor :workers
|
15
|
+
attr_accessor :reload
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@workers = 2
|
19
|
+
@reload = false
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
SuckerPunch::Backgroundable.configure {}
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module SuckerPunch
|
2
|
+
module Backgroundable
|
3
|
+
|
4
|
+
class Job
|
5
|
+
include SuckerPunch::Job
|
6
|
+
workers SuckerPunch::Backgroundable.configuration.workers
|
7
|
+
|
8
|
+
def perform(receiver, method, args, options)
|
9
|
+
receiver = load(receiver) if instantiate?(options)
|
10
|
+
if defined?(ActiveRecord)
|
11
|
+
ActiveRecord::Base.connection_pool.with_connection do
|
12
|
+
receiver.send(method, *args)
|
13
|
+
end
|
14
|
+
else
|
15
|
+
receiver.send(method, *args)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def later(sec, *args)
|
20
|
+
after(sec) { perform(*args) }
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def instantiate?(options)
|
26
|
+
return true if SuckerPunch::Backgroundable.configuration.reload && !(!options[:reload].nil? && options[:reload] == false)
|
27
|
+
options[:reload]
|
28
|
+
end
|
29
|
+
|
30
|
+
def load(receiver)
|
31
|
+
receiver.respond_to?(:id) ? receiver.class.find(receiver.id) : receiver
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# This code was copied from the Backgroundable module in Torquebox
|
2
|
+
# (see https://github.com/torquebox/torquebox/blob/master/gems/messaging/lib/torquebox/messaging/backgroundable.rb).
|
3
|
+
|
4
|
+
module SuckerPunch
|
5
|
+
|
6
|
+
module Backgroundable
|
7
|
+
|
8
|
+
module Util
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def singleton_methods_include?(klass, method)
|
12
|
+
methods_include?(klass.singleton_methods, method) ||
|
13
|
+
private_singleton_methods_include?(klass, method)
|
14
|
+
end
|
15
|
+
|
16
|
+
def private_singleton_methods_include?(klass, method)
|
17
|
+
methods_include?(klass.private_methods, method)
|
18
|
+
end
|
19
|
+
|
20
|
+
def protected_singleton_methods_include?(klass, method)
|
21
|
+
methods_include?(klass.protected_methods, method)
|
22
|
+
end
|
23
|
+
|
24
|
+
def instance_methods_include?(klass, method)
|
25
|
+
methods_include?(klass.instance_methods, method) ||
|
26
|
+
private_instance_methods_include?(klass, method)
|
27
|
+
end
|
28
|
+
|
29
|
+
def private_instance_methods_include?(klass, method)
|
30
|
+
methods_include?(klass.private_instance_methods, method)
|
31
|
+
end
|
32
|
+
|
33
|
+
def protected_instance_methods_include?(klass, method)
|
34
|
+
methods_include?(klass.protected_instance_methods, method)
|
35
|
+
end
|
36
|
+
|
37
|
+
def methods_include?(methods, method)
|
38
|
+
method = (RUBY_VERSION =~ /^1\.8\./ ? method.to_s : method.to_sym)
|
39
|
+
methods.include?(method)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# Code taken from http://iain.nl/testing-activerecord-in-isolation
|
2
|
+
|
3
|
+
require 'active_record'
|
4
|
+
|
5
|
+
db_file = './spec/test.db'
|
6
|
+
File.delete(db_file) if File.exist?(db_file)
|
7
|
+
ActiveRecord::Base.establish_connection adapter: 'sqlite3', database: db_file
|
8
|
+
|
9
|
+
ActiveRecord::Migration.create_table :test_models do |t|
|
10
|
+
t.integer :value
|
11
|
+
t.timestamps
|
12
|
+
end
|
13
|
+
|
14
|
+
module ActiveModel::Validations
|
15
|
+
# Extension to enhance `should have` on AR Model instances. Calls
|
16
|
+
# model.valid? in order to prepare the object's errors object.
|
17
|
+
#
|
18
|
+
# You can also use this to specify the content of the error messages.
|
19
|
+
#
|
20
|
+
# @example
|
21
|
+
#
|
22
|
+
# model.should have(:no).errors_on(:attribute)
|
23
|
+
# model.should have(1).error_on(:attribute)
|
24
|
+
# model.should have(n).errors_on(:attribute)
|
25
|
+
#
|
26
|
+
# model.errors_on(:attribute).should include("can't be blank")
|
27
|
+
def errors_on(attribute)
|
28
|
+
self.valid?
|
29
|
+
[self.errors[attribute]].flatten.compact
|
30
|
+
end
|
31
|
+
alias :error_on :errors_on
|
32
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
|
3
|
+
module SimpleCov::Configuration
|
4
|
+
def clean_filters
|
5
|
+
@filters = []
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
SimpleCov.configure do
|
10
|
+
clean_filters
|
11
|
+
load_profile 'test_frameworks'
|
12
|
+
end
|
13
|
+
|
14
|
+
ENV["COVERAGE"] && SimpleCov.start do
|
15
|
+
add_filter "/.rvm/"
|
16
|
+
end
|
17
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
18
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
19
|
+
|
20
|
+
require 'rspec'
|
21
|
+
require 'sucker_punch-backgroundable'
|
22
|
+
|
23
|
+
# Requires supporting files with custom matchers and macros, etc,
|
24
|
+
# in ./support/ and its subdirectories.
|
25
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
26
|
+
|
27
|
+
RSpec.configure do |config|
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/test_class')
|
3
|
+
|
4
|
+
describe "sucker_punch-backgroundable" do
|
5
|
+
before :each do
|
6
|
+
@obj = TestClass.new
|
7
|
+
TestClass.clear
|
8
|
+
end
|
9
|
+
|
10
|
+
context 'instance methods' do
|
11
|
+
it "backgrounds instance methods declared after :always_background" do
|
12
|
+
@obj.always1
|
13
|
+
check_queue(1)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "backgrounds instance methods declared before :always_background" do
|
17
|
+
@obj.always2(100)
|
18
|
+
check_queue(100)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "allows backgrounding of instance methods not declared as :always_background" do
|
22
|
+
@obj.background.normal(200)
|
23
|
+
check_queue(200)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "allows running instance methods with a specified delay" do
|
27
|
+
@obj.later(2).normal(200) # run after 2 seconds
|
28
|
+
check_queue(200, 2.2)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "allows running instance methods with a specified delay, even when they are declared as :always_bacground" do
|
32
|
+
@obj.later(2).always1 # run after 2 seconds
|
33
|
+
check_queue(1, 2.2)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'class methods' do
|
38
|
+
it "backgrounds class methods declared after :always_background" do
|
39
|
+
TestClass.class_always1
|
40
|
+
check_queue(1)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "backgrounds class methods declared before :always_background" do
|
44
|
+
TestClass.class_always2(100)
|
45
|
+
check_queue(100)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "allows backgrounding of class methods not declared as :always_background" do
|
49
|
+
TestClass.background.class_normal(200)
|
50
|
+
check_queue(200)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "allows running class methods with a specified delay" do
|
54
|
+
TestClass.later(2).class_normal(200) # run after 2 seconds
|
55
|
+
check_queue(200, 2.2)
|
56
|
+
end
|
57
|
+
|
58
|
+
it "allows running class methods with a specified delay, even when they are declared as :always_bacground" do
|
59
|
+
TestClass.later(2).class_always1 # run after 2 seconds
|
60
|
+
check_queue(1, 2.2)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'singleton methods' do
|
65
|
+
before :each do
|
66
|
+
def @obj.my_singleton(value)
|
67
|
+
add_to_queue(value + 1)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
it "allows backgrounding of singleton methods" do
|
72
|
+
@obj.background.my_singleton(200)
|
73
|
+
check_queue(201)
|
74
|
+
end
|
75
|
+
|
76
|
+
it "allows running singleton methods with a specified delay" do
|
77
|
+
@obj.later(2).my_singleton(200) # run after 2 seconds
|
78
|
+
check_queue(201, 2.2)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def check_queue(value, wait_before = 0.2, wait_after = 0.3)
|
83
|
+
sleep( wait_before )
|
84
|
+
TestClass.queue.length.should eq(0)
|
85
|
+
sleep( wait_after )
|
86
|
+
TestClass.queue.length.should eq(1)
|
87
|
+
TestClass.queue.pop.should eq(value)
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'reloading' do
|
91
|
+
before do
|
92
|
+
require File.expand_path(File.dirname(__FILE__) + '/load_active_record')
|
93
|
+
require File.expand_path(File.dirname(__FILE__) + '/test_model')
|
94
|
+
end
|
95
|
+
|
96
|
+
before :each do
|
97
|
+
@model = TestModel.create(:value => 5)
|
98
|
+
end
|
99
|
+
|
100
|
+
after :each do
|
101
|
+
TestModel.delete_all
|
102
|
+
end
|
103
|
+
|
104
|
+
it "fully reloads objects when :reload option is true" do
|
105
|
+
@model.later(0.4, :reload => true).copy_value
|
106
|
+
@model.value += 1 # change object
|
107
|
+
sleep(0.5)
|
108
|
+
TestModel.queue.pop.should eq(5)
|
109
|
+
end
|
110
|
+
|
111
|
+
it "doesn't reload objects when :reload option is false" do
|
112
|
+
@model.later(0.4).copy_value # :reload defaults to false
|
113
|
+
@model.value += 1 # change object
|
114
|
+
sleep(0.5)
|
115
|
+
TestModel.queue.pop.should eq(6)
|
116
|
+
end
|
117
|
+
|
118
|
+
it "respects :reload => true as option to :always_background" do
|
119
|
+
@model.copy_value_in_background
|
120
|
+
@model.value += 1 # change object
|
121
|
+
sleep(0.5)
|
122
|
+
TestModel.queue.pop.should eq(5)
|
123
|
+
end
|
124
|
+
|
125
|
+
context 'global reload option' do
|
126
|
+
it "honors when global reload is set to true" do
|
127
|
+
SuckerPunch::Backgroundable.configure do |config|
|
128
|
+
config.reload = true
|
129
|
+
end
|
130
|
+
@model.later(0.4).copy_value
|
131
|
+
@model.value += 1 # change object
|
132
|
+
sleep(0.5)
|
133
|
+
TestModel.queue.pop.should eq(5)
|
134
|
+
end
|
135
|
+
|
136
|
+
it "honors :reload => false even when when global reload is set to true" do
|
137
|
+
SuckerPunch::Backgroundable.configure do |config|
|
138
|
+
config.reload = true
|
139
|
+
end
|
140
|
+
@model.later(0.4, :reload => false).copy_value
|
141
|
+
@model.value += 1 # change object
|
142
|
+
sleep(0.5)
|
143
|
+
TestModel.queue.pop.should eq(6)
|
144
|
+
end
|
145
|
+
|
146
|
+
it "ignores :reload for class methods" do
|
147
|
+
SuckerPunch::Backgroundable.configure do |config|
|
148
|
+
config.reload = true
|
149
|
+
end
|
150
|
+
TestModel.class_always
|
151
|
+
sleep(0.5)
|
152
|
+
TestModel.queue.pop.should eq(7)
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
data/spec/test_class.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
class TestClass
|
2
|
+
include SuckerPunch::Backgroundable
|
3
|
+
|
4
|
+
@@queue = Queue.new
|
5
|
+
|
6
|
+
def self.queue
|
7
|
+
@@queue
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.clear
|
11
|
+
@@queue.clear
|
12
|
+
end
|
13
|
+
|
14
|
+
always_background :always1
|
15
|
+
def always1
|
16
|
+
add_to_queue
|
17
|
+
end
|
18
|
+
|
19
|
+
def always2(value)
|
20
|
+
add_to_queue(value)
|
21
|
+
end
|
22
|
+
always_background :always2
|
23
|
+
|
24
|
+
def normal(value)
|
25
|
+
add_to_queue(value)
|
26
|
+
end
|
27
|
+
|
28
|
+
always_background :class_always1
|
29
|
+
def self.class_always1
|
30
|
+
self.class_add_to_queue
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.class_always2(value)
|
34
|
+
self.class_add_to_queue(value)
|
35
|
+
end
|
36
|
+
always_background :class_always2
|
37
|
+
|
38
|
+
def self.class_normal(value)
|
39
|
+
self.class_add_to_queue(value)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def add_to_queue(value = 1)
|
45
|
+
sleep(0.4)
|
46
|
+
@@queue << value
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.class_add_to_queue(value = 1)
|
50
|
+
sleep(0.4)
|
51
|
+
@@queue << value
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
data/spec/test_model.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
class TestModel < ActiveRecord::Base
|
2
|
+
include SuckerPunch::Backgroundable
|
3
|
+
|
4
|
+
@@queue = Queue.new
|
5
|
+
|
6
|
+
def self.queue
|
7
|
+
@@queue
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.clear
|
11
|
+
@@queue.clear
|
12
|
+
end
|
13
|
+
|
14
|
+
def copy_value
|
15
|
+
@@queue << value
|
16
|
+
end
|
17
|
+
|
18
|
+
always_background :class_always
|
19
|
+
def self.class_always
|
20
|
+
sleep(0.4)
|
21
|
+
@@queue << 7
|
22
|
+
end
|
23
|
+
|
24
|
+
always_background :copy_value_in_background, :reload => true
|
25
|
+
def copy_value_in_background
|
26
|
+
sleep(0.4)
|
27
|
+
@@queue << value
|
28
|
+
end
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,178 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sucker_punch-backgroundable
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Michaël Van Damme
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-05-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: sucker_punch
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ! '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.0.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ! '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.0.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.8.0
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 2.8.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rdoc
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.12'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.12'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: jeweler
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ~>
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 2.0.1
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ~>
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 2.0.1
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: simplecov
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ! '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ! '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: activerecord
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ! '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ! '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: sqlite3
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ! '>='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
description: This gem allows you to background any method call without having to write
|
126
|
+
a special job class. Heavily inspired by the Backgroundable module in TorqueBox.
|
127
|
+
email: michael.vandamme@vub.ac.be
|
128
|
+
executables: []
|
129
|
+
extensions: []
|
130
|
+
extra_rdoc_files:
|
131
|
+
- LICENSE.txt
|
132
|
+
- README.md
|
133
|
+
files:
|
134
|
+
- .document
|
135
|
+
- .rspec
|
136
|
+
- .travis
|
137
|
+
- CHANGELOG.md
|
138
|
+
- Gemfile
|
139
|
+
- Gemfile.lock
|
140
|
+
- LICENSE.txt
|
141
|
+
- README.md
|
142
|
+
- Rakefile
|
143
|
+
- VERSION
|
144
|
+
- lib/sucker_punch-backgroundable.rb
|
145
|
+
- lib/sucker_punch/backgroundable/backgroundable.rb
|
146
|
+
- lib/sucker_punch/backgroundable/config.rb
|
147
|
+
- lib/sucker_punch/backgroundable/job.rb
|
148
|
+
- lib/sucker_punch/backgroundable/util.rb
|
149
|
+
- spec/load_active_record.rb
|
150
|
+
- spec/spec_helper.rb
|
151
|
+
- spec/sucker_punch-backgroundable_spec.rb
|
152
|
+
- spec/test_class.rb
|
153
|
+
- spec/test_model.rb
|
154
|
+
homepage: http://github.com/mvdamme/sucker_punch-backgroundable
|
155
|
+
licenses:
|
156
|
+
- LGPL-3
|
157
|
+
metadata: {}
|
158
|
+
post_install_message:
|
159
|
+
rdoc_options: []
|
160
|
+
require_paths:
|
161
|
+
- lib
|
162
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ! '>='
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
168
|
+
requirements:
|
169
|
+
- - ! '>='
|
170
|
+
- !ruby/object:Gem::Version
|
171
|
+
version: '0'
|
172
|
+
requirements: []
|
173
|
+
rubyforge_project:
|
174
|
+
rubygems_version: 2.2.2
|
175
|
+
signing_key:
|
176
|
+
specification_version: 4
|
177
|
+
summary: Easily execute an object's methods in the background with sucker_punch
|
178
|
+
test_files: []
|