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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7794b97f4ada35102cd112f803d049df99e0fcdb
4
- data.tar.gz: 5f3f4276da47d24c629f57c9f4e957c9b84e0e21
3
+ metadata.gz: 1a04c2bcbca5f354f981c2f929f862ca3dde8d20
4
+ data.tar.gz: 28f8f7ab95247ebbe85b8f0738e7971642e42d20
5
5
  SHA512:
6
- metadata.gz: 1c5c90bb25e28f7585981f0557ead12e9a2231dc51c47e326d29a7170620b17537b36dfd4bec0fd3ab499b85d13bc222a5d940c91ccd9bc4c36627e8e2aa095f
7
- data.tar.gz: 256aef995922fbba3c09d5380f3152fd3d343e7c7418d8566ce94a8c0bbf12edfcdabf6030ae501daee63314f68af7074a84d4da2856a58c7aa6a946ffaa6986
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
- `state\_machine.state :reset do @counter = 0 end`
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.
@@ -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
- inputs = __make_inputs__ input
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
- def after block=nil, &blk
6
- behavior = get_behavior block, blk
7
- @afters << behavior
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 block=nil, &blk
11
- behavior = get_behavior block, blk
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
- @current_input = input
17
- run_befores
18
- run_states
19
- run_transitions
20
- run_afters
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 input
58
+ def run_setups
38
59
  @setups.each do | block |
39
- @sm.instance_exec( input, &block )
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( input, @state, &teardown )
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 block=nil, &blk
64
- behavior = get_behavior block, blk
65
- @setups << behavior
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; @teardowns << block end
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
- @before_first = []
101
- @handlers = mk_ary_hash
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 mk_block blocky
106
- case blocky
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
- blocky
109
- when Symbol, String
110
- @sm.method blocky
132
+ b
133
+ when Symbol
134
+ @sm.method b
111
135
  else
112
- blocky.to_proc
136
+ raise ArgumentError, "Cannot create a proc or method from #{b}"
113
137
  end
114
138
  end
115
139
 
116
- def mk_ary_hash; Hash.new{ |h,k| h[k] = [] } end
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
@@ -1,5 +1,5 @@
1
1
  module Lab42
2
2
  class StateMachine
3
- Version = "0.1.2"
3
+ Version = "0.2.0"
4
4
  end # class StateMachine
5
5
  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.1.2
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-10 00:00:00.000000000 Z
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