davidlee-state-fu 0.11.0 → 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.
Files changed (51) hide show
  1. data/lib/{state_fu/binding.rb → binding.rb} +31 -33
  2. data/lib/{state_fu/event.rb → event.rb} +12 -17
  3. data/lib/{state_fu/executioner.rb → executioner.rb} +8 -19
  4. data/lib/{state_fu/hooks.rb → hooks.rb} +13 -10
  5. data/lib/{state_fu/interface.rb → interface.rb} +0 -0
  6. data/lib/{state_fu/lathe.rb → lathe.rb} +12 -2
  7. data/lib/{state_fu/machine.rb → machine.rb} +0 -0
  8. data/lib/{state_fu/method_factory.rb → method_factory.rb} +0 -0
  9. data/lib/{state_fu/persistence.rb → persistence.rb} +0 -0
  10. data/lib/{state_fu/persistence → persistence}/active_record.rb +0 -0
  11. data/lib/{state_fu/persistence → persistence}/attribute.rb +0 -0
  12. data/lib/{state_fu/persistence → persistence}/base.rb +0 -0
  13. data/lib/{state_fu/persistence → persistence}/relaxdb.rb +0 -0
  14. data/lib/{state_fu/persistence → persistence}/session.rb +0 -0
  15. data/lib/{state_fu/sprocket.rb → sprocket.rb} +0 -0
  16. data/lib/state-fu.rb +11 -52
  17. data/lib/{state_fu/state.rb → state.rb} +0 -0
  18. data/lib/{state_fu → support}/active_support_lite/array.rb +0 -0
  19. data/lib/{state_fu → support}/active_support_lite/array/access.rb +0 -0
  20. data/lib/{state_fu → support}/active_support_lite/array/conversions.rb +0 -0
  21. data/lib/{state_fu → support}/active_support_lite/array/extract_options.rb +0 -0
  22. data/lib/{state_fu → support}/active_support_lite/array/grouping.rb +0 -0
  23. data/lib/{state_fu → support}/active_support_lite/array/random_access.rb +0 -0
  24. data/lib/{state_fu → support}/active_support_lite/array/wrapper.rb +0 -0
  25. data/lib/{state_fu → support}/active_support_lite/blank.rb +0 -0
  26. data/lib/{state_fu → support}/active_support_lite/cattr_reader.rb +0 -0
  27. data/lib/{state_fu → support}/active_support_lite/keys.rb +0 -0
  28. data/lib/{state_fu → support}/active_support_lite/misc.rb +0 -0
  29. data/lib/{state_fu → support}/active_support_lite/module.rb +0 -0
  30. data/lib/{state_fu → support}/active_support_lite/module/delegation.rb +0 -0
  31. data/lib/{state_fu → support}/active_support_lite/object.rb +0 -0
  32. data/lib/{state_fu → support}/active_support_lite/string.rb +0 -0
  33. data/lib/{state_fu → support}/active_support_lite/symbol.rb +0 -0
  34. data/lib/{state_fu → support}/applicable.rb +0 -0
  35. data/lib/{state_fu → support}/arrays.rb +0 -0
  36. data/lib/{state_fu → support}/core_ext.rb +1 -0
  37. data/lib/{state_fu → support}/exceptions.rb +0 -0
  38. data/lib/{state_fu → support}/has_options.rb +0 -0
  39. data/lib/{state_fu → support}/logger.rb +0 -0
  40. data/lib/{state_fu → support}/methodical.rb +0 -0
  41. data/lib/{no_stdout.rb → support/no_stdout.rb} +0 -0
  42. data/lib/{state_fu → support}/plotter.rb +1 -1
  43. data/lib/{vizier.rb → support/vizier.rb} +0 -0
  44. data/lib/{state_fu/transition.rb → transition.rb} +5 -4
  45. data/lib/{state_fu/transition_query.rb → transition_query.rb} +44 -67
  46. data/spec/integration/state_definition_spec.rb +0 -20
  47. data/spec/integration/transition_spec.rb +1 -1
  48. data/spec/state_fu_spec.rb +127 -127
  49. metadata +47 -48
  50. data/lib/state_fu.rb +0 -1
  51. data/lib/state_fu/nil_transition.rb +0 -49
@@ -14,6 +14,9 @@ module StateFu
14
14
  result.each *a, &b
15
15
  end
16
16
 
17
+ # calling result() will cause the set of transitions to be calculated -
18
+ # the cat will then be either dead or alive; until then it's a litte from
19
+ # column A, a little from column B.
17
20
  def method_missing(method_name, *args, &block)
18
21
  if result.respond_to?(method_name, true)
19
22
  result.__send__(method_name, *args, &block)
@@ -21,46 +24,27 @@ module StateFu
21
24
  super(method_name, *args, &block)
22
25
  end
23
26
  end
24
-
25
- #
26
- #
27
- #
28
-
29
- # same as find, except that if there is more than one target for the event
30
- # and only one is valid, it will return that one.
31
- # def search(destination=nil, &block)
32
- # # use the prepared event & target if none are supplied
33
- # event, target = destination.nil? ? [options[:event], options[:target]] : parse_destination(destination)
34
- # query = for_event(event).to(target)
35
- # query.find || query.valid.singular || NilTransition.new
36
- # end
37
-
38
- # find a transition by event and optionally (optional if it can be inferred) target.
39
- def find(destination=nil, &block)
40
- # use the prepared event & target if none are supplied
41
- event, target = destination.nil? ? [options[:event], options[:target]] : parse_destination(destination)
42
- _args, _block = @args, @block
43
- returning binding.new_transition(event, target) do |transition|
44
- # return NilTransition.new if transition.nil?
45
- transition.apply!(&_block) if _block
46
- if _args
47
- transition.args = _args
48
- end
49
- end
27
+
28
+ # prepare the query with arguments / block
29
+ # so that they can be applied to the transition once one is selected
30
+ def with(*args, &block)
31
+ @args = args
32
+ @block = block if block_given?
33
+ self
50
34
  end
51
35
 
52
- # def legal?(destination=nil, &block)
53
- # # use the prepared event & target if none are supplied
54
- # event, target = destination.nil? ? [options[:event], options[:target]] : parse_destination(destination)
55
- # begin
56
- # !!search(destination, &block)
57
- # rescue IllegalTransition
58
- # false
59
- # end
36
+ # build a list of possible transition destinations ([event, target])
37
+ # without actually constructing any transition objects
38
+ # def all_destinations
39
+ # binding.events.inject([]){ |arr, evt| arr += evt.targets.map{|tgt| [evt,tgt] }; arr}.uniq
40
+ # end
41
+ #
42
+ # def all_destination_names
43
+ # all_destinations.map {|tuple| tuple.map(&:to_sym) }
60
44
  # end
61
45
 
62
46
  #
63
- #
47
+ # Chainable Filters
64
48
  #
65
49
 
66
50
  def cyclic
@@ -100,15 +84,26 @@ module StateFu
100
84
  end
101
85
 
102
86
  #
103
- #
87
+ # Means to an outcome
104
88
  #
105
89
 
106
- def only_one
90
+ # find a transition by event and optionally (optional if it can be inferred) target.
91
+ def find(destination=nil, &block)
92
+ # use the prepared event & target, and block, if none are supplied
93
+ event, target = destination.nil? ? [options[:event], options[:target]] : parse_destination(destination)
94
+ block ||= @block
95
+ returning Transition.new(binding, event, target, &block) do |transition|
96
+ if @args
97
+ transition.args = @args
98
+ end
99
+ end
100
+ end
101
+
102
+ def singular
107
103
  result.first if result.length == 1
108
104
  end
109
- alias_method :singular, :only_one
110
105
 
111
- def only_one?
106
+ def singular?
112
107
  !!singular
113
108
  end
114
109
 
@@ -131,10 +126,6 @@ module StateFu
131
126
  end
132
127
  end
133
128
 
134
- #
135
- #
136
- #
137
-
138
129
  def events
139
130
  map {|t| t.event }
140
131
  end
@@ -143,30 +134,9 @@ module StateFu
143
134
  map {|t| t.target }
144
135
  end
145
136
 
146
- def apply! # (&block
147
- result.each { |t| t.apply &block if block }
148
- end
149
-
150
- def with(*args, &block)
151
- @args = args
152
- @block = block if block_given?
153
- self
154
- end
155
-
156
- def all_destinations
157
- binding.events.inject([]){ |arr, evt| arr += evt.targets.map{|tgt| [evt,tgt] }; arr}.uniq
158
- end
159
-
160
- def all_destination_names
161
- all_destinations.map {|tuple| tuple.map(&:to_sym) }
162
- end
163
-
164
137
  private
165
138
 
166
- #
167
- # Result
168
- #
169
-
139
+ # extend result with this to provide a few conveniences
170
140
  module Result
171
141
  def states
172
142
  map(&:target).uniq.extend StateArray
@@ -179,6 +149,11 @@ module StateFu
179
149
  end
180
150
  end # Result
181
151
 
152
+ # looks a little complex because of all the places that previously set
153
+ # options can filter the set of transitions - but all it's doing is
154
+ # looping over each event, and each event's possible targets, and building
155
+ # a list of transitions.
156
+
182
157
  def result
183
158
  @result = binding.events.select do |e|
184
159
  case options[:cyclic]
@@ -193,18 +168,19 @@ module StateFu
193
168
  next if options[:event] and event != options[:event]
194
169
  returning [] do |ts|
195
170
 
196
- # TODO hmm ... "sequences" ... delete this?
171
+ # TODO hmm ... "sequences" ... undecided on these. see Event / Lathe for more detail
197
172
  if options[:sequences]
198
173
  if target = event.target_for_origin(current_state)
199
174
  ts << binding.transition([event,target], *args) unless options[:cyclic]
200
175
  end
201
176
  end
202
177
 
178
+ # build a list of transitions from the possible events and their targets
203
179
  if event.targets
204
180
  next unless event.target if options[:simple]
205
181
  event.targets.flatten.each do |target|
206
182
  next if options[:target] and target != options[:target]
207
- t = binding.new_transition( event, target, *args)
183
+ t = Transition.new(binding, event, target, *args)
208
184
  ts << t if (t.valid? or !options[:valid])
209
185
  end
210
186
  end
@@ -245,3 +221,4 @@ module StateFu
245
221
 
246
222
  end
247
223
  end
224
+
@@ -161,23 +161,3 @@ describe "Adding states to a Machine" do
161
161
  end
162
162
  end
163
163
 
164
- describe "adding events inside a state block" do
165
- before do
166
- @lambda = lambda{ Klass.state_fu_machine(){ state(:egg){ event(:hatch, :to => :chick) }}}
167
- end
168
-
169
- it "should not throw an error" do
170
- @lambda.should_not raise_error
171
- end
172
-
173
- describe "Klass.state_fu_machine(){ state(:egg){ event(:hatch, :to => :chick) }}}" do
174
- before() do
175
- Klass.state_fu_machine(){ state(:egg){ event(:hatch, :to => :chick) }}
176
- end
177
- it "should add an event :hatch to the machine" do
178
- end
179
- end
180
- end
181
-
182
-
183
-
@@ -19,7 +19,7 @@ describe StateFu::Transition do
19
19
  @abc = Alphabet.new
20
20
  evt = Alphabet.machine.events[:a_to_b]
21
21
  tgt = Alphabet.machine.states[:b]
22
- @t = @abc.stfu.new_transition(evt, tgt,
22
+ @t = StateFu::Transition.new(@abc.stfu, evt, tgt,
23
23
  :a, :b, 'c' => 'cat')
24
24
  end
25
25
 
@@ -10,17 +10,17 @@ describe "A door which opens and shuts:" do
10
10
  # class Door
11
11
  make_pristine_class('Door') do
12
12
  include StateFu
13
-
13
+
14
14
  attr_accessor :locked
15
-
15
+
16
16
  def shut
17
17
  "I don't know how to shut!"
18
18
  end
19
-
19
+
20
20
  def locked?
21
21
  !!locked
22
22
  end
23
-
23
+
24
24
  def method_missing(method_name, *args, &block)
25
25
  raise NoMethodError.new("I'm just a door!" )
26
26
  end
@@ -28,7 +28,7 @@ describe "A door which opens and shuts:" do
28
28
  machine do
29
29
  event :shut, :transitions_from => :open, :to => :closed
30
30
  event :slam, :transitions_from => :open, :to => :closed
31
- event :open, :transitions_from => :closed, :to => :open,
31
+ event :open, :transitions_from => :closed, :to => :open,
32
32
  :requires => :not_locked?,
33
33
  :message => "Sorry, it's locked."
34
34
  end
@@ -51,7 +51,7 @@ describe "A door which opens and shuts:" do
51
51
  it "have an initial state of :open, the first state defined" do
52
52
  Door.machine.initial_state.name.should == :open
53
53
  end
54
-
54
+
55
55
  it "have a requirement :not_locked? for the :open event" do
56
56
  Door.machine.events[:open].requirements.should == [:not_locked?]
57
57
  end
@@ -76,9 +76,9 @@ describe "A door which opens and shuts:" do
76
76
  before do
77
77
  @door = Door.new
78
78
  end
79
-
79
+
80
80
  describe "magic event methods" do
81
-
81
+
82
82
  it "doesn't normally have a method #shut!" do
83
83
  @door.respond_to?(:shut!).should == false
84
84
  end
@@ -86,11 +86,11 @@ describe "A door which opens and shuts:" do
86
86
  it "will define #shut! when method_missing is called for the first time" do
87
87
  begin
88
88
  @door.play_the_ukelele
89
- rescue NoMethodError
89
+ rescue NoMethodError
90
90
  end
91
- @door.respond_to?(:shut!).should == true
91
+ @door.respond_to?(:shut!).should == true
92
92
  end
93
-
93
+
94
94
  it "will keep any existing methods when method_missing is triggered" do
95
95
  @door.respond_to?(:shut).should == true
96
96
  @door.respond_to?(:can_shut?).should == false
@@ -100,7 +100,7 @@ describe "A door which opens and shuts:" do
100
100
  @door.respond_to?(:can_shut?).should == true # new methods defined
101
101
  @door.shut.should == "I don't know how to shut!" # old method retained
102
102
  end
103
-
103
+
104
104
  it "gets a set of new methods when any magic method is called" do
105
105
  @door.respond_to?(:shut).should == true # already defined
106
106
  @door.respond_to?(:open).should == false
@@ -109,36 +109,36 @@ describe "A door which opens and shuts:" do
109
109
  @door.respond_to?(:shut!).should == false
110
110
  @door.respond_to?(:open!).should == false
111
111
  @door.can_shut?.should == true # call one of them (triggers method_missing)
112
- @door.respond_to?(:open).should == false # a private method: Kernel#open
112
+ @door.respond_to?(:open).should == false # a private method: Kernel#open
113
113
  @door.respond_to?(:can_shut?).should == true # but these are all newly defined public methods
114
- @door.respond_to?(:can_open?).should == true
115
- @door.respond_to?(:shut!).should == true
116
- @door.respond_to?(:open!).should == true
114
+ @door.respond_to?(:can_open?).should == true
115
+ @door.respond_to?(:shut!).should == true
116
+ @door.respond_to?(:open!).should == true
117
117
  end
118
-
118
+
119
119
  it "retains any previously defined method_missing" do
120
120
  begin
121
121
  @door.hug_me
122
122
  rescue NoMethodError => e
123
123
  e.message.should == "I'm just a door!"
124
- end
124
+ end
125
125
  end
126
-
126
+
127
127
  describe "for :slam - " do
128
128
  describe "#slam" do
129
129
  it "should return an unfired StateFu::Transition" do
130
130
  t = @door.slam
131
131
  t.should be_kind_of(StateFu::Transition)
132
132
  t.fired?.should == false
133
- end
133
+ end
134
134
  end
135
135
 
136
136
  describe "#can_slam?" do
137
137
  it "should be true if the transition is valid for the current state" do
138
138
  @door.current_state.should == :open
139
139
  @door.can_slam?.should == true
140
- end
141
-
140
+ end
141
+
142
142
  it "should be false when the transition has unmet requirements" do
143
143
  Door.machine.events[:slam].lathe do
144
144
  requires :some_impossible_condition do
@@ -152,21 +152,21 @@ describe "A door which opens and shuts:" do
152
152
  @door.shut!
153
153
  @door.current_state.should == :closed
154
154
  @door.can_slam?.should == nil
155
- end
155
+ end
156
156
  end
157
157
  end
158
-
159
- end # magic event methods
160
-
158
+
159
+ end # magic event methods
160
+
161
161
  describe "magic state methods" do
162
162
  it "should be defined for each state by method_missing voodoo" do
163
163
  @door.should_not respond_to(:closed?)
164
164
  @door.should_not respond_to(:open?)
165
165
  @door.open?.should == true
166
166
  @door.should respond_to(:closed?)
167
- @door.should respond_to(:open?)
167
+ @door.should respond_to(:open?)
168
168
  end
169
-
169
+
170
170
  describe "for :closed - " do
171
171
  describe "#closed?" do
172
172
  it "should be true when the current_state is :closed" do
@@ -194,28 +194,28 @@ describe "A door which opens and shuts:" do
194
194
  shut_result.should be_complete
195
195
  @door.current_state.should == :closed
196
196
  end
197
-
197
+
198
198
  it "raises a StateFu::IllegalTransition if #shut! is called when already :closed" do
199
199
  @door.current_state.should == :open
200
200
  @door.shut!.should be_true
201
201
  @door.current_state.should == :closed
202
- lambda do
202
+ lambda do
203
203
  t = @door.shut!
204
204
  t.origin.should == :open
205
205
  end.should raise_error(StateFu::IllegalTransition)
206
206
  end
207
-
207
+
208
208
  it "raises StateFu::RequirementError if #open! is called when it is locked" do
209
209
  @door.shut!
210
210
  @door.locked = true
211
211
  lambda { @door.open! }.should raise_error(StateFu::RequirementError)
212
212
  end
213
-
213
+
214
214
  it "tells you why it won't open if you ask nicely" do
215
215
  @door.shut!
216
216
  @door.locked = true
217
217
  @door.locked?.should be_true
218
-
218
+
219
219
  transition = @door.state_fu.transition :open
220
220
  transition.requirement_errors.should == {:not_locked? => "Sorry, it's locked."}
221
221
  end
@@ -238,27 +238,27 @@ describe "A door which opens and shuts:" do
238
238
  end
239
239
  end
240
240
  end
241
-
241
+
242
242
  describe "Transition objects" do
243
-
244
- # TODO refactor me
243
+
244
+ # TODO refactor me
245
245
  def should_be_an_unfired_transition_with_the_event_slam_from_open_to_closed(transition)
246
246
  transition.should be_kind_of(StateFu::Transition)
247
247
  transition.fired?.should == false
248
248
  transition.current_state.should == :open
249
249
  transition.event.should == :slam
250
250
  transition.origin.should == :open
251
- transition.target.should == :closed
251
+ transition.target.should == :closed
252
252
  end
253
-
254
- it "returns a Transition on #slam" do
253
+
254
+ it "returns a Transition on #slam" do
255
255
  @door.slam do |transition|
256
256
  transition.should be_kind_of(StateFu::Transition)
257
257
  transition.fired?.should == false
258
258
  transition.current_state.should == :open
259
259
  transition.event.should == :slam
260
260
  transition.origin.should == :open
261
- transition.target.should == :closed
261
+ transition.target.should == :closed
262
262
  end
263
263
  end
264
264
 
@@ -276,15 +276,15 @@ describe "A door which opens and shuts:" do
276
276
  transition = @door.state_fu.transition [:slam, :closed]
277
277
  should_be_an_unfired_transition_with_the_event_slam_from_open_to_closed( transition )
278
278
  end
279
-
279
+
280
280
  it "changes the door's state when you #fire! the transition" do
281
281
  transition = @door.slam
282
282
  transition.fire!
283
283
  transition.fired?.should == true
284
284
  transition.complete?.should == true
285
- @door.current_state.should == :closed
285
+ @door.current_state.should == :closed
286
286
  end
287
-
287
+
288
288
  it "can tell you its #origin and #target states" do
289
289
  transition = @door.state_fu.transition :shut
290
290
  transition.origin.should be_kind_of(StateFu::State)
@@ -299,12 +299,12 @@ describe "A door which opens and shuts:" do
299
299
  transition = @door.state_fu.transition :open
300
300
  transition.valid?.should == false
301
301
  transition.unmet_requirements.should == [:not_locked?]
302
- transition.unmet_requirement_messages.should == ["Sorry, it's locked."]
302
+ transition.unmet_requirement_messages.should == ["Sorry, it's locked."]
303
303
  transition.requirement_errors.should == {:not_locked? => "Sorry, it's locked."}
304
304
  transition.first_unmet_requirement.should == :not_locked?
305
305
  transition.first_unmet_requirement_message.should == "Sorry, it's locked."
306
306
  end
307
- end
307
+ end
308
308
 
309
309
  # TODO save this for later ...............
310
310
  describe "#state_fu_binding" do
@@ -323,14 +323,14 @@ describe "A door which opens and shuts:" do
323
323
  it "have a list of #valid_transitions" do
324
324
  @door.state_fu_binding.valid_transitions.should be_kind_of(StateFu::TransitionQuery)
325
325
  @door.state_fu_binding.valid_transitions.length.should == 2
326
- t = @door.state_fu_binding.valid_transitions.first
327
- t.event.name.should == :shut
328
- t.origin.name.should == :open
329
- t.target.name.should == :closed
330
- t = @door.state_fu_binding.valid_transitions.last
331
- t.event.name.should == :slam
332
- t.origin.name.should == :open
333
- t.target.name.should == :closed
326
+ transition = @door.state_fu_binding.valid_transitions.first
327
+ transition.event.name.should == :shut
328
+ transition.origin.name.should == :open
329
+ transition.target.name.should == :closed
330
+ transition = @door.state_fu_binding.valid_transitions.last
331
+ transition.event.name.should == :slam
332
+ transition.origin.name.should == :open
333
+ transition.target.name.should == :closed
334
334
  end
335
335
  end
336
336
 
@@ -551,7 +551,7 @@ describe "arguments given to different method signatures" do
551
551
  def b2(t,a=nil) received[:b2] = [t,a] end
552
552
  def c2(t,*a) received[:c2] = [t,a] end
553
553
 
554
- # these method signatures get a transition, a list of arguments,
554
+ # these method signatures get a transition, a list of arguments,
555
555
  # and the object which owns the machine
556
556
  def a3(t,a,o) received[:a3] = [t,a,o] end
557
557
  def b3(t,a,o=nil) received[:b3] = [t,a,o] end
@@ -565,12 +565,12 @@ describe "arguments given to different method signatures" do
565
565
 
566
566
  end
567
567
  end # before
568
-
568
+
569
569
  describe "the machine" do
570
570
  it "have an event :observe which is a #cycle?" do
571
- Recorder.machine.events[:observe].cycle?.should be_true
571
+ Recorder.machine.events[:observe].cycle?.should be_true
572
572
  end
573
-
573
+
574
574
  it "have a list of execute hooks" do
575
575
  Recorder.machine.events[:observe].hooks[:execute].should == [:a1, :b1, :c1, :a2, :b2, :c2, :a3, :b3, :c3]
576
576
  end
@@ -587,17 +587,17 @@ describe "arguments given to different method signatures" do
587
587
  t.should be_kind_of(StateFu::Transition)
588
588
  t.should be_complete
589
589
  end
590
-
590
+
591
591
  describe "observing method calls on #observe!" do
592
592
  before do
593
593
  @t = @recorder.observe!
594
594
  @results = @recorder.received
595
595
  end
596
-
596
+
597
597
  it "call the event's :execute hooks on #observe!" do
598
598
  @results.keys.should =~ [:a1, :b1, :c1, :a2, :b2, :c2, :a3, :b3, :c3]
599
599
  end
600
-
600
+
601
601
  describe "methods which expect one argument" do
602
602
  it "receive a StateFu::Transition" do
603
603
  @results[:a1].should == [@t]
@@ -618,7 +618,7 @@ describe "arguments given to different method signatures" do
618
618
  it "receive a StateFu::Transition, an argument list and the recorder object" do
619
619
  @results[:a3].should == [@t, @t.args, @recorder]
620
620
  @results[:b3].should == [@t, @t.args, @recorder]
621
- @results[:c3].should == [@t, @t.args, [@recorder]]
621
+ @results[:c3].should == [@t, @t.args, [@recorder]]
622
622
  end
623
623
  end
624
624
  end
@@ -630,12 +630,12 @@ end
630
630
  #
631
631
 
632
632
  describe "sitting at a poker machine" do
633
-
633
+
634
634
  before :all do
635
635
  make_pristine_class('PokerMachine') do
636
-
636
+
637
637
  attr_accessor :silly_noises_inflicted
638
-
638
+
639
639
  def insert_coins n
640
640
  @credits = n * PokerMachine::CREDITS_PER_COIN
641
641
  end
@@ -644,32 +644,32 @@ describe "sitting at a poker machine" do
644
644
  def refund_coins
645
645
  (self.credits, x = 0, self.credits / PokerMachine::CREDITS_PER_COIN)[1]
646
646
  end
647
-
647
+
648
648
  def play_a_silly_noise
649
649
  @silly_noises_inflicted << [:silly_noise]
650
650
  end
651
-
652
- # an array with the accessors (StateFu::Bindings)
651
+
652
+ # an array with the accessors (StateFu::Bindings)
653
653
  # for each of the wheels' state machines, for convenience
654
654
  def wheels
655
- [wheel_one, wheel_two, wheel_three]
655
+ [wheel_one, wheel_two, wheel_three]
656
656
  end
657
657
 
658
658
  def wheels_spinning?
659
659
  wheels.any?(&:spinning?)
660
660
  end
661
-
661
+
662
662
  def display
663
663
  wheels.map(&:current_state_name)
664
664
  end
665
-
665
+
666
666
  def wait
667
667
  while wheels_spinning?
668
- spin_wheels!
669
- end
670
- stop_spinning!
668
+ spin_wheels!
669
+ end
670
+ stop_spinning!
671
671
  end
672
-
672
+
673
673
  PokerMachine::CREDITS_TO_PLAY = 5
674
674
  PokerMachine::CREDITS_PER_COIN = 5
675
675
 
@@ -679,32 +679,32 @@ describe "sitting at a poker machine" do
679
679
  @credits = 0
680
680
  @silly_noises_inflicted = []
681
681
  end
682
-
682
+
683
683
  machine do
684
- # adds a hook to the machine's global after slot
684
+ # adds a hook to the machine's global after slot
685
685
  after_everything :play_a_silly_noise
686
-
686
+
687
687
  # Define helper methods with 'proc' or its alias 'define'. This is
688
688
  # implicit when you supply a block and a symbol for an event or state
689
- # hook, a requirement, or a requirement failure message.
689
+ # hook, a requirement, or a requirement failure message.
690
690
  #
691
691
  # Named procs are "machine-local": they are available in any other
692
692
  # block evaluated by StateFu for a given machine, but are not defined
693
693
  # on the stateful class itself.
694
- #
694
+ #
695
695
  # Use them to extend the state machine DSL without cluttering up your
696
696
  # classes themselves.
697
- #
697
+ #
698
698
  # If you want a method which spans multiple machines (eg 'wheels',
699
699
  # above) or which is available to your object in any context, define
700
700
  # it as a standard method. You will then be able to access it in any
701
701
  # of your state machines.
702
- named_proc(:wheel_states) { wheels.map(&:current_state) }
702
+ named_proc(:wheel_states) { wheels.map(&:current_state) }
703
703
  named_proc(:wheels_stopped?) do
704
704
  !wheels.any?(&:spinning?)
705
705
  end
706
-
707
- state :ready do
706
+
707
+ state :ready do
708
708
 
709
709
  event :pull_lever, :transitions_to => :spinning do
710
710
  # The execution context always provides handy access to all the
@@ -712,91 +712,91 @@ describe "sitting at a poker machine" do
712
712
  # still be qualified.
713
713
  requires(:enough_credits) { self.credits >= PokerMachine::CREDITS_TO_PLAY }
714
714
  triggers(:deduct_credits) { self.credits -= PokerMachine::CREDITS_TO_PLAY }
715
- triggers(:spin_wheels) { [wheel_one, wheel_two,wheel_three].each(&:start!) }
715
+ triggers(:spin_wheels) { [wheel_one, wheel_two,wheel_three].each(&:start!) }
716
716
  # if we enable this line, the machine will #wait automatically
717
717
  # so that merely pulling the lever causes it to return to the ready state:
718
718
  #
719
- # after :wait
720
- end # :pull_lever event
719
+ # after :wait
720
+ end # :pull_lever event
721
721
  end # :ready state
722
-
723
- state :spinning do
722
+
723
+ state :spinning do
724
724
  cycle :spin_wheels do
725
725
  # executes after the transition has been accepted
726
726
  after do
727
- wheels.each do |wheel|
727
+ wheels.each do |wheel|
728
728
  if wheel.spinning?
729
729
  wheel.spin!
730
730
  end
731
- end
731
+ end
732
732
  end # execute
733
733
  end # :spinning state
734
734
 
735
- event :stop_spinning, :to => :ready do
736
- requires :wheels_stopped?
735
+ event :stop_spinning, :to => :ready do
736
+ requires :wheels_stopped?
737
737
  execute :payout do
738
738
  if wheel_states == wheel_states.uniq
739
739
  self.credits += wheel_states.first[:value]
740
- end
740
+ end
741
741
  end
742
- end # :stop_spinning event
743
- end # spinning state
744
- end # default machine
745
-
742
+ end # :stop_spinning event
743
+ end # spinning state
744
+ end # default machine
745
+
746
746
  [:one, :two, :three].each do |wheel|
747
747
  machine "wheel_#{wheel}" do
748
-
748
+
749
749
  state :bomb, :value => -5
750
750
  state :cherry, :value => 5
751
751
  state :smiley, :value => 10
752
- state :gold, :value => 15
752
+ state :gold, :value => 15
753
753
 
754
754
  state :spinning do
755
755
  cycle :spin do
756
756
  execute do
757
- silly_noises_inflicted << :spinning_noise
757
+ silly_noises_inflicted << :spinning_noise
758
758
  end
759
759
  after do
760
- if rand(3) == 0
760
+ if rand(3) == 0
761
761
  # we use binding.stop! rather than self.stop! here
762
762
  # to disambiguate which machine we're sending the event to.
763
763
  #
764
764
  # .binding yields a StateFu::Binding, which has all the same
765
- # magic methods as @pokie, but is explicitly for one machine,
765
+ # magic methods as @pokie, but is explicitly for one machine,
766
766
  # and one @pokie.
767
- #
768
- # @pokie.stop! would always cause the same wheel to stop
769
- # (the first one, becuase it was defined first, and automatically
767
+ #
768
+ # @pokie.stop! would always cause the same wheel to stop
769
+ # (the first one, becuase it was defined first, and automatically
770
770
  # defined methods never clobber any pre-existing methods) -
771
771
  # which isn't what we want here.
772
- binding.stop!([:bomb, :cherry, :smiley, :gold].rand)
772
+ binding.stop!([:bomb, :cherry, :smiley, :gold].rand)
773
773
  end
774
774
  end
775
775
  end
776
776
  end
777
-
777
+
778
778
  initial_state states.except(:spinning).rand
779
-
779
+
780
780
  event :start, :from => states.except(:spinning), :to => :spinning
781
781
  event :stop, :from => :spinning, :to => states.except(:spinning)
782
-
782
+
783
783
  end # machine :cell_#{cell}
784
784
  end # each cell
785
- end # PokerMachine
786
- end # before
787
-
785
+ end # PokerMachine
786
+ end # before
787
+
788
788
  describe "the state machine" do
789
789
  end
790
-
790
+
791
791
  before :each do
792
792
  @pokie = PokerMachine.new
793
793
  end
794
-
794
+
795
795
  # just a sanity check for method_missing
796
796
  it "doesn't talk to you" do
797
797
  lambda { @pokie.talk_to_me }.should raise_error(NoMethodError)
798
798
  end
799
-
799
+
800
800
  it "you need credits to pull the lever" do
801
801
  @pokie.state_fu!
802
802
  @pokie.credits.should == 0
@@ -808,13 +808,13 @@ describe "sitting at a poker machine" do
808
808
  it "has three wheels" do
809
809
  @pokie.wheels.length.should == 3
810
810
  end
811
-
811
+
812
812
  it "displays three icons" do
813
813
  @pokie.display.should be_kind_of(Array)
814
814
  @pokie.display.map(&:class).should == [Symbol, Symbol, Symbol]
815
815
  (@pokie.display - [:bomb, :cherry, :smiley, :gold]).should be_empty
816
816
  end
817
-
817
+
818
818
  describe "putting in 20 coins" do
819
819
  before do
820
820
  @pokie.insert_coins(20)
@@ -823,7 +823,7 @@ describe "sitting at a poker machine" do
823
823
  it "gives you 100 credits" do
824
824
  @pokie.credits.should == 100
825
825
  end
826
-
826
+
827
827
  describe "then pulling the lever" do
828
828
 
829
829
  it "spins the icons" do
@@ -840,27 +840,27 @@ describe "sitting at a poker machine" do
840
840
  it "makes a silly noise" do
841
841
  lambda { @pokie.pull_lever! }.should change(@pokie.silly_noises_inflicted, :length)
842
842
  end
843
-
843
+
844
844
  it "wont let you pull it again while it's still spinning" do
845
845
  @pokie.pull_lever!
846
846
  @pokie.spinning?.should be_true
847
847
  @pokie.can_pull_lever?.should == nil
848
848
  lambda{ @pokie.pull_lever! }.should raise_error(StateFu::IllegalTransition)
849
- end
850
-
849
+ end
850
+
851
851
  it "makes a spinning sound while you wait" do
852
852
  @pokie.pull_lever!
853
853
  noises_before = @pokie.silly_noises_inflicted
854
854
  @pokie.wait
855
855
  (@pokie.silly_noises_inflicted).should include(:spinning_noise)
856
856
  end
857
-
857
+
858
858
  it "it stops spinning after a little #wait" do
859
- @pokie.pull_lever!
859
+ @pokie.pull_lever!
860
860
  @pokie.wait
861
861
  @pokie.spinning?.should be_false
862
862
  end
863
-
863
+
864
864
  it "gives you more credits if all the icons are the same" do
865
865
  @pokie.pull_lever!
866
866
  @pokie.wheel_one.stop! :smiley
@@ -868,9 +868,9 @@ describe "sitting at a poker machine" do
868
868
  @pokie.wheel_three.stop! :smiley
869
869
  @pokie.wait
870
870
  @pokie.credits.should == 105
871
- end
872
- end
873
- end
871
+ end
872
+ end
873
+ end
874
874
  end
875
875
 
876
876