lab42_state_machine 0.1.2 → 0.2.0
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/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
|