transitions 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +18 -1
- data/.travis.yml +5 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +7 -6
- data/LICENSE.txt +21 -0
- data/README.md +9 -4
- data/Rakefile +9 -4
- data/bin/console +7 -0
- data/lib/active_model/transitions.rb +19 -12
- data/lib/transitions.rb +15 -15
- data/lib/transitions/event.rb +19 -15
- data/lib/transitions/machine.rb +23 -22
- data/lib/transitions/presenter.rb +2 -6
- data/lib/transitions/state.rb +10 -7
- data/lib/transitions/state_transition.rb +37 -6
- data/lib/transitions/version.rb +1 -1
- data/transitions.gemspec +23 -24
- metadata +39 -45
- data/.ruby-gemset +0 -1
- data/MIT-LICENSE.txt +0 -21
- data/test/active_record/test_active_record.rb +0 -326
- data/test/active_record/test_active_record_scopes.rb +0 -64
- data/test/active_record/test_active_record_timestamps.rb +0 -132
- data/test/active_record/test_custom_select.rb +0 -33
- data/test/event/test_event.rb +0 -72
- data/test/event/test_event_arguments.rb +0 -29
- data/test/event/test_event_being_fired.rb +0 -26
- data/test/event/test_event_checks.rb +0 -33
- data/test/helper.rb +0 -18
- data/test/machine/machine_template.rb +0 -27
- data/test/machine/test_available_states_listing.rb +0 -24
- data/test/machine/test_fire_event_machine.rb +0 -29
- data/test/machine/test_machine.rb +0 -66
- data/test/state/test_state.rb +0 -71
- data/test/state/test_state_predicate_method.rb +0 -32
- data/test/state_transition/test_state_transition.rb +0 -45
- data/test/state_transition/test_state_transition_event_failed_callback.rb +0 -36
- data/test/state_transition/test_state_transition_event_fired_callback.rb +0 -44
- data/test/state_transition/test_state_transition_guard_check.rb +0 -66
- data/test/state_transition/test_state_transition_on_transition_callback.rb +0 -48
- data/test/state_transition/test_state_transition_success_callback.rb +0 -49
@@ -1,24 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
class Bender
|
4
|
-
include Transitions
|
5
|
-
|
6
|
-
state_machine do
|
7
|
-
state :drinking
|
8
|
-
state :smoking
|
9
|
-
state :gambling
|
10
|
-
|
11
|
-
event :cough do
|
12
|
-
transitions from: :smoking, to: :gambling
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
class TestAvailableStatesListing < Test::Unit::TestCase
|
18
|
-
test 'available_states should return the states for the state machine' do
|
19
|
-
assert_equal [:drinking, :gambling, :smoking], Bender.available_states
|
20
|
-
end
|
21
|
-
test 'available_events should return the events for the state machine' do
|
22
|
-
assert_equal [:cough], Bender.available_events
|
23
|
-
end
|
24
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
require_relative './machine_template'
|
3
|
-
|
4
|
-
class TestFireEventMachine < Test::Unit::TestCase
|
5
|
-
def setup
|
6
|
-
@record = MachineTestSubject.new
|
7
|
-
@machine = MachineTestSubject.get_state_machine
|
8
|
-
@event = @machine.events_for(@record.current_state).first
|
9
|
-
assert_not_nil @event
|
10
|
-
end
|
11
|
-
|
12
|
-
test 'fire_event returns true if state transition was successful' do
|
13
|
-
@machine.stubs(:transition_to_new_state).returns(:closed)
|
14
|
-
|
15
|
-
assert_equal true, @machine.fire_event(@event, @record, false)
|
16
|
-
end
|
17
|
-
|
18
|
-
test 'fire_event returns false if state transition was unsuccessful' do
|
19
|
-
@machine.stubs(:transition_to_new_state).returns(false)
|
20
|
-
|
21
|
-
assert_equal false, @machine.fire_event(@event, @record, false)
|
22
|
-
end
|
23
|
-
|
24
|
-
test 'fire_event returns false if state transition raises' do
|
25
|
-
@machine.stubs(:transition_to_new_state).raises(StandardError)
|
26
|
-
|
27
|
-
assert_equal false, @machine.fire_event(@event, @record, false)
|
28
|
-
end
|
29
|
-
end
|
@@ -1,66 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
class MachineTestSubject
|
4
|
-
include Transitions
|
5
|
-
|
6
|
-
state_machine initial: :closed do
|
7
|
-
state :open
|
8
|
-
state :closed
|
9
|
-
|
10
|
-
event :shutdown do
|
11
|
-
transitions from: :open, to: :closed
|
12
|
-
end
|
13
|
-
|
14
|
-
event :timeout do
|
15
|
-
transitions from: :open, to: :closed
|
16
|
-
end
|
17
|
-
|
18
|
-
event :restart do
|
19
|
-
transitions from: :closed, to: :open, guard: :restart_allowed?
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def restart_allowed?(allowed = true)
|
24
|
-
allowed
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
class TransitionsMachineTest < Test::Unit::TestCase
|
29
|
-
test 'sets #initial_state from :initial option' do
|
30
|
-
assert_equal :closed, MachineTestSubject.get_state_machine.initial_state
|
31
|
-
end
|
32
|
-
|
33
|
-
test '`get_state_machine` returns Transitions::Machine' do
|
34
|
-
assert_kind_of Transitions::Machine, MachineTestSubject.get_state_machine
|
35
|
-
end
|
36
|
-
|
37
|
-
test 'finds events for given state' do
|
38
|
-
events = MachineTestSubject.get_state_machine.events_for(:open)
|
39
|
-
assert events.include?(:shutdown)
|
40
|
-
assert events.include?(:timeout)
|
41
|
-
end
|
42
|
-
|
43
|
-
test 'knows all available transitions for current state' do
|
44
|
-
machine = MachineTestSubject.new
|
45
|
-
assert_equal [:restart], machine.available_transitions
|
46
|
-
machine.restart
|
47
|
-
assert_equal [:shutdown, :timeout], machine.available_transitions
|
48
|
-
end
|
49
|
-
|
50
|
-
test 'knows that it can use a transition when it is available' do
|
51
|
-
machine = MachineTestSubject.new
|
52
|
-
machine.restart
|
53
|
-
assert machine.can_transition?(:shutdown)
|
54
|
-
end
|
55
|
-
|
56
|
-
test "knows that it can't use a transition when it is unavailable" do
|
57
|
-
machine = MachineTestSubject.new
|
58
|
-
assert machine.cant_transition?(:shutdown)
|
59
|
-
end
|
60
|
-
|
61
|
-
test "knows that it can't transition to a state denied by a guard" do
|
62
|
-
machine = MachineTestSubject.new
|
63
|
-
assert machine.can_execute_restart? true
|
64
|
-
refute machine.can_execute_restart? false
|
65
|
-
end
|
66
|
-
end
|
data/test/state/test_state.rb
DELETED
@@ -1,71 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
class TestState < Test::Unit::TestCase
|
4
|
-
def setup
|
5
|
-
machine = Class.new do
|
6
|
-
include Transitions
|
7
|
-
state_machine do
|
8
|
-
end
|
9
|
-
end.get_state_machine
|
10
|
-
state_name = :astate
|
11
|
-
@options = { machine: machine, custom_key: :my_key }
|
12
|
-
@state = Transitions::State.new(state_name, @options)
|
13
|
-
end
|
14
|
-
|
15
|
-
def new_state_name
|
16
|
-
Random.alphanumeric(16)
|
17
|
-
end
|
18
|
-
|
19
|
-
test 'sets the name' do
|
20
|
-
assert_equal :astate, @state.name
|
21
|
-
end
|
22
|
-
|
23
|
-
test 'sets the display_name from name' do
|
24
|
-
assert_equal 'Astate', @state.display_name
|
25
|
-
end
|
26
|
-
|
27
|
-
test 'sets the display_name from options' do
|
28
|
-
assert_equal 'A State', Transitions::State.new(new_state_name, @options.merge(display: 'A State')).display_name
|
29
|
-
end
|
30
|
-
|
31
|
-
test 'sets the options and expose them as options' do
|
32
|
-
@options.delete(:machine)
|
33
|
-
state = Transitions::State.new new_state_name, @options
|
34
|
-
assert_equal @options, state.options
|
35
|
-
end
|
36
|
-
|
37
|
-
test 'equals a symbol of the same name' do
|
38
|
-
assert_equal @state, :astate
|
39
|
-
end
|
40
|
-
|
41
|
-
test 'equals a State of the same name' do
|
42
|
-
assert_equal @state, @state
|
43
|
-
end
|
44
|
-
|
45
|
-
test 'should send a message to the record for an action if the action is present as a symbol' do
|
46
|
-
state = Transitions::State.new new_state_name, @options.merge(entering: :foo)
|
47
|
-
|
48
|
-
record = stub
|
49
|
-
record.expects(:foo)
|
50
|
-
|
51
|
-
state.call_action(:entering, record)
|
52
|
-
end
|
53
|
-
|
54
|
-
test 'should send a message to the record for an action if the action is present as a string' do
|
55
|
-
state = Transitions::State.new new_state_name, @options.merge(entering: 'foo')
|
56
|
-
|
57
|
-
record = stub
|
58
|
-
record.expects(:foo)
|
59
|
-
|
60
|
-
state.call_action(:entering, record)
|
61
|
-
end
|
62
|
-
|
63
|
-
test 'should call a proc, passing in the record for an action if the action is present' do
|
64
|
-
state = Transitions::State.new new_state_name, @options.merge(entering: proc(&:foobar))
|
65
|
-
|
66
|
-
record = stub
|
67
|
-
record.expects(:foobar)
|
68
|
-
|
69
|
-
state.call_action(:entering, record)
|
70
|
-
end
|
71
|
-
end
|
@@ -1,32 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
class Bus
|
4
|
-
include Transitions
|
5
|
-
|
6
|
-
state_machine do
|
7
|
-
state :parking
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
class TestStatePredicateMethod < Test::Unit::TestCase
|
12
|
-
def setup
|
13
|
-
@bus = Bus.new
|
14
|
-
end
|
15
|
-
|
16
|
-
test 'should generate predicate methods for states' do
|
17
|
-
assert_true @bus.respond_to?(:parking?)
|
18
|
-
assert_true @bus.send(:parking?)
|
19
|
-
end
|
20
|
-
|
21
|
-
test 'should raise `InvalidMethodOverride` if we try to overwrite existing methods' do
|
22
|
-
assert_raise(Transitions::InvalidMethodOverride) do
|
23
|
-
Class.new do
|
24
|
-
include Transitions
|
25
|
-
|
26
|
-
state_machine do
|
27
|
-
state :frozen
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
@@ -1,45 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
class TestStateTransition < Test::Unit::TestCase
|
4
|
-
test 'should set from, to, and opts attr readers' do
|
5
|
-
opts = { from: 'foo', to: 'bar', guard: 'g' }
|
6
|
-
st = Transitions::StateTransition.new(opts)
|
7
|
-
|
8
|
-
assert_equal opts[:from], st.from
|
9
|
-
assert_equal opts[:to], st.to
|
10
|
-
assert_equal opts, st.options
|
11
|
-
end
|
12
|
-
|
13
|
-
test 'should pass equality check if from and to are the same' do
|
14
|
-
opts = { from: 'foo', to: 'bar', guard: 'g' }
|
15
|
-
st = Transitions::StateTransition.new(opts)
|
16
|
-
|
17
|
-
obj = stub
|
18
|
-
obj.stubs(:from).returns(opts[:from])
|
19
|
-
obj.stubs(:to).returns(opts[:to])
|
20
|
-
|
21
|
-
assert_equal st, obj
|
22
|
-
end
|
23
|
-
|
24
|
-
test 'should fail equality check if from are not the same' do
|
25
|
-
opts = { from: 'foo', to: 'bar', guard: 'g' }
|
26
|
-
st = Transitions::StateTransition.new(opts)
|
27
|
-
|
28
|
-
obj = stub
|
29
|
-
obj.stubs(:from).returns('blah')
|
30
|
-
obj.stubs(:to).returns(opts[:to])
|
31
|
-
|
32
|
-
assert_not_equal st, obj
|
33
|
-
end
|
34
|
-
|
35
|
-
test 'should fail equality check if to are not the same' do
|
36
|
-
opts = { from: 'foo', to: 'bar', guard: 'g' }
|
37
|
-
st = Transitions::StateTransition.new(opts)
|
38
|
-
|
39
|
-
obj = stub
|
40
|
-
obj.stubs(:from).returns(opts[:from])
|
41
|
-
obj.stubs(:to).returns('blah')
|
42
|
-
|
43
|
-
assert_not_equal st, obj
|
44
|
-
end
|
45
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
class Car
|
4
|
-
include Transitions
|
5
|
-
|
6
|
-
state_machine do
|
7
|
-
state :parked
|
8
|
-
state :driving
|
9
|
-
state :switched_off
|
10
|
-
|
11
|
-
event :start_driving do
|
12
|
-
transitions from: :parked, to: :driving
|
13
|
-
end
|
14
|
-
|
15
|
-
event :switch_off_engine do
|
16
|
-
transitions from: :parked, to: :switched_off
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
class TestStateTransitionEventFailedCallback < Test::Unit::TestCase
|
22
|
-
def setup
|
23
|
-
@car = Car.new
|
24
|
-
end
|
25
|
-
|
26
|
-
test "should execute the event_failed_callback and don't raise error if callback is defined" do
|
27
|
-
@car.start_driving
|
28
|
-
@car.expects(:event_failed).with(:switch_off_engine)
|
29
|
-
@car.switch_off_engine
|
30
|
-
end
|
31
|
-
|
32
|
-
test "should just re-raise any error on transition if the event_failed_callback isn't defined" do
|
33
|
-
@car.start_driving
|
34
|
-
assert_raise(Transitions::InvalidTransition) { @car.switch_off_engine }
|
35
|
-
end
|
36
|
-
end
|
@@ -1,44 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
class Car
|
4
|
-
include Transitions
|
5
|
-
|
6
|
-
state_machine do
|
7
|
-
state :parked
|
8
|
-
state :driving
|
9
|
-
|
10
|
-
event :start_driving do
|
11
|
-
transitions from: :parked, to: :driving
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
class TestStateTransitionEventFiredCallback < Test::Unit::TestCase
|
17
|
-
def setup
|
18
|
-
@car = Car.new
|
19
|
-
end
|
20
|
-
|
21
|
-
test 'should execute the event_fired callback after successfull event execution if it callback is defined' do
|
22
|
-
@car.stubs(:event_fired)
|
23
|
-
@car.expects(:event_fired).with(:parked, :driving, :start_driving).once
|
24
|
-
|
25
|
-
@car.start_driving!
|
26
|
-
end
|
27
|
-
|
28
|
-
test 'should not execute the event_fired callback after successfull event execution if it callback is not defined' do
|
29
|
-
pend 'Test fails right now although functionality is working as expected'
|
30
|
-
# This test fails right now even though it works as expected in the console.
|
31
|
-
# The reason for this is, that mocha's `expects` does a little bit more than just set up an expectation,
|
32
|
-
# it actually defines this method if it doesn't exist or at least it overwrites respond_to?
|
33
|
-
# @car.respond_to?(:event_fired)
|
34
|
-
# returns false before the `expects` call, but true after.
|
35
|
-
# Hence, this test fails.
|
36
|
-
# Something like
|
37
|
-
# @car.instance_eval { undef :event_fired }
|
38
|
-
# doesn't work either, probably because expects just overwrites respond_to?
|
39
|
-
# but does not define the method
|
40
|
-
# How to fix?
|
41
|
-
@car.expects(:event_fired).never
|
42
|
-
@car.start_driving!
|
43
|
-
end
|
44
|
-
end
|
@@ -1,66 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
class TestStateTransitionGuardCheck < Test::Unit::TestCase
|
4
|
-
args = [:foo, 'bar']
|
5
|
-
|
6
|
-
test 'should return true of there is no guard' do
|
7
|
-
opts = { from: 'foo', to: 'bar' }
|
8
|
-
st = Transitions::StateTransition.new(opts)
|
9
|
-
|
10
|
-
assert st.executable?(nil, *args)
|
11
|
-
end
|
12
|
-
|
13
|
-
test 'should call the method on the object if guard is a symbol' do
|
14
|
-
opts = { from: 'foo', to: 'bar', guard: :test_guard }
|
15
|
-
st = Transitions::StateTransition.new(opts)
|
16
|
-
|
17
|
-
obj = stub
|
18
|
-
obj.expects(:test_guard).with(*args)
|
19
|
-
|
20
|
-
st.executable?(obj, *args)
|
21
|
-
end
|
22
|
-
|
23
|
-
test 'should call the method on the object if guard is a string' do
|
24
|
-
opts = { from: 'foo', to: 'bar', guard: 'test_guard' }
|
25
|
-
st = Transitions::StateTransition.new(opts)
|
26
|
-
|
27
|
-
obj = stub
|
28
|
-
obj.expects(:test_guard).with(*args)
|
29
|
-
|
30
|
-
st.executable?(obj, *args)
|
31
|
-
end
|
32
|
-
|
33
|
-
test 'should call the proc passing the object if the guard is a proc' do
|
34
|
-
opts = { from: 'foo', to: 'bar', guard: proc { |o, *args| o.test_guard(*args) } }
|
35
|
-
st = Transitions::StateTransition.new(opts)
|
36
|
-
|
37
|
-
obj = stub
|
38
|
-
obj.expects(:test_guard).with(*args)
|
39
|
-
|
40
|
-
st.executable?(obj, *args)
|
41
|
-
end
|
42
|
-
|
43
|
-
test 'should call the callable passing the object if the guard responds to #call' do
|
44
|
-
callable = Object.new
|
45
|
-
callable.define_singleton_method(:call) { |obj, *args| obj.test_guard(*args) }
|
46
|
-
|
47
|
-
opts = { from: 'foo', to: 'bar', guard: callable }
|
48
|
-
st = Transitions::StateTransition.new(opts)
|
49
|
-
|
50
|
-
obj = stub
|
51
|
-
obj.expects(:test_guard).with(*args)
|
52
|
-
|
53
|
-
st.executable?(obj, *args)
|
54
|
-
end
|
55
|
-
|
56
|
-
test 'should call the method on the object if guard is a symbol' do
|
57
|
-
opts = { from: 'foo', to: 'bar', guard: [:test_guard, :test_another_guard] }
|
58
|
-
st = Transitions::StateTransition.new(opts)
|
59
|
-
|
60
|
-
obj = stub
|
61
|
-
obj.expects(:test_guard).with(*args).returns(true)
|
62
|
-
obj.expects(:test_another_guard).with(*args).returns(true)
|
63
|
-
|
64
|
-
assert st.executable?(obj, *args)
|
65
|
-
end
|
66
|
-
end
|
@@ -1,48 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
class Truck
|
4
|
-
include Transitions
|
5
|
-
attr_reader :test_recorder
|
6
|
-
|
7
|
-
def initialize
|
8
|
-
@test_recorder = []
|
9
|
-
end
|
10
|
-
|
11
|
-
state_machine do
|
12
|
-
state :parked
|
13
|
-
state :running
|
14
|
-
state :driving
|
15
|
-
|
16
|
-
event :turn_key do
|
17
|
-
transitions from: :parked, to: :running, on_transition: :start_engine
|
18
|
-
end
|
19
|
-
|
20
|
-
event :start_driving do
|
21
|
-
transitions from: :parked, to: :driving, on_transition: [:start_engine, :loosen_handbrake, :push_gas_pedal]
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
%w(start_engine loosen_handbrake push_gas_pedal).each do |m|
|
26
|
-
define_method(m) { @test_recorder << m }
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
class TestStateTransitionCallbacks < Test::Unit::TestCase
|
31
|
-
test "should execute callback defined via 'on_transition'" do
|
32
|
-
truck = Truck.new
|
33
|
-
truck.expects(:start_engine)
|
34
|
-
truck.turn_key!
|
35
|
-
end
|
36
|
-
|
37
|
-
test "should execute multiple callbacks defined via 'on_transition' in the same order they were defined" do
|
38
|
-
# This test requires some explanation: We started out with something like this:
|
39
|
-
# truck.expects(:start_engine).in_sequence(on_transition_sequence)
|
40
|
-
# Which, after a while (don't ask me why) caused some weird problems and seemed to fail randomly.
|
41
|
-
# Hence the workaround below.
|
42
|
-
|
43
|
-
truck = Truck.new
|
44
|
-
|
45
|
-
truck.start_driving!
|
46
|
-
assert_equal truck.test_recorder, [:start_engine, :loosen_handbrake, :push_gas_pedal].map(&:to_s)
|
47
|
-
end
|
48
|
-
end
|