transitions 1.0.0 → 1.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 +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
|