lab42_state_machine 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +31 -1
- data/lib/lab42/state_machine.rb +2 -18
- data/lib/lab42/state_machine/controller.rb +76 -39
- data/lib/lab42/state_machine/controller/stream_api.rb +39 -0
- data/lib/lab42/state_machine/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1a04c2bcbca5f354f981c2f929f862ca3dde8d20
|
4
|
+
data.tar.gz: 28f8f7ab95247ebbe85b8f0738e7971642e42d20
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4c2391b75893b6779206664fc468b8ce289fcb42b59b27f1613a30e9a5a02819d6d433111b3299d0a4c82e8ab198cef718915488d5394838fd1673c06d50b240
|
7
|
+
data.tar.gz: ad0f241232884a58993dccf3997b9629cea8d7ae25e85b45a4cabb70c478144a21d4213e643d8b35a675cb68c34c3a05af10f2c191c5520761fa1e2ab04def4c
|
data/README.md
CHANGED
@@ -35,7 +35,7 @@ This simple example demonstrates the following essential rules:
|
|
35
35
|
* An easy way to setup the State Machine is by providing a block to its constructor. This block
|
36
36
|
is instance evalled and thus has access to the whole API (see below). But of course the public API
|
37
37
|
methods can be accessed in a more detached style too:
|
38
|
-
|
38
|
+
```state_machine.state :reset do @counter = 0 end```
|
39
39
|
|
40
40
|
* The initial state of the State Machine defaults to `:init`
|
41
41
|
|
@@ -181,3 +181,33 @@ This is the (overloaded - for the sake of a slim API) workerbee of the State Mac
|
|
181
181
|
##### state setter form (1 param)
|
182
182
|
|
183
183
|
```state new_state``` Set new state of the StateMachine
|
184
|
+
|
185
|
+
### Advanced Stream API
|
186
|
+
|
187
|
+
This part of the API is exposed by `controller` and allows the StateMachine to implement some stream operations like `rewind` or `drop_while`.
|
188
|
+
|
189
|
+
Unless indicated otherwise the invocation of a method in this API does not interrupt the normal flow of the StateMachine but the bang version
|
190
|
+
also implies a `skip`. Thusly in general
|
191
|
+
|
192
|
+
```ruby
|
193
|
+
controller.<advanced_stream_api_method>!
|
194
|
+
```
|
195
|
+
|
196
|
+
is the same as
|
197
|
+
|
198
|
+
```ruby
|
199
|
+
controller.<advanced_stream_api_method>
|
200
|
+
skip
|
201
|
+
```
|
202
|
+
|
203
|
+
Also unless indicated otherwise the result of the invocation replaces the internal stream of the controller (having effect on input from the **next step only**)
|
204
|
+
|
205
|
+
In order to better understand this API we recommand to have a look at the [corresponding specs]( https://github.com/RobertDober/lab42_state_machine/blob/master/spec/units/stream_api_spec.rb)
|
206
|
+
|
207
|
+
#### drop\_until( &condition)
|
208
|
+
|
209
|
+
Works like ```drop_while{ |ele| !condition.( ele ) }```
|
210
|
+
|
211
|
+
#### drop\_while( &condition )
|
212
|
+
|
213
|
+
Forwarded to the internal stream which is replaced by this result.
|
data/lib/lab42/state_machine.rb
CHANGED
@@ -6,7 +6,7 @@ module Lab42
|
|
6
6
|
extend Forwarder
|
7
7
|
attr_accessor :subject
|
8
8
|
|
9
|
-
forward_all :after, :before, :setup, :state, :teardown, :transition, to: :controller
|
9
|
+
forward_all :after, :before, :setup, :skip, :state, :teardown, :transition, to: :controller
|
10
10
|
|
11
11
|
def behavior name, &behave
|
12
12
|
class << self; self end. module_eval do
|
@@ -19,15 +19,7 @@ module Lab42
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def run input=[]
|
22
|
-
|
23
|
-
input = nil
|
24
|
-
|
25
|
-
controller.run_setups( (inputs.peek rescue nil) )
|
26
|
-
loop do
|
27
|
-
input = inputs.next
|
28
|
-
controller.run input
|
29
|
-
end
|
30
|
-
controller.run_teardowns input
|
22
|
+
controller.run input
|
31
23
|
subject
|
32
24
|
end
|
33
25
|
|
@@ -47,14 +39,6 @@ module Lab42
|
|
47
39
|
end
|
48
40
|
end
|
49
41
|
|
50
|
-
def __make_inputs__ input
|
51
|
-
case input
|
52
|
-
when Enumerable, Enumerator
|
53
|
-
input.lazy
|
54
|
-
else
|
55
|
-
raise ArgumentError, "cannot enumerate on object #{input}"
|
56
|
-
end
|
57
|
-
end
|
58
42
|
|
59
43
|
end # class StateMachine
|
60
44
|
end # module Lab42
|
@@ -1,23 +1,29 @@
|
|
1
|
+
require 'lab42/state_machine/controller/stream_api'
|
1
2
|
module Lab42
|
2
3
|
class StateMachine
|
3
4
|
class Controller
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
6
|
+
include StreamApi
|
7
|
+
|
8
|
+
attr_reader :stream
|
9
|
+
|
10
|
+
SkipState = Class.new RuntimeError
|
11
|
+
|
12
|
+
def after blk=nil, &block
|
13
|
+
@afters << mk_block(blk, block)
|
8
14
|
end
|
9
15
|
|
10
|
-
def before
|
11
|
-
|
12
|
-
@befores << behavior
|
16
|
+
def before blk=nil, &block
|
17
|
+
@befores << mk_block(blk, block)
|
13
18
|
end
|
14
19
|
|
15
20
|
def run input
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
+
mk_input_stream input
|
22
|
+
run_setups
|
23
|
+
loop do
|
24
|
+
run_one
|
25
|
+
end
|
26
|
+
run_teardowns
|
21
27
|
end
|
22
28
|
|
23
29
|
def run_afters
|
@@ -28,27 +34,43 @@ module Lab42
|
|
28
34
|
run_state_blocks @befores
|
29
35
|
end
|
30
36
|
|
37
|
+
def run_one
|
38
|
+
@current_input = stream.next
|
39
|
+
run_befores
|
40
|
+
run_states
|
41
|
+
run_transitions
|
42
|
+
run_afters
|
43
|
+
rescue SkipState
|
44
|
+
end
|
45
|
+
|
46
|
+
def run_setup_blocks blox
|
47
|
+
blox.each do | block |
|
48
|
+
@sm.instance_exec( __peek__, &block )
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
31
52
|
def run_state_blocks blox
|
32
53
|
blox.each do | block |
|
33
54
|
@sm.instance_exec( @current_input, @old_state, @state, &block )
|
34
55
|
end
|
35
56
|
end
|
36
57
|
|
37
|
-
def run_setups
|
58
|
+
def run_setups
|
38
59
|
@setups.each do | block |
|
39
|
-
@sm.instance_exec(
|
60
|
+
@sm.instance_exec( peek_first, &block )
|
40
61
|
end
|
62
|
+
rescue SkipState
|
41
63
|
end
|
42
64
|
|
43
65
|
def run_states
|
44
66
|
run_state_blocks @handlers[@state]
|
45
67
|
end
|
46
68
|
|
47
|
-
|
48
|
-
def run_teardowns input
|
69
|
+
def run_teardowns
|
49
70
|
@teardowns.each do | teardown |
|
50
|
-
@sm.instance_exec(
|
71
|
+
@sm.instance_exec( @current_input, @state, &teardown )
|
51
72
|
end
|
73
|
+
rescue SkipState
|
52
74
|
end
|
53
75
|
|
54
76
|
def run_transitions
|
@@ -60,9 +82,12 @@ module Lab42
|
|
60
82
|
@state = st
|
61
83
|
end
|
62
84
|
|
63
|
-
def setup
|
64
|
-
|
65
|
-
|
85
|
+
def setup blk=nil, &block
|
86
|
+
@setups << mk_block(blk, block)
|
87
|
+
end
|
88
|
+
|
89
|
+
def skip
|
90
|
+
raise SkipState, "skipping actions in this setup/state/teardown"
|
66
91
|
end
|
67
92
|
|
68
93
|
def state *args, &block
|
@@ -72,7 +97,9 @@ module Lab42
|
|
72
97
|
@handlers[ args.first ] << block
|
73
98
|
end
|
74
99
|
|
75
|
-
def teardown &block
|
100
|
+
def teardown blk=nil, &block
|
101
|
+
@teardowns << mk_block(blk, block)
|
102
|
+
end
|
76
103
|
|
77
104
|
def transition trs_hshes, &block
|
78
105
|
trs_hshes.each do | from, to |
|
@@ -83,37 +110,47 @@ module Lab42
|
|
83
110
|
private
|
84
111
|
def current_transition; [@old_state, @state] end
|
85
112
|
|
86
|
-
def get_behavior block1, block2
|
87
|
-
raise ArgumentError, "need exactly one block ( or symbol )" unless !!block1 != !!block2
|
88
|
-
mk_block block1 || block2
|
89
|
-
end
|
90
|
-
|
91
113
|
def initialize state_machine
|
92
114
|
@sm = state_machine
|
93
115
|
@old_state = nil
|
94
116
|
@state = :init
|
95
117
|
|
96
|
-
@setups
|
97
|
-
@teardowns
|
98
|
-
@afters
|
99
|
-
@befores
|
100
|
-
@
|
101
|
-
@
|
102
|
-
@transitions = mk_ary_hash
|
118
|
+
@setups = []
|
119
|
+
@teardowns = []
|
120
|
+
@afters = []
|
121
|
+
@befores = []
|
122
|
+
@handlers = mk_ary_hash
|
123
|
+
@transitions = mk_ary_hash
|
103
124
|
end
|
104
125
|
|
105
|
-
def
|
106
|
-
|
126
|
+
def mk_ary_hash; Hash.new{ |h,k| h[k] = [] } end
|
127
|
+
|
128
|
+
def mk_block block, blk
|
129
|
+
raise ArgumentError, "Need a block or a proc param" unless !!block != !!blk
|
130
|
+
case b = block || blk
|
107
131
|
when Proc, Method
|
108
|
-
|
109
|
-
when Symbol
|
110
|
-
@sm.method
|
132
|
+
b
|
133
|
+
when Symbol
|
134
|
+
@sm.method b
|
111
135
|
else
|
112
|
-
|
136
|
+
raise ArgumentError, "Cannot create a proc or method from #{b}"
|
113
137
|
end
|
114
138
|
end
|
115
139
|
|
116
|
-
def
|
140
|
+
def mk_input_stream input
|
141
|
+
case input
|
142
|
+
when Enumerable, Enumerator
|
143
|
+
@stream = input.lazy
|
144
|
+
else
|
145
|
+
raise ArgumentError, "cannot enumerate on object #{input}"
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def peek_first
|
150
|
+
@__peek_first__ ||= stream.peek
|
151
|
+
rescue StopIteration
|
152
|
+
nil
|
153
|
+
end
|
117
154
|
end # class Controller
|
118
155
|
end # class StateMachine
|
119
156
|
end # module Lab42
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'forwarder'
|
2
|
+
module Lab42
|
3
|
+
class StateMachine
|
4
|
+
class Controller
|
5
|
+
module StreamApi
|
6
|
+
|
7
|
+
extend Forwarder
|
8
|
+
forward :rewind, to: :stream
|
9
|
+
|
10
|
+
class ::Proc
|
11
|
+
def negated
|
12
|
+
->(*args, &blk){ !self.(*args, &blk) }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def drop_until &condition
|
17
|
+
@stream = stream.drop_while( &condition.negated )
|
18
|
+
end
|
19
|
+
def drop_until! &condition
|
20
|
+
drop_until( &condition )
|
21
|
+
@sm.skip
|
22
|
+
end
|
23
|
+
|
24
|
+
def drop_while &condition
|
25
|
+
@stream = stream.drop_while( &condition )
|
26
|
+
end
|
27
|
+
def drop_while! &condition
|
28
|
+
drop_while( &condition )
|
29
|
+
@sm.skip
|
30
|
+
end
|
31
|
+
|
32
|
+
def rewind!
|
33
|
+
rewind
|
34
|
+
@sm.skip
|
35
|
+
end
|
36
|
+
end # module StreamApi
|
37
|
+
end # class Controller
|
38
|
+
end # class StateMachine
|
39
|
+
end # module Lab42
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lab42_state_machine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Dober
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-09-
|
11
|
+
date: 2013-09-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: forwarder19
|
@@ -60,6 +60,7 @@ extra_rdoc_files: []
|
|
60
60
|
files:
|
61
61
|
- lib/lab42/state_machine/version.rb
|
62
62
|
- lib/lab42/state_machine/controller.rb
|
63
|
+
- lib/lab42/state_machine/controller/stream_api.rb
|
63
64
|
- lib/lab42/state_machine.rb
|
64
65
|
- LICENSE
|
65
66
|
- README.md
|