motion-state-machine 0.8.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.
- data/.gitignore +19 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +145 -0
- data/Rakefile +31 -0
- data/lib/motion-state-machine.rb +9 -0
- data/lib/motion-state-machine/base.rb +223 -0
- data/lib/motion-state-machine/spec_app_delegate.rb +7 -0
- data/lib/motion-state-machine/state.rb +379 -0
- data/lib/motion-state-machine/transition.rb +407 -0
- data/lib/motion-state-machine/version.rb +3 -0
- data/motion-state-machine.gemspec +19 -0
- data/spec/motion-state-machine/base_spec.rb +118 -0
- data/spec/motion-state-machine/benchmark_spec.rb +74 -0
- data/spec/motion-state-machine/notification_transition_spec.rb +57 -0
- data/spec/motion-state-machine/send_event_transition_spec.rb +53 -0
- data/spec/motion-state-machine/state_spec.rb +219 -0
- data/spec/motion-state-machine/timed_transition_spec.rb +48 -0
- data/spec/motion-state-machine/transition_spec.rb +157 -0
- metadata +90 -0
@@ -0,0 +1,48 @@
|
|
1
|
+
describe StateMachine::TimedTransition do
|
2
|
+
|
3
|
+
before do
|
4
|
+
@state_machine = StateMachine::Base.new start_state: :timing_out
|
5
|
+
action = proc { @fired = true }
|
6
|
+
@state_machine.when :timing_out do |state|
|
7
|
+
@transition = state.transition_to(:timed_out, after: 0.5, action: action).first
|
8
|
+
state.transition_to :canceled, on: :cancel
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should be created correctly" do
|
13
|
+
@transition.should.is_a(StateMachine::TimedTransition)
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "after entering the state that is timing out" do
|
17
|
+
before do
|
18
|
+
@fired = false
|
19
|
+
@other_queue = Dispatch::Queue.concurrent :default
|
20
|
+
@other_queue.sync do
|
21
|
+
@state_machine.start! # will arm the transition
|
22
|
+
end
|
23
|
+
@state_machine.current_state.symbol.should == :timing_out
|
24
|
+
@fired.should == false
|
25
|
+
end
|
26
|
+
|
27
|
+
it "it should execute at the given time if not cancelled" do
|
28
|
+
sleep 0.49
|
29
|
+
@state_machine.current_state.symbol.should == :timing_out
|
30
|
+
@fired.should == false
|
31
|
+
sleep 0.02
|
32
|
+
@state_machine.current_state.symbol.should == :timed_out
|
33
|
+
@fired.should == true
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should not execute if leaving the state before timeout" do
|
37
|
+
sleep 0.49
|
38
|
+
@fired.should == false
|
39
|
+
@other_queue.async do
|
40
|
+
@state_machine.event :cancel
|
41
|
+
end
|
42
|
+
sleep 0.02
|
43
|
+
@state_machine.current_state.symbol.should == :canceled
|
44
|
+
@fired.should == false
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
describe StateMachine::Transition do
|
2
|
+
before do
|
3
|
+
@state_machine = StateMachine::Base.new start_state: :awake
|
4
|
+
@source_state = @state_machine.state :awake
|
5
|
+
@destination_state = @state_machine.state :tired
|
6
|
+
@options = {
|
7
|
+
state_machine: @state_machine,
|
8
|
+
from: :awake,
|
9
|
+
to: :tired,
|
10
|
+
on: :work_done
|
11
|
+
}
|
12
|
+
StateMachine::Transition.event_type = :on
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#initialize(options)" do
|
16
|
+
it "should not raise if correctly initialized" do
|
17
|
+
proc {StateMachine::Transition.new @options}.should.not.raise
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should raise if it should be internal, but source state != destination state" do
|
21
|
+
@options[:from].should != @options[:to]
|
22
|
+
proc {StateMachine::Transition.new @options.merge(internal: true)}.
|
23
|
+
should.raise ArgumentError, /Internal/
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "after initialization" do
|
28
|
+
before do
|
29
|
+
@transition = StateMachine::Transition.new @options
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#allowed?" do
|
33
|
+
it "should be true if no guard blocks are given" do
|
34
|
+
@transition.should.be.allowed
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should have the correct logic results according to a logic table" do
|
38
|
+
# :unless :if allowed?
|
39
|
+
{
|
40
|
+
[nil, nil] => true,
|
41
|
+
[nil, false] => false,
|
42
|
+
[nil, true] => true,
|
43
|
+
[false, nil] => true,
|
44
|
+
[false, false] => false,
|
45
|
+
[false, true] => true,
|
46
|
+
[true, nil] => false,
|
47
|
+
[true, false] => false,
|
48
|
+
[true, true] => false,
|
49
|
+
}.each do |guards, result|
|
50
|
+
transition = StateMachine::Transition.new @options.dup
|
51
|
+
transition.options[:unless] = proc {guards[0]} unless guards[0].nil?
|
52
|
+
transition.options[:if] = proc {guards[1]} unless guards[1].nil?
|
53
|
+
transition.allowed?.should == result
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "#unguarded_execute" do
|
60
|
+
it "should call its source state's exit method if not internal" do
|
61
|
+
exit_action_called = false
|
62
|
+
@state_machine.when(:awake) do |state|
|
63
|
+
state.on_exit do
|
64
|
+
exit_action_called = true
|
65
|
+
end
|
66
|
+
end
|
67
|
+
@state_machine.start!
|
68
|
+
exit_action_called.should == false
|
69
|
+
@transition.send :unguarded_execute
|
70
|
+
exit_action_called.should == true
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should not call its source state's exit method if internal" do
|
74
|
+
@transition.options[:internal] = true
|
75
|
+
exit_action_called = false
|
76
|
+
@state_machine.when(:awake) do |state|
|
77
|
+
state.on_exit do
|
78
|
+
exit_action_called = true
|
79
|
+
end
|
80
|
+
end
|
81
|
+
@state_machine.start!
|
82
|
+
exit_action_called.should == false
|
83
|
+
@transition.send :unguarded_execute
|
84
|
+
exit_action_called.should == false
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should call its destination state's enter method if not internal" do
|
88
|
+
entry_action_called = false
|
89
|
+
@state_machine.when(:tired) do |state|
|
90
|
+
state.on_entry do
|
91
|
+
entry_action_called = true
|
92
|
+
end
|
93
|
+
end
|
94
|
+
@state_machine.start!
|
95
|
+
entry_action_called.should == false
|
96
|
+
@transition.send :unguarded_execute
|
97
|
+
entry_action_called.should == true
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should not call its destination state's enter method if internal" do
|
101
|
+
@transition.options[:internal] = true
|
102
|
+
entry_action_called = false
|
103
|
+
@state_machine.when(:tired) do |state|
|
104
|
+
state.on_entry do
|
105
|
+
entry_action_called = true
|
106
|
+
end
|
107
|
+
end
|
108
|
+
@state_machine.start!
|
109
|
+
entry_action_called.should == false
|
110
|
+
@transition.send :unguarded_execute
|
111
|
+
entry_action_called.should == false
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should call its action block if given" do
|
115
|
+
called = false
|
116
|
+
argument = nil
|
117
|
+
@transition.options[:action] = proc do |state_machine|
|
118
|
+
called = true
|
119
|
+
argument = state_machine
|
120
|
+
end
|
121
|
+
@state_machine.start!
|
122
|
+
called.should == false
|
123
|
+
@transition.send :unguarded_execute
|
124
|
+
called.should == true
|
125
|
+
argument.should == @state_machine
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should not be guarded, but directly execute" do
|
129
|
+
@transition.options[:if] = proc { false }
|
130
|
+
@transition.options[:unless] = proc { true }
|
131
|
+
@state_machine.start!
|
132
|
+
@state_machine.current_state.symbol.should == :awake
|
133
|
+
@transition.send :unguarded_execute
|
134
|
+
@state_machine.current_state.symbol.should == :tired
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
describe "#handle_in_source_state" do
|
139
|
+
it "should raise if called before the state machine is started" do
|
140
|
+
@state_machine.current_state.symbol.should == :waiting_for_start
|
141
|
+
proc {@transition.send :handle_in_source_state}.
|
142
|
+
should.raise RuntimeError, /started/
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should raise if called outside the initial queue" do
|
146
|
+
@state_machine.start!
|
147
|
+
other_queue = Dispatch::Queue.concurrent(:default)
|
148
|
+
other_queue.to_s.should != Dispatch::Queue.main.to_s
|
149
|
+
other_queue.sync do
|
150
|
+
proc {@transition.send :handle_in_source_state}.should.raise RuntimeError, /queue/
|
151
|
+
end
|
152
|
+
@state_machine.current_state.symbol.should == :awake
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: motion-state-machine
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.8.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Sebastian Burkhart
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-06-30 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rake
|
16
|
+
requirement: &70177501197480 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70177501197480
|
25
|
+
description: A finite state machine for RubyMotion with a flavor of Grand Central
|
26
|
+
Dispatch.
|
27
|
+
email:
|
28
|
+
- sebastianburkhart@me.com
|
29
|
+
executables: []
|
30
|
+
extensions: []
|
31
|
+
extra_rdoc_files: []
|
32
|
+
files:
|
33
|
+
- .gitignore
|
34
|
+
- Gemfile
|
35
|
+
- LICENSE
|
36
|
+
- README.md
|
37
|
+
- Rakefile
|
38
|
+
- lib/motion-state-machine.rb
|
39
|
+
- lib/motion-state-machine/base.rb
|
40
|
+
- lib/motion-state-machine/spec_app_delegate.rb
|
41
|
+
- lib/motion-state-machine/state.rb
|
42
|
+
- lib/motion-state-machine/transition.rb
|
43
|
+
- lib/motion-state-machine/version.rb
|
44
|
+
- motion-state-machine.gemspec
|
45
|
+
- spec/motion-state-machine/base_spec.rb
|
46
|
+
- spec/motion-state-machine/benchmark_spec.rb
|
47
|
+
- spec/motion-state-machine/notification_transition_spec.rb
|
48
|
+
- spec/motion-state-machine/send_event_transition_spec.rb
|
49
|
+
- spec/motion-state-machine/state_spec.rb
|
50
|
+
- spec/motion-state-machine/timed_transition_spec.rb
|
51
|
+
- spec/motion-state-machine/transition_spec.rb
|
52
|
+
homepage: https://github.com/opyh/motion-state-machine
|
53
|
+
licenses: []
|
54
|
+
post_install_message:
|
55
|
+
rdoc_options: []
|
56
|
+
require_paths:
|
57
|
+
- lib
|
58
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
60
|
+
requirements:
|
61
|
+
- - ! '>='
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
64
|
+
segments:
|
65
|
+
- 0
|
66
|
+
hash: 774551363156047026
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
69
|
+
requirements:
|
70
|
+
- - ! '>='
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '0'
|
73
|
+
segments:
|
74
|
+
- 0
|
75
|
+
hash: 774551363156047026
|
76
|
+
requirements: []
|
77
|
+
rubyforge_project:
|
78
|
+
rubygems_version: 1.8.10
|
79
|
+
signing_key:
|
80
|
+
specification_version: 3
|
81
|
+
summary: Comes with a nice syntax for state and transition definition. Supports triggering
|
82
|
+
via events, timeouts and NSNotifications.
|
83
|
+
test_files:
|
84
|
+
- spec/motion-state-machine/base_spec.rb
|
85
|
+
- spec/motion-state-machine/benchmark_spec.rb
|
86
|
+
- spec/motion-state-machine/notification_transition_spec.rb
|
87
|
+
- spec/motion-state-machine/send_event_transition_spec.rb
|
88
|
+
- spec/motion-state-machine/state_spec.rb
|
89
|
+
- spec/motion-state-machine/timed_transition_spec.rb
|
90
|
+
- spec/motion-state-machine/transition_spec.rb
|