state-fu 0.11.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/LICENSE +40 -0
- data/README.textile +293 -0
- data/Rakefile +114 -0
- data/lib/binding.rb +292 -0
- data/lib/event.rb +192 -0
- data/lib/executioner.rb +120 -0
- data/lib/hooks.rb +39 -0
- data/lib/interface.rb +132 -0
- data/lib/lathe.rb +538 -0
- data/lib/machine.rb +184 -0
- data/lib/method_factory.rb +243 -0
- data/lib/persistence.rb +116 -0
- data/lib/persistence/active_record.rb +34 -0
- data/lib/persistence/attribute.rb +47 -0
- data/lib/persistence/base.rb +100 -0
- data/lib/persistence/relaxdb.rb +23 -0
- data/lib/persistence/session.rb +7 -0
- data/lib/sprocket.rb +58 -0
- data/lib/state-fu.rb +56 -0
- data/lib/state.rb +48 -0
- data/lib/support/active_support_lite/array.rb +9 -0
- data/lib/support/active_support_lite/array/access.rb +60 -0
- data/lib/support/active_support_lite/array/conversions.rb +202 -0
- data/lib/support/active_support_lite/array/extract_options.rb +21 -0
- data/lib/support/active_support_lite/array/grouping.rb +109 -0
- data/lib/support/active_support_lite/array/random_access.rb +13 -0
- data/lib/support/active_support_lite/array/wrapper.rb +25 -0
- data/lib/support/active_support_lite/blank.rb +67 -0
- data/lib/support/active_support_lite/cattr_reader.rb +57 -0
- data/lib/support/active_support_lite/keys.rb +57 -0
- data/lib/support/active_support_lite/misc.rb +59 -0
- data/lib/support/active_support_lite/module.rb +1 -0
- data/lib/support/active_support_lite/module/delegation.rb +130 -0
- data/lib/support/active_support_lite/object.rb +9 -0
- data/lib/support/active_support_lite/string.rb +38 -0
- data/lib/support/active_support_lite/symbol.rb +16 -0
- data/lib/support/applicable.rb +41 -0
- data/lib/support/arrays.rb +197 -0
- data/lib/support/core_ext.rb +90 -0
- data/lib/support/exceptions.rb +106 -0
- data/lib/support/has_options.rb +16 -0
- data/lib/support/logger.rb +165 -0
- data/lib/support/methodical.rb +17 -0
- data/lib/support/no_stdout.rb +55 -0
- data/lib/support/plotter.rb +62 -0
- data/lib/support/vizier.rb +300 -0
- data/lib/tasks/spec_last.rake +55 -0
- data/lib/tasks/state_fu.rake +57 -0
- data/lib/transition.rb +338 -0
- data/lib/transition_query.rb +224 -0
- data/spec/custom_formatter.rb +49 -0
- data/spec/features/binding_and_transition_helper_mixin_spec.rb +111 -0
- data/spec/features/method_missing_only_once_spec.rb +28 -0
- data/spec/features/not_requirements_spec.rb +118 -0
- data/spec/features/plotter_spec.rb +97 -0
- data/spec/features/shared_log_spec.rb +7 -0
- data/spec/features/singleton_machine_spec.rb +39 -0
- data/spec/features/state_and_array_options_accessor_spec.rb +47 -0
- data/spec/features/transition_boolean_comparison_spec.rb +101 -0
- data/spec/helper.rb +13 -0
- data/spec/integration/active_record_persistence_spec.rb +202 -0
- data/spec/integration/binding_extension_spec.rb +41 -0
- data/spec/integration/class_accessor_spec.rb +117 -0
- data/spec/integration/event_definition_spec.rb +74 -0
- data/spec/integration/example_01_document_spec.rb +133 -0
- data/spec/integration/example_02_string_spec.rb +88 -0
- data/spec/integration/instance_accessor_spec.rb +97 -0
- data/spec/integration/lathe_extension_spec.rb +67 -0
- data/spec/integration/machine_duplication_spec.rb +101 -0
- data/spec/integration/relaxdb_persistence_spec.rb +97 -0
- data/spec/integration/requirement_reflection_spec.rb +270 -0
- data/spec/integration/state_definition_spec.rb +163 -0
- data/spec/integration/transition_spec.rb +1033 -0
- data/spec/spec.opts +9 -0
- data/spec/spec_helper.rb +132 -0
- data/spec/state_fu_spec.rb +948 -0
- data/spec/units/binding_spec.rb +192 -0
- data/spec/units/event_spec.rb +214 -0
- data/spec/units/exceptions_spec.rb +82 -0
- data/spec/units/lathe_spec.rb +570 -0
- data/spec/units/machine_spec.rb +229 -0
- data/spec/units/method_factory_spec.rb +366 -0
- data/spec/units/sprocket_spec.rb +69 -0
- data/spec/units/state_spec.rb +59 -0
- metadata +171 -0
@@ -0,0 +1,570 @@
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../helper")
|
2
|
+
|
3
|
+
describe StateFu::Lathe do
|
4
|
+
include MySpecHelper
|
5
|
+
|
6
|
+
before do
|
7
|
+
reset!
|
8
|
+
make_pristine_class('Klass')
|
9
|
+
@machine = StateFu::Machine.new()
|
10
|
+
@state = Object.new()
|
11
|
+
@event = Object.new()
|
12
|
+
|
13
|
+
stub(@machine).tools() { [].extend( StateFu::ToolArray ) }
|
14
|
+
@lathe = StateFu::Lathe.new( @machine )
|
15
|
+
@states = [].extend StateFu::StateArray
|
16
|
+
stub( @machine ).states() { @states }
|
17
|
+
@events = [].extend StateFu::EventArray
|
18
|
+
stub( @machine ).events() { @events }
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "constructor" do
|
22
|
+
it "should create a new Lathe given valid arguments" do
|
23
|
+
lathe = StateFu::Lathe.new( @machine )
|
24
|
+
lathe.should be_kind_of( StateFu::Lathe )
|
25
|
+
lathe.machine.should == @machine
|
26
|
+
lathe.state_or_event.should == nil
|
27
|
+
lathe.options.should == {}
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should accept a state_or_event (state / event ) and if given one, be a child" do
|
31
|
+
options = {}
|
32
|
+
mock( @state ).apply!( options ) {}
|
33
|
+
lathe = StateFu::Lathe.new( @machine, @state )
|
34
|
+
lathe.should be_kind_of( StateFu::Lathe )
|
35
|
+
lathe.machine.should == @machine
|
36
|
+
lathe.state_or_event.should == @state
|
37
|
+
lathe.options.should == {}
|
38
|
+
lathe.should be_child
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "lathe instance with no state_or_event (master lathe for a machine)" do
|
43
|
+
before do
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should be master?" do
|
47
|
+
@lathe.should be_master
|
48
|
+
@lathe.should_not be_child
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "defining a state with .state" do
|
52
|
+
|
53
|
+
it "should add a state to the lathe's machine.states if the named state does not exist" do
|
54
|
+
@lathe.state( :wibble )
|
55
|
+
@machine.states.should_not be_empty
|
56
|
+
@machine.states.length.should == 1
|
57
|
+
s = @machine.states.first
|
58
|
+
s.should be_kind_of( StateFu::State )
|
59
|
+
s.name.should == :wibble
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should create a child lathe and apply the options and block if supplied" do
|
63
|
+
options = {:banana => :flower}
|
64
|
+
@state = Object.new()
|
65
|
+
@child = Object.new()
|
66
|
+
# can't mock the block :(
|
67
|
+
mock( StateFu::State ).new( @machine, :wobble, options ) { @state }
|
68
|
+
mock( StateFu::Lathe ).new( @machine, @state, options ) { @child }
|
69
|
+
mock( @child )
|
70
|
+
@lathe.state( :wobble, options )
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should update the named state if it exists" do
|
74
|
+
@lathe.state( :wibble, { :nick => :wobble } )
|
75
|
+
@machine.states.should_not be_empty
|
76
|
+
@machine.states.length.should == 1
|
77
|
+
s = @machine.states.first
|
78
|
+
@lathe.state( :wibble, { :meta => :voodoo } ).should == s
|
79
|
+
s.options[:meta].should == :voodoo
|
80
|
+
s.options[:nick].should == :wobble
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should return the named state" do
|
84
|
+
s = @lathe.state( :wibble, { :nick => :wobble } )
|
85
|
+
s.should be_kind_of( StateFu::State )
|
86
|
+
s.name.should == :wibble
|
87
|
+
end
|
88
|
+
end # .state
|
89
|
+
|
90
|
+
describe "defining multiple states with .states" do
|
91
|
+
|
92
|
+
it "should add all states named to the machine if they dont exist" do
|
93
|
+
@lathe.states :a, :b, :c, {:group => :alphabet} do
|
94
|
+
requires :jackson_five
|
95
|
+
end
|
96
|
+
@machine.states.length.should == 3
|
97
|
+
@machine.states.map(&:name).should == [:a, :b, :c]
|
98
|
+
@machine.states.each {|s| s.options[:group].should == :alphabet }
|
99
|
+
@machine.states.each {|s| s.entry_requirements.should include(:jackson_five) }
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should apply the block / options to each named state if it already exists" do
|
103
|
+
@lathe.state :lemon do
|
104
|
+
requires :squinty_face
|
105
|
+
end
|
106
|
+
@lathe.states :mango, :orange, :lemon, {:group => :fruit } do
|
107
|
+
requires :knife
|
108
|
+
on_entry :peel
|
109
|
+
end
|
110
|
+
@lathe.states :orange, :lemon, :mandarin, { :type => :citrus } do
|
111
|
+
requires :juicer
|
112
|
+
on_entry :juice
|
113
|
+
end
|
114
|
+
states = @machine.states
|
115
|
+
states[:mango ].options.should == { :group => :fruit }
|
116
|
+
states[:lemon ].options.should == { :group => :fruit, :type => :citrus }
|
117
|
+
states[:mandarin].options.should == { :type => :citrus }
|
118
|
+
states[:mango ].entry_requirements.should == [:knife]
|
119
|
+
states[:lemon ].entry_requirements.should == [:squinty_face, :knife, :juicer]
|
120
|
+
states[:mandarin].entry_requirements.should == [:juicer]
|
121
|
+
states[:mango ].hooks[:entry].should == [:peel]
|
122
|
+
states[:lemon ].hooks[:entry].should == [:peel, :juice]
|
123
|
+
states[:mandarin].hooks[:entry].should == [:juice]
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should apply to all existing states given :ALL" do
|
127
|
+
@lathe.states :hot, :cold
|
128
|
+
names = []
|
129
|
+
@lathe.states :ALL do |s|
|
130
|
+
names << s.name
|
131
|
+
end
|
132
|
+
names.should == [:hot, :cold]
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should apply to all existing states given no arguments" do
|
136
|
+
@lathe.states :hot, :cold
|
137
|
+
names = []
|
138
|
+
@lathe.states do |s|
|
139
|
+
names << s.name
|
140
|
+
end
|
141
|
+
names.should == [:hot, :cold]
|
142
|
+
end
|
143
|
+
|
144
|
+
# TODO
|
145
|
+
it "should apply to all existing states except those named given :except => [...]" do
|
146
|
+
@lathe.states :hot, :cold, :warm
|
147
|
+
|
148
|
+
names = []
|
149
|
+
@lathe.states :ALL, :except => :warm do |s|
|
150
|
+
names << s.name
|
151
|
+
end
|
152
|
+
names.should == [:hot, :cold]
|
153
|
+
|
154
|
+
names = []
|
155
|
+
@lathe.states :ALL, :except => [:hot, :cold] do |s|
|
156
|
+
names << s.name
|
157
|
+
end
|
158
|
+
names.should == [:warm]
|
159
|
+
end
|
160
|
+
|
161
|
+
it "should return an array of states with extensions" do
|
162
|
+
x = @lathe.states :hot, :cold, :warm
|
163
|
+
x.should be_kind_of( Array )
|
164
|
+
x.length.should == 3
|
165
|
+
x.each {|e| e.should be_kind_of( StateFu::State ) }
|
166
|
+
x.map(&:name).should == [:hot, :cold, :warm]
|
167
|
+
x.except(:warm).map(&:name).should == [:hot, :cold]
|
168
|
+
end
|
169
|
+
end # states
|
170
|
+
|
171
|
+
describe "defining an event with .event" do
|
172
|
+
|
173
|
+
it "should add a event to the lathe's machine.events if the named event does not exist" do
|
174
|
+
@lathe.event( :wibble )
|
175
|
+
@machine.events.should_not be_empty
|
176
|
+
@machine.events.length.should == 1
|
177
|
+
s = @machine.events.first
|
178
|
+
s.should be_kind_of( StateFu::Event )
|
179
|
+
s.name.should == :wibble
|
180
|
+
end
|
181
|
+
|
182
|
+
it "should create a child lathe and apply the options and block if supplied" do
|
183
|
+
options = {:banana => :flower}
|
184
|
+
@event = Object.new()
|
185
|
+
@child = Object.new()
|
186
|
+
# can't mock the block :(
|
187
|
+
mock( StateFu::Event ).new( @machine, :wobble, options ) { @event }
|
188
|
+
mock( StateFu::Lathe ).new( @machine, @event, options ) { @child }
|
189
|
+
mock( @child )
|
190
|
+
@lathe.event( :wobble, options )
|
191
|
+
end
|
192
|
+
|
193
|
+
it "should update the named event if it exists" do
|
194
|
+
@lathe.event( :wibble )
|
195
|
+
@machine.events.should_not be_empty
|
196
|
+
@machine.events.length.should == 1
|
197
|
+
s = @machine.events.first
|
198
|
+
@lathe.event( :wibble, { :meta => :voodoo } ).should == s
|
199
|
+
s.options[:meta].should == :voodoo
|
200
|
+
end
|
201
|
+
|
202
|
+
it "should create states mentioned in the event definition and add them to machine.states" do
|
203
|
+
@machine = StateFu::Machine.new( :snoo )
|
204
|
+
@lathe = StateFu::Lathe.new( @machine )
|
205
|
+
@lathe.event(:wobble, :from => [:a, :b], :to => :c )
|
206
|
+
@machine.events.should_not be_empty
|
207
|
+
@machine.events.length.should == 1
|
208
|
+
@machine.events.first.name.should == :wobble
|
209
|
+
@machine.states.length.should == 3
|
210
|
+
@machine.states.map(&:name).sort_by {|x| x.to_s }.should == [ :a, :b, :c]
|
211
|
+
@machine.events[:wobble].origins.map(&:name).should == [:a,:b]
|
212
|
+
@machine.events[:wobble].targets.map(&:name).should == [:c]
|
213
|
+
end
|
214
|
+
|
215
|
+
it "should allow definition of events using :from => {*origin => *target}" do
|
216
|
+
@machine = StateFu::Machine.new( :hash_it_up )
|
217
|
+
@lathe = StateFu::Lathe.new( @machine )
|
218
|
+
e = @lathe.event(:snooze, :from => { :nine => :ten } )
|
219
|
+
e.name.should == :snooze
|
220
|
+
e.origins.length.should == 1
|
221
|
+
e.origin.name.should == :nine
|
222
|
+
e.targets.length.should == 1
|
223
|
+
e.target.name.should == :ten
|
224
|
+
end
|
225
|
+
|
226
|
+
end # .event
|
227
|
+
|
228
|
+
describe "defining multiple events with .events" do
|
229
|
+
|
230
|
+
it "should add all events named to the machine if they dont exist" do
|
231
|
+
@lathe.event :tickle
|
232
|
+
@lathe.events :hit, :smack, :punch, {:group => :acts_of_violence} do
|
233
|
+
requires :strong_stomach
|
234
|
+
end
|
235
|
+
e = @machine.events
|
236
|
+
e.length.should == 4
|
237
|
+
e.map(&:name).should == [:tickle, :hit, :smack, :punch]
|
238
|
+
e[:tickle].options[:group].should == nil
|
239
|
+
e[:punch ].options[:group].should == :acts_of_violence
|
240
|
+
e[:tickle].requirements.should == []
|
241
|
+
e[:punch ].requirements.should == [:strong_stomach]
|
242
|
+
end
|
243
|
+
|
244
|
+
it "should apply the block / options to each named event if it already exists" do
|
245
|
+
@lathe.event :fart, { :socially_acceptable => false } do
|
246
|
+
requires :tilt_to_one_side
|
247
|
+
after :inhale_through_nose
|
248
|
+
end
|
249
|
+
|
250
|
+
@lathe.event :smile, { :socially_acceptable => true } do
|
251
|
+
requires :teeth
|
252
|
+
after :close_mouth
|
253
|
+
end
|
254
|
+
|
255
|
+
@lathe.events :smile, :fart, { :group => :human_actions } do
|
256
|
+
requires :corporeal_body, :free_will
|
257
|
+
after :blink
|
258
|
+
end
|
259
|
+
e = @machine.events
|
260
|
+
e[:fart].options[:socially_acceptable].should == false
|
261
|
+
e[:smile].options[:socially_acceptable].should == true
|
262
|
+
e[:fart].requirements.should == [:tilt_to_one_side, :corporeal_body, :free_will]
|
263
|
+
e[:smile].requirements.should == [:teeth, :corporeal_body, :free_will]
|
264
|
+
e[:fart].hooks[:after].should == [:inhale_through_nose, :blink]
|
265
|
+
e[:smile].hooks[:after].should == [:close_mouth, :blink]
|
266
|
+
end
|
267
|
+
|
268
|
+
it "should apply to all existing events given :ALL" do
|
269
|
+
@lathe.events :spit, :run
|
270
|
+
names = []
|
271
|
+
@lathe.events :ALL do |s|
|
272
|
+
names << s.name
|
273
|
+
end
|
274
|
+
names.should == [:spit, :run]
|
275
|
+
end
|
276
|
+
|
277
|
+
it "should apply to all existing events given no arguments" do
|
278
|
+
@lathe.events :dance, :juggle
|
279
|
+
names = []
|
280
|
+
@lathe.events do |s|
|
281
|
+
names << s.name
|
282
|
+
end
|
283
|
+
names.should == [:dance, :juggle]
|
284
|
+
end
|
285
|
+
|
286
|
+
# TODO
|
287
|
+
it "should apply to all existing events except those named given :except => [...]" do
|
288
|
+
@lathe.events :wink, :bow, :salute
|
289
|
+
|
290
|
+
names = []
|
291
|
+
@lathe.events :ALL, :except => :salute do |s|
|
292
|
+
names << s.name
|
293
|
+
end
|
294
|
+
names.should == [:wink, :bow]
|
295
|
+
|
296
|
+
names = []
|
297
|
+
@lathe.events :ALL, :except => [:bow, :wink] do |s|
|
298
|
+
names << s.name
|
299
|
+
end
|
300
|
+
names.should == [:salute]
|
301
|
+
|
302
|
+
end
|
303
|
+
|
304
|
+
end # events
|
305
|
+
|
306
|
+
describe "initial_state" do
|
307
|
+
|
308
|
+
it "should set the initial state to its argument, creating if it does not exist" do
|
309
|
+
@machine.instance_eval do
|
310
|
+
class << self
|
311
|
+
attr_accessor :initial_state
|
312
|
+
end
|
313
|
+
end
|
314
|
+
@machine.states.should be_empty
|
315
|
+
@lathe.initial_state :bambi
|
316
|
+
@machine.states.should_not be_empty
|
317
|
+
@machine.states.length.should == 1
|
318
|
+
@machine.states.first.name.should == :bambi
|
319
|
+
@machine.initial_state.name.should == :bambi
|
320
|
+
@lathe.initial_state :thumper
|
321
|
+
@machine.states.length.should == 2
|
322
|
+
@machine.states.map(&:name).should == [:bambi, :thumper]
|
323
|
+
@machine.states.last.name.should == :thumper
|
324
|
+
@machine.initial_state.name.should == :thumper
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
describe "helper" do
|
329
|
+
it "should call machine.helper *args" do
|
330
|
+
mock( @machine ).helper( :fee, :fi, :fo, :fum )
|
331
|
+
@lathe.helper( :fee, :fi, :fo, :fum )
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
end # master lathe instance
|
336
|
+
|
337
|
+
# child lathe - created and yielded within nested blocks in a
|
338
|
+
# machine definition
|
339
|
+
describe "a child lathe for a state" do
|
340
|
+
before do
|
341
|
+
@master = @lathe
|
342
|
+
@state = @lathe.state(:a)
|
343
|
+
@lathe = StateFu::Lathe.new( @machine, @state )
|
344
|
+
end
|
345
|
+
|
346
|
+
describe ".cycle( evt_name )" do
|
347
|
+
before do
|
348
|
+
@machine = StateFu::Machine.new( :snoo )
|
349
|
+
@master = StateFu::Lathe.new( @machine )
|
350
|
+
@state = @master.state(:a)
|
351
|
+
@lathe = StateFu::Lathe.new( @machine, @state )
|
352
|
+
end
|
353
|
+
|
354
|
+
it "should create a named event from and to the lathe's state_or_event (state)" do
|
355
|
+
|
356
|
+
@machine.events.should be_empty
|
357
|
+
@machine.states.length.should == 1
|
358
|
+
@lathe.cycle(:rebirth)
|
359
|
+
@machine.events.should_not be_empty
|
360
|
+
@machine.states.length.should == 1
|
361
|
+
cycle = @machine.events.first
|
362
|
+
cycle.should be_kind_of( StateFu::Event )
|
363
|
+
cycle.origins.should == [@state]
|
364
|
+
cycle.targets.should == [@state]
|
365
|
+
end
|
366
|
+
|
367
|
+
it "should create an event with a default name if given no name" do
|
368
|
+
@machine.events.should be_empty
|
369
|
+
@machine.states.length.should == 1
|
370
|
+
@lathe.cycle
|
371
|
+
@machine.events.should_not be_empty
|
372
|
+
@machine.states.length.should == 1
|
373
|
+
e = @machine.events.first
|
374
|
+
e.name.should == :cycle_a
|
375
|
+
e.origins.should == [@state]
|
376
|
+
e.targets.should == [@state]
|
377
|
+
end
|
378
|
+
|
379
|
+
end
|
380
|
+
|
381
|
+
describe ".event(:name)" do
|
382
|
+
before do
|
383
|
+
mock( @machine ).find_or_create_states_by_name( @lathe.state_or_event ).at_least(1) { @lathe.state_or_event }
|
384
|
+
end
|
385
|
+
|
386
|
+
it "should create the named event if it does not exist" do
|
387
|
+
@machine.events.should be_empty
|
388
|
+
@lathe.event(:poop)
|
389
|
+
@machine.events.should_not be_empty
|
390
|
+
@machine.events[:poop].should be_kind_of( StateFu::Event )
|
391
|
+
end
|
392
|
+
|
393
|
+
it "should update the named event if it does exist" do
|
394
|
+
@lathe.machine.should == @machine
|
395
|
+
@lathe.event(:poop)
|
396
|
+
@machine.events[:poop].options.should == {}
|
397
|
+
@lathe.event(:poop, :lick => :me )
|
398
|
+
@machine.events[:poop].options[:lick].should == :me
|
399
|
+
end
|
400
|
+
|
401
|
+
it "should yield a created event given a block with arity 1" do
|
402
|
+
@machine.events.length.should == 0
|
403
|
+
@lathe.event(:poop) do |e| # yield the event
|
404
|
+
e.should be_kind_of( StateFu::Event )
|
405
|
+
e.name.should == :poop
|
406
|
+
e.options[:called] = true
|
407
|
+
end
|
408
|
+
@machine.events.length.should == 1
|
409
|
+
e = @machine.events[:poop]
|
410
|
+
e.options[:called].should == true
|
411
|
+
end
|
412
|
+
|
413
|
+
end
|
414
|
+
|
415
|
+
describe ".requires()" do
|
416
|
+
|
417
|
+
before do
|
418
|
+
@state.exit_requirements.should == []
|
419
|
+
@state.entry_requirements.should == []
|
420
|
+
end
|
421
|
+
|
422
|
+
it "should add :method_name to state.entry_requirements given a name" do
|
423
|
+
@lathe.requires( :method_name )
|
424
|
+
@state.entry_requirements.should == [:method_name]
|
425
|
+
@state.exit_requirements.should == []
|
426
|
+
end
|
427
|
+
|
428
|
+
|
429
|
+
it "should add :method_name to state.entry_requirements given a name and :on => :exit" do
|
430
|
+
@lathe.requires( :method_name, :on => :exit )
|
431
|
+
@state.exit_requirements.should == [:method_name]
|
432
|
+
@state.entry_requirements.should == []
|
433
|
+
end
|
434
|
+
|
435
|
+
it "should add :method_name to entry_requirements and exit_requirements given a name and :on => [:entry, :exit]" do
|
436
|
+
@lathe.requires( :method_name, :on => [:entry, :exit] )
|
437
|
+
@state.exit_requirements.should == [:method_name]
|
438
|
+
@state.entry_requirements.should == [:method_name]
|
439
|
+
end
|
440
|
+
|
441
|
+
it "should add multiple method_names if more than one is given" do
|
442
|
+
@lathe.requires( :method_one, :method_two )
|
443
|
+
@lathe.requires( :method_three, :method_four, :on => [:exit] )
|
444
|
+
@state.entry_requirements.should == [:method_one, :method_two]
|
445
|
+
@state.exit_requirements.should == [:method_three, :method_four]
|
446
|
+
end
|
447
|
+
|
448
|
+
it "should add to machine.named_procs if a block is given" do
|
449
|
+
class << @machine
|
450
|
+
attr_accessor :named_procs
|
451
|
+
end
|
452
|
+
@machine.named_procs = {}
|
453
|
+
block = lambda { puts "wee" }
|
454
|
+
@machine.named_procs.should == {}
|
455
|
+
@lathe.requires( :method_name, :on => [:entry, :exit], &block )
|
456
|
+
@state.exit_requirements.should == [:method_name]
|
457
|
+
@state.entry_requirements.should == [:method_name]
|
458
|
+
@machine.named_procs[:method_name].should == block
|
459
|
+
end
|
460
|
+
|
461
|
+
it "should add a message to machine.requirement_messages if a string is given" do
|
462
|
+
class << @machine
|
463
|
+
attr_accessor :requirement_messages
|
464
|
+
end
|
465
|
+
@machine.requirement_messages = {}
|
466
|
+
@lathe.requires( :method_one, :message => "Method one says no soup for you!" )
|
467
|
+
@machine.should respond_to(:requirement_messages)
|
468
|
+
@machine.requirement_messages.keys.should == [:method_one]
|
469
|
+
@machine.requirement_messages.values.first.should be_kind_of( String )
|
470
|
+
end
|
471
|
+
|
472
|
+
end
|
473
|
+
end # a child lathe for a state
|
474
|
+
|
475
|
+
describe "a child lathe for an event" do
|
476
|
+
before do
|
477
|
+
@master = @lathe
|
478
|
+
@event = @lathe.event( :go )
|
479
|
+
@lathe = StateFu::Lathe.new( @machine, @event )
|
480
|
+
stub( @machine ).find_or_create_states_by_name(:a) { [:a] }
|
481
|
+
stub( @machine ).find_or_create_states_by_name(:b) { [:b] }
|
482
|
+
end
|
483
|
+
|
484
|
+
describe ".from" do
|
485
|
+
it "should create any states mentioned which do not exist" do
|
486
|
+
mock( @machine ).find_or_create_states_by_name(:a, :b) { [:a, :b] }
|
487
|
+
@lathe.from( :a, :b )
|
488
|
+
end
|
489
|
+
|
490
|
+
it "should set the origins to the result of machine.find_or_create_states_by_name" do
|
491
|
+
mock( @machine ).find_or_create_states_by_name(:a, :b) { [:a, :b] }
|
492
|
+
@lathe.from( :a, :b )
|
493
|
+
@event.origins.should == [:a, :b]
|
494
|
+
end
|
495
|
+
|
496
|
+
it "should accumulate @origins on successive invocations" do
|
497
|
+
mock( @machine ).find_or_create_states_by_name(:a, :b) { [:a, :b] }
|
498
|
+
mock( @machine ).find_or_create_states_by_name(:x, :y) { [:x, :y] }
|
499
|
+
@lathe.from( :a, :b )
|
500
|
+
@event.origins.should == [:a, :b]
|
501
|
+
@lathe.from( :x, :y )
|
502
|
+
@event.origins.should == [:a, :b, :x, :y]
|
503
|
+
end
|
504
|
+
|
505
|
+
it "should set / update both origin and target if a hash is given" do
|
506
|
+
mock( @machine ).find_or_create_states_by_name(:a) { [:a] }
|
507
|
+
mock( @machine ).find_or_create_states_by_name(:b) { [:b] }
|
508
|
+
mock( @machine ).find_or_create_states_by_name(:a, :b) { [:a, :b] }
|
509
|
+
mock( @machine ).find_or_create_states_by_name(:x, :y) { [:x, :y] }
|
510
|
+
@lathe.from( :a => :b )
|
511
|
+
@event.origin.should == :a
|
512
|
+
@event.target.should == :b
|
513
|
+
@lathe.from( { [:a, :b] => [:x, :y] })
|
514
|
+
@event.origin.should == nil
|
515
|
+
@event.target.should == nil
|
516
|
+
@event.origins.should == [:a, :b]
|
517
|
+
@event.targets.should == [:b, :x, :y] # accumulated total
|
518
|
+
end
|
519
|
+
end
|
520
|
+
|
521
|
+
describe ".to" do
|
522
|
+
it "should create any states mentioned which do not exist" do
|
523
|
+
mock( @machine ).find_or_create_states_by_name(:a, :b) { [:a, :b] }
|
524
|
+
@lathe.to( :a, :b )
|
525
|
+
end
|
526
|
+
|
527
|
+
it "should set the targets to the result of machine.find_or_create_states_by_name" do
|
528
|
+
mock( @machine ).find_or_create_states_by_name(:a, :b) { [:a, :b] }
|
529
|
+
@lathe.to( :a, :b )
|
530
|
+
@event.targets.should == [:a, :b]
|
531
|
+
end
|
532
|
+
|
533
|
+
it "should update @origins on successive invocations" do
|
534
|
+
mock( @machine ).find_or_create_states_by_name(:a, :b) { [:a, :b] }
|
535
|
+
mock( @machine ).find_or_create_states_by_name(:x, :y) { [:x, :y] }
|
536
|
+
@lathe.to( :a, :b )
|
537
|
+
@event.targets.should == [:a, :b]
|
538
|
+
@lathe.to( :x, :y )
|
539
|
+
@event.targets.should == [:a, :b, :x, :y] # accumulated targets
|
540
|
+
end
|
541
|
+
end
|
542
|
+
|
543
|
+
describe ".requires()" do
|
544
|
+
|
545
|
+
before do
|
546
|
+
@event.requirements.should == []
|
547
|
+
end
|
548
|
+
|
549
|
+
it "should add :method_name to event.requirements given a name" do
|
550
|
+
@lathe.requires( :method_name )
|
551
|
+
@event.requirements.should == [:method_name]
|
552
|
+
end
|
553
|
+
|
554
|
+
it "should add to machine.named_procs if a block is given" do
|
555
|
+
class << @machine
|
556
|
+
attr_accessor :named_procs
|
557
|
+
end
|
558
|
+
@machine.named_procs = {}
|
559
|
+
block = lambda { puts "wee" }
|
560
|
+
@machine.named_procs.should == {}
|
561
|
+
@lathe.requires( :method_name, &block )
|
562
|
+
@event.requirements.should == [:method_name]
|
563
|
+
@machine.named_procs[:method_name].should == block
|
564
|
+
end
|
565
|
+
|
566
|
+
end # requires
|
567
|
+
|
568
|
+
end # a child lathe for an event
|
569
|
+
|
570
|
+
end
|