fist_of_fury 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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rspec +1 -0
- data/Gemfile +4 -0
- data/Guardfile +5 -0
- data/LICENSE.txt +22 -0
- data/README.md +79 -0
- data/Rakefile +1 -0
- data/fist_of_fury.gemspec +30 -0
- data/lib/fist_of_fury/actor/clock.rb +50 -0
- data/lib/fist_of_fury/actor/dispatcher.rb +32 -0
- data/lib/fist_of_fury/actor.rb +23 -0
- data/lib/fist_of_fury/api.rb +11 -0
- data/lib/fist_of_fury/logging.rb +9 -0
- data/lib/fist_of_fury/railtie.rb +6 -0
- data/lib/fist_of_fury/recurrent.rb +42 -0
- data/lib/fist_of_fury/schedule.rb +39 -0
- data/lib/fist_of_fury/subclass_tracking.rb +20 -0
- data/lib/fist_of_fury/supervisor.rb +30 -0
- data/lib/fist_of_fury/version.rb +3 -0
- data/lib/fist_of_fury.rb +59 -0
- data/spec/fist_of_fury_spec.rb +22 -0
- data/spec/spec_helper.rb +13 -0
- metadata +180 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: aaac55f7aa5ff55179438b0849987c260000e695
|
4
|
+
data.tar.gz: cb691189d955e8d22fe2b2a25997da15f2321c47
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: daec4f0b46b06ae89773d9c68783ce2d59c2c201fde9ea21a5d59f3d17545790c1ecc293edf0227f93f8a39dcf9c5c35a8a9643816af688910d0712e7eb6b812
|
7
|
+
data.tar.gz: 90c799dab5cae395152b2bdecd623cd200a8e93ba0c1f48fae0d021faad3a720a12bf0d010b2c2d60bb095aa1dbcd95ccfb101af4e312ec261dd578345408e75
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Joshua Rieken
|
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,79 @@
|
|
1
|
+
# Fist of Fury
|
2
|
+
|
3
|
+
Recurring jobs for [Sucker Punch](https://github.com/brandonhilkert/sucker_punch).
|
4
|
+
|
5
|
+
**This is alpha software. Use at your own risk!**
|
6
|
+
|
7
|
+
## Why
|
8
|
+
|
9
|
+
Sucker Punch offers the capability to run background jobs within the web server process, allowing for less use of resources and utilization of free hosting on services such as Heroku. However, it does not include the ability to run jobs at scheduled intervals. This is where Fist of Fury comes in.
|
10
|
+
|
11
|
+
## What
|
12
|
+
|
13
|
+
Fist of Fury is heavily inspired by [Sidetiq](https://github.com/tobiassvn/sidetiq) for [Sidekiq](https://github.com/mperham/sidekiq). It uses the [ice_cube](https://github.com/seejohnrun/ice_cube) gem for easy creation of recurrence rules.
|
14
|
+
|
15
|
+
## Installation
|
16
|
+
|
17
|
+
Add this line to your application's Gemfile:
|
18
|
+
|
19
|
+
gem 'fist_of_fury', '~> 0.1'
|
20
|
+
|
21
|
+
And then execute:
|
22
|
+
|
23
|
+
$ bundle
|
24
|
+
|
25
|
+
Or install it yourself as:
|
26
|
+
|
27
|
+
$ gem install fist_of_fury
|
28
|
+
|
29
|
+
## Usage
|
30
|
+
|
31
|
+
You can schedule your jobs within the jobs themselves:
|
32
|
+
|
33
|
+
```Ruby
|
34
|
+
# app/jobs/say_hi_job.rb
|
35
|
+
|
36
|
+
class SayHiJob
|
37
|
+
include SuckerPunch::Job
|
38
|
+
include FistOfFury::Recurrent
|
39
|
+
|
40
|
+
recurs { minutely }
|
41
|
+
|
42
|
+
def perform
|
43
|
+
Rails.logger.info 'Hi!'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
```
|
47
|
+
|
48
|
+
Then in the initializer:
|
49
|
+
|
50
|
+
```Ruby
|
51
|
+
# config/initializers/fist_of_fury.rb
|
52
|
+
|
53
|
+
# Ensures the jobs don't run while in the Rails console.
|
54
|
+
unless defined?(Rails::Console)
|
55
|
+
FistOfFury.attack!
|
56
|
+
end
|
57
|
+
```
|
58
|
+
|
59
|
+
Or you can even specify the recurrence rules all within the initializer:
|
60
|
+
|
61
|
+
```Ruby
|
62
|
+
# config/initializers/fist_of_fury.rb
|
63
|
+
|
64
|
+
# Ensures the jobs don't run while in the Rails console.
|
65
|
+
unless defined?(Rails::Console)
|
66
|
+
FistOfFury.attack! do
|
67
|
+
LogJob.recurs { secondly(3) }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
```
|
71
|
+
|
72
|
+
|
73
|
+
## Contributing
|
74
|
+
|
75
|
+
1. Fork it ( http://github.com/<my-github-username>/fist_of_fury/fork )
|
76
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
77
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
78
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
79
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'fist_of_fury/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = 'fist_of_fury'
|
8
|
+
gem.version = FistOfFury::VERSION
|
9
|
+
gem.authors = ['Joshua Rieken']
|
10
|
+
gem.email = ['joshua@joshuarieken.com']
|
11
|
+
gem.description = %q{Recurring jobs for Sucker Punch}
|
12
|
+
gem.summary = gem.description
|
13
|
+
gem.homepage = 'https://github.com/facto/fist_of_fury'
|
14
|
+
gem.license = 'MIT'
|
15
|
+
|
16
|
+
gem.files = `git ls-files -z`.split("\x0")
|
17
|
+
gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
19
|
+
gem.require_paths = ['lib']
|
20
|
+
|
21
|
+
gem.add_development_dependency 'pry'
|
22
|
+
gem.add_development_dependency 'rake'
|
23
|
+
gem.add_development_dependency 'rspec'
|
24
|
+
gem.add_development_dependency 'guard'
|
25
|
+
gem.add_development_dependency 'guard-rspec'
|
26
|
+
|
27
|
+
gem.add_dependency 'sucker_punch', '>= 1.0.2'
|
28
|
+
gem.add_dependency 'celluloid', '>= 0.15.2'
|
29
|
+
gem.add_dependency 'ice_cube', '~> 0.11.3'
|
30
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module FistOfFury
|
2
|
+
module Actor
|
3
|
+
class Clock
|
4
|
+
include Logging
|
5
|
+
include FistOfFury::Actor
|
6
|
+
|
7
|
+
attr_reader :schedules
|
8
|
+
|
9
|
+
def initialize(*args, &block)
|
10
|
+
after(0) do
|
11
|
+
debug 'FistOfFury::Clock looping...'
|
12
|
+
loop!
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def schedule_for(worker)
|
17
|
+
worker.schedule if worker.respond_to? :schedule
|
18
|
+
end
|
19
|
+
|
20
|
+
def tick(tick = current_time)
|
21
|
+
FistOfFury.workers.each do |worker|
|
22
|
+
FistOfFury.dispatcher.dispatch(worker, tick)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def current_time
|
27
|
+
# TODO: configurable time zone support
|
28
|
+
Time.now
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def loop!
|
34
|
+
after([time { tick }, 0].max) do
|
35
|
+
loop!
|
36
|
+
end
|
37
|
+
rescue StandardError => e
|
38
|
+
# TODO: global exception handling support
|
39
|
+
# handle_exception(e, context: 'FistOfFury::Clock#loop!')
|
40
|
+
raise e
|
41
|
+
end
|
42
|
+
|
43
|
+
def time
|
44
|
+
start = current_time
|
45
|
+
yield
|
46
|
+
1 - (current_time.to_f - start.to_f)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module FistOfFury
|
2
|
+
module Actor
|
3
|
+
class Dispatcher
|
4
|
+
include Logging
|
5
|
+
include FistOfFury::Actor
|
6
|
+
|
7
|
+
def dispatch(worker, tick)
|
8
|
+
schedule = worker.schedule
|
9
|
+
return unless schedule.schedule_next?(tick)
|
10
|
+
enqueue(worker, schedule.next_occurrence(tick))
|
11
|
+
rescue StandardError => e
|
12
|
+
# TODO: exception handling support
|
13
|
+
raise e
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def enqueue(worker, next_run_time)
|
19
|
+
klass = worker.to_s
|
20
|
+
info "Enqueue: #{klass}"
|
21
|
+
last_run_time = FistOfFury.store["#{klass}:next"] || -1
|
22
|
+
next_run_time = next_run_time.to_f
|
23
|
+
FistOfFury.store["#{klass}:last"] = last_run_time
|
24
|
+
FistOfFury.store["#{klass}:next"] = next_run_time
|
25
|
+
worker.new.async.perform
|
26
|
+
rescue StandardError => e
|
27
|
+
# TODO: exception handling support
|
28
|
+
raise e
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module FistOfFury
|
2
|
+
module Actor
|
3
|
+
def self.included(base)
|
4
|
+
base.__send__(:include, Celluloid)
|
5
|
+
base.finalizer :fist_of_fury_finalizer
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(*args, &block)
|
9
|
+
log_call 'initialize'
|
10
|
+
super
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def fist_of_fury_finalizer
|
16
|
+
log_call 'shutting down ...'
|
17
|
+
end
|
18
|
+
|
19
|
+
def log_call(call)
|
20
|
+
info "#{self.class.name} id: #{object_id} #{call}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module FistOfFury
|
2
|
+
module Recurrent
|
3
|
+
extend SubclassTracking
|
4
|
+
|
5
|
+
module ClassMethods
|
6
|
+
include SubclassTracking
|
7
|
+
|
8
|
+
attr_writer :schedule
|
9
|
+
|
10
|
+
def schedule
|
11
|
+
@schedule ||= FistOfFury::Schedule.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def last_scheduled_occurrence
|
15
|
+
scheduled_occurrence 'last'
|
16
|
+
end
|
17
|
+
|
18
|
+
def next_scheduled_occurrence
|
19
|
+
scheduled_occurrence 'next'
|
20
|
+
end
|
21
|
+
|
22
|
+
def recurs(options={}, &block)
|
23
|
+
schedule.instance_eval(&block)
|
24
|
+
schedule.options = options
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def scheduled_occurrence(key)
|
30
|
+
(FistOfFury.store["#{self.class.to_s}:#{key}"] || -1).to_f
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.included(klass)
|
35
|
+
super
|
36
|
+
|
37
|
+
klass.extend(FistOfFury::Recurrent::ClassMethods)
|
38
|
+
klass.extend(FistOfFury::SubclassTracking)
|
39
|
+
subclasses << klass
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module FistOfFury
|
2
|
+
class Schedule
|
3
|
+
attr_accessor :options
|
4
|
+
attr_reader :last_occurrence
|
5
|
+
|
6
|
+
# TODO: configurable timezone support
|
7
|
+
START_TIME = Time.local(2010, 1, 1)
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@schedule = IceCube::Schedule.new(START_TIME)
|
11
|
+
end
|
12
|
+
|
13
|
+
def method_missing(meth, *args, &block)
|
14
|
+
if IceCube::Rule.respond_to?(meth)
|
15
|
+
rule = IceCube::Rule.send(meth, *args, &block)
|
16
|
+
@schedule.add_recurrence_rule(rule)
|
17
|
+
rule
|
18
|
+
elsif @schedule.respond_to?(meth)
|
19
|
+
@schedule.send(meth, *args, &block)
|
20
|
+
else
|
21
|
+
super
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def schedule_next?(time)
|
26
|
+
next_occurrence = @schedule.next_occurrence(time)
|
27
|
+
if @last_scheduled != next_occurrence
|
28
|
+
@last_scheduled = next_occurrence
|
29
|
+
true
|
30
|
+
else
|
31
|
+
false
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_s
|
36
|
+
@schedule.to_s
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module FistOfFury
|
2
|
+
module SubclassTracking
|
3
|
+
def subclasses(deep = false)
|
4
|
+
@subclasses ||= []
|
5
|
+
|
6
|
+
if deep
|
7
|
+
@subclasses.inject([]) do |result, subclass|
|
8
|
+
(result << subclass) + subclass.subclasses(true)
|
9
|
+
end
|
10
|
+
else
|
11
|
+
@subclasses
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def inherited(klass)
|
16
|
+
super
|
17
|
+
subclasses << klass
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module FistOfFury
|
2
|
+
class Supervisor < Celluloid::SupervisionGroup
|
3
|
+
supervise FistOfFury::Actor::Clock, as: :fist_of_fury_clock
|
4
|
+
# TODO: configurable pool size. For now, use Celluloid's CPU-based default.
|
5
|
+
pool FistOfFury::Actor::Dispatcher, as: :fist_of_fury_dispatcher
|
6
|
+
|
7
|
+
class << self
|
8
|
+
include Logging
|
9
|
+
|
10
|
+
def clock
|
11
|
+
run! if Celluloid::Actor[:fist_of_fury_clock].nil?
|
12
|
+
Celluloid::Actor[:fist_of_fury_clock]
|
13
|
+
end
|
14
|
+
|
15
|
+
def dispatcher
|
16
|
+
run! if Celluloid::Actor[:fist_of_fury_dispatcher].nil?
|
17
|
+
Celluloid::Actor[:fist_of_fury_dispatcher]
|
18
|
+
end
|
19
|
+
|
20
|
+
def run!
|
21
|
+
info 'FistOfFury::Supervisor start'
|
22
|
+
super
|
23
|
+
end
|
24
|
+
|
25
|
+
def run
|
26
|
+
raise "FistOfFury::Supervisor should not be run in the foreground."
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/fist_of_fury.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# stdlib
|
2
|
+
require 'ostruct'
|
3
|
+
require 'singleton'
|
4
|
+
require 'socket'
|
5
|
+
require 'time'
|
6
|
+
|
7
|
+
# gems
|
8
|
+
require 'ice_cube'
|
9
|
+
require 'sucker_punch'
|
10
|
+
require 'celluloid'
|
11
|
+
|
12
|
+
# internal
|
13
|
+
require 'fist_of_fury/subclass_tracking'
|
14
|
+
require 'fist_of_fury/api'
|
15
|
+
require 'fist_of_fury/logging'
|
16
|
+
require 'fist_of_fury/schedule'
|
17
|
+
require 'fist_of_fury/recurrent'
|
18
|
+
require 'fist_of_fury/version'
|
19
|
+
|
20
|
+
# actor topology
|
21
|
+
require 'fist_of_fury/actor'
|
22
|
+
require 'fist_of_fury/actor/clock'
|
23
|
+
require 'fist_of_fury/actor/dispatcher'
|
24
|
+
require 'fist_of_fury/supervisor'
|
25
|
+
|
26
|
+
module FistOfFury
|
27
|
+
include FistOfFury::API
|
28
|
+
|
29
|
+
extend self
|
30
|
+
|
31
|
+
class << self
|
32
|
+
attr_writer :logger
|
33
|
+
end
|
34
|
+
|
35
|
+
def logger
|
36
|
+
@logger ||= SuckerPunch.logger
|
37
|
+
end
|
38
|
+
|
39
|
+
def clock
|
40
|
+
FistOfFury::Supervisor.clock
|
41
|
+
end
|
42
|
+
|
43
|
+
def dispatcher
|
44
|
+
FistOfFury::Supervisor.dispatcher
|
45
|
+
end
|
46
|
+
|
47
|
+
def store
|
48
|
+
@store ||= {}
|
49
|
+
end
|
50
|
+
|
51
|
+
def attack!
|
52
|
+
return true if @attacking
|
53
|
+
yield if block_given?
|
54
|
+
FistOfFury::Supervisor.run!
|
55
|
+
@attacking = true
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
require 'fist_of_fury/railtie' if defined?(::Rails)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe FistOfFury do
|
4
|
+
describe 'logger' do
|
5
|
+
it "delegates get to Sucker Punch's logger" do
|
6
|
+
expect(FistOfFury.logger).to eq SuckerPunch.logger
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
describe 'clock' do
|
11
|
+
it "delegates get to FistOfFury::Supervisor's clock" do
|
12
|
+
expect(FistOfFury::Supervisor).to receive(:clock)
|
13
|
+
FistOfFury.clock
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'store' do
|
18
|
+
it 'starts out as an empty hash' do
|
19
|
+
expect(FistOfFury.store).to eq Hash.new
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fist_of_fury
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Joshua Rieken
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-03-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: pry
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: guard
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: guard-rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: sucker_punch
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 1.0.2
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 1.0.2
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: celluloid
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 0.15.2
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 0.15.2
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: ice_cube
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 0.11.3
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 0.11.3
|
125
|
+
description: Recurring jobs for Sucker Punch
|
126
|
+
email:
|
127
|
+
- joshua@joshuarieken.com
|
128
|
+
executables: []
|
129
|
+
extensions: []
|
130
|
+
extra_rdoc_files: []
|
131
|
+
files:
|
132
|
+
- ".gitignore"
|
133
|
+
- ".rspec"
|
134
|
+
- Gemfile
|
135
|
+
- Guardfile
|
136
|
+
- LICENSE.txt
|
137
|
+
- README.md
|
138
|
+
- Rakefile
|
139
|
+
- fist_of_fury.gemspec
|
140
|
+
- lib/fist_of_fury.rb
|
141
|
+
- lib/fist_of_fury/actor.rb
|
142
|
+
- lib/fist_of_fury/actor/clock.rb
|
143
|
+
- lib/fist_of_fury/actor/dispatcher.rb
|
144
|
+
- lib/fist_of_fury/api.rb
|
145
|
+
- lib/fist_of_fury/logging.rb
|
146
|
+
- lib/fist_of_fury/railtie.rb
|
147
|
+
- lib/fist_of_fury/recurrent.rb
|
148
|
+
- lib/fist_of_fury/schedule.rb
|
149
|
+
- lib/fist_of_fury/subclass_tracking.rb
|
150
|
+
- lib/fist_of_fury/supervisor.rb
|
151
|
+
- lib/fist_of_fury/version.rb
|
152
|
+
- spec/fist_of_fury_spec.rb
|
153
|
+
- spec/spec_helper.rb
|
154
|
+
homepage: https://github.com/facto/fist_of_fury
|
155
|
+
licenses:
|
156
|
+
- MIT
|
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: Recurring jobs for Sucker Punch
|
178
|
+
test_files:
|
179
|
+
- spec/fist_of_fury_spec.rb
|
180
|
+
- spec/spec_helper.rb
|