fist_of_fury 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: aaac55f7aa5ff55179438b0849987c260000e695
4
- data.tar.gz: cb691189d955e8d22fe2b2a25997da15f2321c47
3
+ metadata.gz: 30fd5d339ee339c1294b986583f7a0abed1cb08a
4
+ data.tar.gz: 593d60d97908fa37af0f13192fc68487950d8a71
5
5
  SHA512:
6
- metadata.gz: daec4f0b46b06ae89773d9c68783ce2d59c2c201fde9ea21a5d59f3d17545790c1ecc293edf0227f93f8a39dcf9c5c35a8a9643816af688910d0712e7eb6b812
7
- data.tar.gz: 90c799dab5cae395152b2bdecd623cd200a8e93ba0c1f48fae0d021faad3a720a12bf0d010b2c2d60bb095aa1dbcd95ccfb101af4e312ec261dd578345408e75
6
+ metadata.gz: 01928d25ec21fece7ac05657327f503ac07f287067b0bf979823241bce3e2a324e9124401343e9cff4668cd18187c620e33f96587284e67318d9094a5aec67a0
7
+ data.tar.gz: f2697fdaf69a3f99e0b14a70f365f10a3cb8588d80b8c4b327d4bb4d1a0775d7ecaaafc98290331737e02611f6ef66005e85356e3067f01115bb5e26ad173534
data/.travis.yml ADDED
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - jruby-19mode
5
+ - rbx
6
+ - 2.0.0
7
+ - 2.1.0
8
+ matrix:
9
+ allow_failures:
10
+ - rvm: jruby-19mode
11
+ - rvm: rbx
data/README.md CHANGED
@@ -1,12 +1,16 @@
1
1
  # Fist of Fury
2
2
 
3
- Recurring jobs for [Sucker Punch](https://github.com/brandonhilkert/sucker_punch).
3
+ [![Build Status](https://travis-ci.org/facto/fist_of_fury.png?branch=master)](https://travis-ci.org/facto/fist_of_fury)
4
+ [![Dependency Status](https://gemnasium.com/facto/fist_of_fury.svg)](https://gemnasium.com/facto/fist_of_fury)
5
+ [![Coverage Status](https://coveralls.io/repos/facto/fist_of_fury/badge.png)](https://coveralls.io/r/facto/fist_of_fury)
6
+ [![Code Climate](https://codeclimate.com/github/facto/fist_of_fury.png)](https://codeclimate.com/github/facto/fist_of_fury)
7
+ [![Gem Version](https://badge.fury.io/rb/fist_of_fury.png)](http://badge.fury.io/rb/fist_of_fury)
4
8
 
5
- **This is alpha software. Use at your own risk!**
9
+ Recurring jobs for [Sucker Punch](https://github.com/brandonhilkert/sucker_punch).
6
10
 
7
11
  ## Why
8
12
 
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.
13
+ Sucker Punch offers the ability to run background jobs *within the web server process*. Yes, this means you can host your app on Heroku without paying for an extra dyno for background jobs. However, Sucker Punch does not implement recurring jobs. Enter Fist of Fury!
10
14
 
11
15
  ## What
12
16
 
@@ -16,7 +20,7 @@ Fist of Fury is heavily inspired by [Sidetiq](https://github.com/tobiassvn/sidet
16
20
 
17
21
  Add this line to your application's Gemfile:
18
22
 
19
- gem 'fist_of_fury', '~> 0.1'
23
+ gem 'fist_of_fury', '~> 0.1.0'
20
24
 
21
25
  And then execute:
22
26
 
@@ -69,10 +73,19 @@ unless defined?(Rails::Console)
69
73
  end
70
74
  ```
71
75
 
76
+ ## Configuration Options
77
+
78
+ In the initializer:
79
+
80
+ ```Ruby
81
+ FistOfFury.configure do |config|
82
+ config.utc = true # false by default; makes all time within Fist of Fury UTC
83
+ end
84
+ ```
72
85
 
73
86
  ## Contributing
74
87
 
75
- 1. Fork it ( http://github.com/<my-github-username>/fist_of_fury/fork )
88
+ 1. Fork it ( http://github.com/facto/fist_of_fury/fork )
76
89
  2. Create your feature branch (`git checkout -b my-new-feature`)
77
90
  3. Commit your changes (`git commit -am 'Add some feature'`)
78
91
  4. Push to the branch (`git push origin my-new-feature`)
data/Rakefile CHANGED
@@ -1 +1,12 @@
1
1
  require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new('spec')
5
+
6
+ # If you want to make this the default task
7
+ task :default => :spec
8
+ task :test => :spec
9
+
10
+ task :console do
11
+ exec "irb -r fist_of_fury -I ./lib"
12
+ end
data/fist_of_fury.gemspec CHANGED
@@ -23,6 +23,11 @@ Gem::Specification.new do |gem|
23
23
  gem.add_development_dependency 'rspec'
24
24
  gem.add_development_dependency 'guard'
25
25
  gem.add_development_dependency 'guard-rspec'
26
+ gem.add_development_dependency 'ruby_gntp'
27
+
28
+ if RUBY_PLATFORM != "java"
29
+ gem.add_development_dependency 'coveralls'
30
+ end
26
31
 
27
32
  gem.add_dependency 'sucker_punch', '>= 1.0.2'
28
33
  gem.add_dependency 'celluloid', '>= 0.15.2'
@@ -1,33 +1,15 @@
1
1
  module FistOfFury
2
2
  module Actor
3
- class Clock
4
- include Logging
3
+ class Clock < FistOfFury::Clock
5
4
  include FistOfFury::Actor
6
5
 
7
- attr_reader :schedules
8
-
9
6
  def initialize(*args, &block)
10
7
  after(0) do
11
- debug 'FistOfFury::Clock looping...'
8
+ debug 'FistOfFury::Clock starting loop...'
12
9
  loop!
13
10
  end
14
11
  end
15
12
 
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
13
  private
32
14
 
33
15
  def loop!
@@ -39,12 +21,6 @@ module FistOfFury
39
21
  # handle_exception(e, context: 'FistOfFury::Clock#loop!')
40
22
  raise e
41
23
  end
42
-
43
- def time
44
- start = current_time
45
- yield
46
- 1 - (current_time.to_f - start.to_f)
47
- end
48
24
  end
49
25
  end
50
26
  end
@@ -1,32 +1,7 @@
1
1
  module FistOfFury
2
2
  module Actor
3
- class Dispatcher
4
- include Logging
3
+ class Dispatcher < FistOfFury::Dispatcher
5
4
  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
5
  end
31
6
  end
32
7
  end
@@ -0,0 +1,29 @@
1
+ module FistOfFury
2
+ class Clock
3
+ include Logging
4
+
5
+ attr_reader :schedules
6
+
7
+ def schedule_for(worker)
8
+ worker.schedule if worker.respond_to? :schedule
9
+ end
10
+
11
+ def current_time
12
+ FistOfFury.config.utc ? Time.now.utc : Time.now
13
+ end
14
+
15
+ protected
16
+
17
+ def time
18
+ start = current_time
19
+ yield
20
+ 1 - (current_time.to_f - start.to_f)
21
+ end
22
+
23
+ def tick(time = current_time)
24
+ FistOfFury.workers.each do |worker|
25
+ FistOfFury.dispatcher.dispatch(worker, time)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,20 @@
1
+ module FistOfFury
2
+ class << self
3
+ attr_writer :config
4
+
5
+ def configure
6
+ yield config
7
+ end
8
+
9
+ def configure_with_defaults
10
+ config.utc = false
11
+ yield config if block_given?
12
+ end
13
+
14
+ def config
15
+ @config ||= OpenStruct.new
16
+ end
17
+ end
18
+
19
+ configure_with_defaults
20
+ end
@@ -0,0 +1,29 @@
1
+ module FistOfFury
2
+ class Dispatcher
3
+ include Logging
4
+
5
+ def dispatch(worker, time)
6
+ worker.schedule_next(time) do
7
+ enqueue(worker, worker.next_occurrence(time))
8
+ end
9
+ rescue StandardError => e
10
+ # TODO: exception handling support
11
+ raise e
12
+ end
13
+
14
+ protected
15
+
16
+ def enqueue(worker, next_run_time)
17
+ klass = worker.to_s
18
+ info "Enqueue: #{klass}"
19
+ last_run_time = FistOfFury.store["#{klass}:next"] || -1
20
+ next_run_time = next_run_time.to_f
21
+ FistOfFury.store["#{klass}:last"] = last_run_time
22
+ FistOfFury.store["#{klass}:next"] = next_run_time
23
+ worker.new.async.perform
24
+ rescue StandardError => e
25
+ # TODO: exception handling support
26
+ raise e
27
+ end
28
+ end
29
+ end
@@ -24,6 +24,10 @@ module FistOfFury
24
24
  schedule.options = options
25
25
  end
26
26
 
27
+ def schedule_next(time, &block)
28
+ schedule.schedule_next(time, &block)
29
+ end
30
+
27
31
  private
28
32
 
29
33
  def scheduled_occurrence(key)
@@ -1,39 +1,45 @@
1
1
  module FistOfFury
2
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)
3
+ attr_accessor :options, :ice_cube_schedule, :last_occurrence
8
4
 
9
5
  def initialize
10
- @schedule = IceCube::Schedule.new(START_TIME)
6
+ self.ice_cube_schedule = IceCube::Schedule.new(start_time)
11
7
  end
12
8
 
13
9
  def method_missing(meth, *args, &block)
14
10
  if IceCube::Rule.respond_to?(meth)
15
11
  rule = IceCube::Rule.send(meth, *args, &block)
16
- @schedule.add_recurrence_rule(rule)
12
+ ice_cube_schedule.add_recurrence_rule(rule)
17
13
  rule
18
- elsif @schedule.respond_to?(meth)
19
- @schedule.send(meth, *args, &block)
14
+ elsif ice_cube_schedule.respond_to?(meth)
15
+ ice_cube_schedule.send(meth, *args, &block)
20
16
  else
21
17
  super
22
18
  end
23
19
  end
24
20
 
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
21
+ def schedule_next(time)
22
+ return unless schedule_next?(time)
23
+ yield
24
+ self.last_occurrence = next_occurrence(time)
33
25
  end
34
26
 
35
27
  def to_s
36
- @schedule.to_s
28
+ ice_cube_schedule.to_s
29
+ end
30
+
31
+ def start_time
32
+ @start_time ||= FistOfFury.config.utc ? Time.utc(2010, 1, 1) : Time.local(2010, 1, 1)
33
+ end
34
+
35
+ private
36
+
37
+ def next_occurrence(time)
38
+ ice_cube_schedule.next_occurrence(time)
39
+ end
40
+
41
+ def schedule_next?(time)
42
+ last_occurrence != next_occurrence(time)
37
43
  end
38
44
  end
39
45
  end
@@ -21,10 +21,6 @@ module FistOfFury
21
21
  info 'FistOfFury::Supervisor start'
22
22
  super
23
23
  end
24
-
25
- def run
26
- raise "FistOfFury::Supervisor should not be run in the foreground."
27
- end
28
24
  end
29
25
  end
30
26
  end
@@ -1,3 +1,3 @@
1
1
  module FistOfFury
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
data/lib/fist_of_fury.rb CHANGED
@@ -10,10 +10,13 @@ require 'sucker_punch'
10
10
  require 'celluloid'
11
11
 
12
12
  # internal
13
+ require 'fist_of_fury/config'
13
14
  require 'fist_of_fury/subclass_tracking'
14
15
  require 'fist_of_fury/api'
15
16
  require 'fist_of_fury/logging'
16
17
  require 'fist_of_fury/schedule'
18
+ require 'fist_of_fury/clock'
19
+ require 'fist_of_fury/dispatcher'
17
20
  require 'fist_of_fury/recurrent'
18
21
  require 'fist_of_fury/version'
19
22
 
@@ -49,10 +52,8 @@ module FistOfFury
49
52
  end
50
53
 
51
54
  def attack!
52
- return true if @attacking
53
55
  yield if block_given?
54
56
  FistOfFury::Supervisor.run!
55
- @attacking = true
56
57
  end
57
58
  end
58
59
 
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ shared_examples_for 'an actor' do
4
+ it 'mixes in Celluloid' do
5
+ expect(subject).to respond_to(:after)
6
+ end
7
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+ require 'fist_of_fury/actor_sharedspec'
3
+ require 'fist_of_fury/clock_sharedspec'
4
+
5
+ describe FistOfFury::Actor::Clock do
6
+ it_should_behave_like 'an actor'
7
+ it_should_behave_like 'a clock'
8
+
9
+ let(:clock) { subject }
10
+
11
+ before :each do
12
+ expect_any_instance_of(described_class).to receive(:after)
13
+ end
14
+
15
+ describe '#initialize' do
16
+ it 'makes a deferred call' do
17
+ clock
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+ require 'fist_of_fury/actor_sharedspec'
3
+ require 'fist_of_fury/dispatcher_sharedspec'
4
+
5
+ describe FistOfFury::Actor::Dispatcher do
6
+ it_should_behave_like 'an actor'
7
+ it_should_behave_like 'a dispatcher'
8
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ shared_examples_for 'the api' do
4
+ describe '#workers' do
5
+ it 'returns the deep subclass list from Recurrent' do
6
+ expect(FistOfFury::Recurrent).to receive(:subclasses).with(true)
7
+ subject.workers
8
+ end
9
+ end
10
+
11
+ describe '#schedules' do
12
+ it 'returns the worker schedules' do
13
+ worker_list = double('worker_list')
14
+ expect(worker_list).to receive(:map)
15
+ allow_any_instance_of(described_class).to receive(:workers).and_return(worker_list)
16
+ subject.schedules
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+ require 'fist_of_fury/logging_sharedspec'
3
+
4
+ shared_examples_for 'a clock' do
5
+ it_should_behave_like 'a logger'
6
+
7
+ describe '#schedule_for' do
8
+ it "delegates to the worker's schedule" do
9
+ worker = double('worker')
10
+ worker.stub(:schedule)
11
+ expect(worker).to receive(:schedule)
12
+ subject.schedule_for(worker)
13
+ end
14
+ end
15
+
16
+ describe '#current_time' do
17
+ context 'when UTC is enabled' do
18
+ before :each do
19
+ FistOfFury.configure { |config| config.utc = true }
20
+ end
21
+
22
+ it 'returns the current time in UTC' do
23
+ now = double('now')
24
+ utc = double('utc')
25
+ now.stub(:utc).and_return(utc)
26
+ Time.stub(:now).and_return(now)
27
+ expect(subject.current_time).to eq utc
28
+ end
29
+ end
30
+
31
+ context 'when UTC is not enabled' do
32
+ before :each do
33
+ FistOfFury.configure { |config| config.utc = false }
34
+ end
35
+
36
+ it 'returns the current time in the default time zone' do
37
+ now = double('now')
38
+ Time.stub(:now).and_return(now)
39
+ expect(subject.current_time).to eq now
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ describe FistOfFury do
4
+ describe 'config' do
5
+ describe '#configure' do
6
+ let(:config) { OpenStruct.new }
7
+
8
+ before :each do
9
+ described_class.config = config
10
+ end
11
+
12
+ it 'calls the block and yields the config ' do
13
+ block_called = false
14
+ described_class.configure do |config|
15
+ expect(config).to eq(config)
16
+ block_called = true
17
+ end
18
+ expect(block_called).to be_true
19
+ end
20
+ end
21
+
22
+ describe '#configure_with_defaults' do
23
+ let(:config) { OpenStruct.new }
24
+
25
+ before :each do
26
+ described_class.config = config
27
+ end
28
+
29
+ it 'calls the block and yields the config ' do
30
+ block_called = false
31
+ described_class.configure_with_defaults do |config|
32
+ expect(config).to eq(config)
33
+ block_called = true
34
+ end
35
+ expect(block_called).to be_true
36
+ end
37
+ end
38
+
39
+ describe '#config' do
40
+ it 'has some default values' do
41
+ expect(described_class.config).to eq OpenStruct.new(
42
+ utc: false
43
+ )
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+ require 'fist_of_fury/logging_sharedspec'
3
+
4
+ shared_examples_for 'a dispatcher' do
5
+ it_should_behave_like 'a logger'
6
+
7
+ describe '#dispatch' do
8
+
9
+ let(:time) { double('time') }
10
+
11
+ let(:worker) { double('worker') }
12
+
13
+ it 'delegates scheduling to the worker' do
14
+ expect(worker).to receive(:schedule_next) do |*args, &block|
15
+ expect(args).to include(time)
16
+ expect(block).to_not be_nil
17
+ end
18
+ subject.dispatch(worker, time)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec_helper'
2
+ require 'fist_of_fury/recurrent_sharedspec'
3
+
4
+ describe AwesomeJob do
5
+ it_should_behave_like 'a job with recurrence'
6
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ shared_examples_for 'a logger' do
4
+ [:fatal, :error, :warn, :info, :debug].each do |level|
5
+ it "responds to :#{level}" do
6
+ expect(subject).to respond_to(level)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ module ::Rails
4
+ class Railtie
5
+ def self.initializer(name)
6
+ end
7
+ end
8
+ end
9
+
10
+ require_relative '../../lib/fist_of_fury/railtie'
11
+
12
+ describe FistOfFury::Railtie do
13
+ after :all do
14
+ Object.send(:remove_const, :Rails)
15
+ end
16
+
17
+ it 'derives from ::Rails::Railtie' do
18
+ expect(described_class.ancestors).to include(::Rails::Railtie)
19
+ end
20
+ end
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+ require 'fist_of_fury/subclass_tracking_sharedspec'
3
+
4
+ shared_examples_for 'a job with recurrence' do
5
+ it_should_behave_like 'a class that tracks its subclasses'
6
+
7
+ after :each do
8
+ Celluloid::Actor.clear_registry
9
+ end
10
+
11
+ describe '::schedule' do
12
+ it 'returns a new schedule' do
13
+ schedule = double('schedule')
14
+ FistOfFury::Schedule.stub(:new).and_return(schedule)
15
+ expect(described_class.schedule).to eq schedule
16
+ end
17
+ end
18
+
19
+ describe '::last_scheduled_occurrence' do
20
+ it 'calls scheduled_occurrence with the right arguments' do
21
+ expect(described_class).to receive(:scheduled_occurrence).with('last')
22
+ described_class.last_scheduled_occurrence
23
+ end
24
+ end
25
+
26
+ describe '::next_scheduled_occurrence' do
27
+ it 'calls scheduled_occurrence with the right arguments' do
28
+ expect(described_class).to receive(:scheduled_occurrence).with('next')
29
+ described_class.next_scheduled_occurrence
30
+ end
31
+ end
32
+
33
+ describe '::recurs' do
34
+ it 'evaluate the block within the context of the schedule and sets the options' do
35
+ block = lambda {}
36
+ schedule = double('schedule')
37
+ options = double('optionss')
38
+ described_class.schedule = schedule
39
+ expect(schedule).to receive(:instance_eval)
40
+ expect(schedule).to receive(:options=).with(options)
41
+ described_class.recurs(options, &block)
42
+ end
43
+ end
44
+
45
+ describe '::schedule_next' do
46
+ let(:block) { lambda {} }
47
+ let(:time) { double('time') }
48
+ let(:schedule) { double('schedule') }
49
+
50
+ it 'delegates to the schedule' do
51
+ described_class.schedule = schedule
52
+ expect(schedule).to receive(:schedule_next).with(time)
53
+ described_class.schedule_next(time, &block)
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,89 @@
1
+ require 'spec_helper'
2
+
3
+ describe FistOfFury::Schedule do
4
+ let(:schedule) { subject }
5
+
6
+ describe '#initialize' do
7
+ it 'creates an IceCube schedule' do
8
+ ice_cube_schedule = double('ice_cube_schedule')
9
+ start_time = double('start_time')
10
+ allow_any_instance_of(described_class).to receive(:start_time).and_return(start_time)
11
+ allow(IceCube::Schedule).to receive(:new).with(start_time).and_return(ice_cube_schedule)
12
+ expect_any_instance_of(described_class).to receive(:ice_cube_schedule=).with(ice_cube_schedule)
13
+ schedule
14
+ end
15
+ end
16
+
17
+ describe '#schedule_next' do
18
+ let(:time) { double('time') }
19
+ let(:block) { lambda {} }
20
+ let(:next_occurrence) { double('next_occurrence') }
21
+
22
+ before :each do
23
+ allow(schedule).to receive(:next_occurrence).and_return(next_occurrence)
24
+ end
25
+
26
+ context 'when it should be scheduled' do
27
+ before :each do
28
+ allow(schedule).to receive(:schedule_next?).and_return(true)
29
+ end
30
+
31
+ it 'calls the block' do
32
+ block_called = false
33
+ schedule.schedule_next(time) { block_called = true }
34
+ expect(block_called).to be_true
35
+ end
36
+
37
+ it 'sets the last occurrence' do
38
+ expect(schedule).to receive(:last_occurrence=).with(next_occurrence)
39
+ schedule.schedule_next(time, &block)
40
+ end
41
+ end
42
+
43
+ context 'when it should not be scheduled' do
44
+ before :each do
45
+ allow(schedule).to receive(:schedule_next?).and_return(false)
46
+ end
47
+
48
+ it 'does not call the block' do
49
+ block_called = false
50
+ schedule.schedule_next(time) { block_called = true }
51
+ expect(block_called).to be_false
52
+ end
53
+
54
+ it 'does not set the last occurrence' do
55
+ expect(schedule).not_to receive(:last_occurrence=).with(next_occurrence)
56
+ schedule.schedule_next(time, &block)
57
+ end
58
+ end
59
+ end
60
+
61
+ describe '#to_s' do
62
+ it 'delegates to ice_cube_schedule' do
63
+ expect(schedule.ice_cube_schedule).to receive(:to_s)
64
+ schedule.to_s
65
+ end
66
+ end
67
+
68
+ describe '#start_time' do
69
+ context 'when utc is enabled' do
70
+ before :each do
71
+ FistOfFury.configure do |config|
72
+ config.utc = true
73
+ end
74
+ end
75
+
76
+ it 'returns the utc start time' do
77
+ expect(Time).to receive(:utc)
78
+ schedule
79
+ end
80
+ end
81
+
82
+ context 'when utc is not enabled' do
83
+ it 'returns the local start time' do
84
+ expect(Time).to receive(:local)
85
+ schedule
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ shared_examples_for 'a class that tracks its subclasses' do
4
+ class ClassThatTracksItsSubclasses < described_class
5
+ end
6
+
7
+ class AnotherClassThatTracksItsSubclasses < ClassThatTracksItsSubclasses
8
+ end
9
+
10
+ describe '#subclasses' do
11
+ context 'when deep is specified' do
12
+ it 'returns the class' do
13
+ expect(described_class.subclasses()).to include(ClassThatTracksItsSubclasses)
14
+ expect(described_class.subclasses(true)).to include(AnotherClassThatTracksItsSubclasses)
15
+ end
16
+ end
17
+
18
+ context 'when deep is not specified' do
19
+ it 'returns the class' do
20
+ expect(described_class.subclasses(false)).to include(ClassThatTracksItsSubclasses)
21
+ expect(described_class.subclasses(false)).not_to include(AnotherClassThatTracksItsSubclasses)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe FistOfFury do
4
+ it 'has a version' do
5
+ expect(FistOfFury::VERSION).to_not be_nil
6
+ end
7
+
8
+ it 'has a version that matches the version in the README' do
9
+ readme_path = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'README.md'))
10
+ readme = File.read(readme_path)
11
+ readme_matches = readme.scan(/gem 'fist_of_fury', '~> (\d+).(\d+).+'/)
12
+ readme_matches
13
+ readme_major = readme_matches[0][0]
14
+ readme_minor = readme_matches[0][1]
15
+
16
+ version_matches = FistOfFury::VERSION.scan(/(\d+).(\d+).+/)
17
+ version_major = version_matches[0][0]
18
+ version_minor = version_matches[0][1]
19
+
20
+ expect(readme_major).to eq(version_major)
21
+ expect(readme_minor).to eq(version_minor)
22
+ end
23
+ end
@@ -1,22 +1,54 @@
1
1
  require 'spec_helper'
2
+ require 'fist_of_fury/api_sharedspec'
2
3
 
3
4
  describe FistOfFury do
4
- describe 'logger' do
5
- it "delegates get to Sucker Punch's logger" do
5
+ it_should_behave_like 'the api'
6
+
7
+ describe '#logger' do
8
+ before :each do
9
+ FistOfFury.logger = nil
10
+ end
11
+
12
+ it "delegates to Sucker Punch's logger" do
6
13
  expect(FistOfFury.logger).to eq SuckerPunch.logger
7
14
  end
15
+
16
+ after :each do
17
+ FistOfFury.logger = Logger.new(nil)
18
+ end
8
19
  end
9
20
 
10
- describe 'clock' do
11
- it "delegates get to FistOfFury::Supervisor's clock" do
21
+ describe '#clock' do
22
+ it "delegates to the supervisor's clock" do
12
23
  expect(FistOfFury::Supervisor).to receive(:clock)
13
24
  FistOfFury.clock
14
25
  end
15
26
  end
16
27
 
17
- describe 'store' do
28
+ describe '#store' do
18
29
  it 'starts out as an empty hash' do
19
30
  expect(FistOfFury.store).to eq Hash.new
20
31
  end
21
32
  end
33
+
34
+ describe '#dispatcher' do
35
+ it "delegates to the supervisor's dispatcher" do
36
+ expect(FistOfFury::Supervisor).to receive(:dispatcher)
37
+ FistOfFury.dispatcher
38
+ end
39
+ end
40
+
41
+ describe '#attack!' do
42
+ it 'calls the block when provided' do
43
+ allow(FistOfFury::Supervisor).to receive(:run!)
44
+ block_called = false
45
+ FistOfFury.attack! { block_called = true }
46
+ expect(block_called).to be_true
47
+ end
48
+
49
+ it 'calls #run! on the supervisor' do
50
+ expect(FistOfFury::Supervisor).to receive(:run!)
51
+ FistOfFury.attack!
52
+ end
53
+ end
22
54
  end
@@ -0,0 +1,7 @@
1
+ class AwesomeJob
2
+ include SuckerPunch::Job
3
+ include FistOfFury::Recurrent
4
+
5
+ def perform
6
+ end
7
+ end
data/spec/spec_helper.rb CHANGED
@@ -3,11 +3,36 @@ begin
3
3
  rescue LoadError
4
4
  end
5
5
 
6
+ if RUBY_PLATFORM != "java"
7
+ require 'coveralls'
8
+ Coveralls.wear!
9
+ end
10
+
6
11
  require 'fist_of_fury'
7
12
 
13
+ Dir[File.join(File.dirname(__FILE__), 'fixtures/**/*.rb')].each do |fixture|
14
+ require fixture
15
+ end
16
+
17
+ FistOfFury.logger = Logger.new(nil)
18
+ # Celluloid.logger = Logger.new(nil)
19
+
8
20
  RSpec.configure do |config|
9
21
  config.after(:each) do
10
22
  # Clean up the master queue list
11
23
  SuckerPunch::Queues.instance_variable_set(:@queues, Set.new)
24
+
25
+ # Make sure supervisor is fake
26
+ class ::FistOfFury::Supervisor
27
+ def self.clock
28
+ @clock ||= FistOfFury::Clock.new
29
+ end
30
+
31
+ def self.dispatcher
32
+ @dispatcher ||= FistOfFury::Dispatcher.new
33
+ end
34
+ end
35
+
36
+ FistOfFury.configure_with_defaults
12
37
  end
13
38
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fist_of_fury
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua Rieken
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-03-19 00:00:00.000000000 Z
11
+ date: 2014-03-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pry
@@ -80,6 +80,34 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: ruby_gntp
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: coveralls
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'
83
111
  - !ruby/object:Gem::Dependency
84
112
  name: sucker_punch
85
113
  requirement: !ruby/object:Gem::Requirement
@@ -131,6 +159,7 @@ extra_rdoc_files: []
131
159
  files:
132
160
  - ".gitignore"
133
161
  - ".rspec"
162
+ - ".travis.yml"
134
163
  - Gemfile
135
164
  - Guardfile
136
165
  - LICENSE.txt
@@ -142,6 +171,9 @@ files:
142
171
  - lib/fist_of_fury/actor/clock.rb
143
172
  - lib/fist_of_fury/actor/dispatcher.rb
144
173
  - lib/fist_of_fury/api.rb
174
+ - lib/fist_of_fury/clock.rb
175
+ - lib/fist_of_fury/config.rb
176
+ - lib/fist_of_fury/dispatcher.rb
145
177
  - lib/fist_of_fury/logging.rb
146
178
  - lib/fist_of_fury/railtie.rb
147
179
  - lib/fist_of_fury/recurrent.rb
@@ -149,7 +181,22 @@ files:
149
181
  - lib/fist_of_fury/subclass_tracking.rb
150
182
  - lib/fist_of_fury/supervisor.rb
151
183
  - lib/fist_of_fury/version.rb
184
+ - spec/fist_of_fury/actor_sharedspec.rb
185
+ - spec/fist_of_fury/actors/clock_spec.rb
186
+ - spec/fist_of_fury/actors/dispatcher_spec.rb
187
+ - spec/fist_of_fury/api_sharedspec.rb
188
+ - spec/fist_of_fury/clock_sharedspec.rb
189
+ - spec/fist_of_fury/config_spec.rb
190
+ - spec/fist_of_fury/dispatcher_sharedspec.rb
191
+ - spec/fist_of_fury/job_spec.rb
192
+ - spec/fist_of_fury/logging_sharedspec.rb
193
+ - spec/fist_of_fury/railtie_spec.rb
194
+ - spec/fist_of_fury/recurrent_sharedspec.rb
195
+ - spec/fist_of_fury/schedule_spec.rb
196
+ - spec/fist_of_fury/subclass_tracking_sharedspec.rb
197
+ - spec/fist_of_fury/version_spec.rb
152
198
  - spec/fist_of_fury_spec.rb
199
+ - spec/fixtures/awesome_job.rb
153
200
  - spec/spec_helper.rb
154
201
  homepage: https://github.com/facto/fist_of_fury
155
202
  licenses:
@@ -176,5 +223,20 @@ signing_key:
176
223
  specification_version: 4
177
224
  summary: Recurring jobs for Sucker Punch
178
225
  test_files:
226
+ - spec/fist_of_fury/actor_sharedspec.rb
227
+ - spec/fist_of_fury/actors/clock_spec.rb
228
+ - spec/fist_of_fury/actors/dispatcher_spec.rb
229
+ - spec/fist_of_fury/api_sharedspec.rb
230
+ - spec/fist_of_fury/clock_sharedspec.rb
231
+ - spec/fist_of_fury/config_spec.rb
232
+ - spec/fist_of_fury/dispatcher_sharedspec.rb
233
+ - spec/fist_of_fury/job_spec.rb
234
+ - spec/fist_of_fury/logging_sharedspec.rb
235
+ - spec/fist_of_fury/railtie_spec.rb
236
+ - spec/fist_of_fury/recurrent_sharedspec.rb
237
+ - spec/fist_of_fury/schedule_spec.rb
238
+ - spec/fist_of_fury/subclass_tracking_sharedspec.rb
239
+ - spec/fist_of_fury/version_spec.rb
179
240
  - spec/fist_of_fury_spec.rb
241
+ - spec/fixtures/awesome_job.rb
180
242
  - spec/spec_helper.rb