yasm 0.0.3 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/CHANGELOG +10 -0
- data/Gemfile +3 -0
- data/PUBLIC_DOMAIN +103 -0
- data/README.markdown +177 -0
- data/VERSION +1 -1
- data/features/action_callbacks.feature +22 -0
- data/features/actions.feature +9 -0
- data/features/final_states.feature +14 -0
- data/features/persistance/couchrest_model_persistance.feature +22 -0
- data/features/state_with_limited_actions.feature +13 -0
- data/features/states_with_time_limits.feature +29 -0
- data/features/step_definitions/action_callback_steps.rb +190 -0
- data/features/step_definitions/action_steps.rb +31 -0
- data/features/step_definitions/final_state_steps.rb +34 -0
- data/features/step_definitions/persistence/couchrest_model_persistence_steps.rb +85 -0
- data/features/step_definitions/state_with_limited_actions_steps.rb +27 -0
- data/features/step_definitions/states_with_time_limits_steps.rb +147 -0
- data/features/support/setup.rb +13 -0
- data/lib/yasm.rb +2 -0
- data/lib/yasm/context.rb +24 -6
- data/lib/yasm/context/state_configuration.rb +12 -2
- data/lib/yasm/context/state_configuration/action_hook.rb +33 -0
- data/lib/yasm/context/state_container.rb +29 -6
- data/lib/yasm/persistence.rb +1 -0
- data/lib/yasm/persistence/couchrest_model.rb +46 -0
- data/yasm.gemspec +12 -43
- metadata +69 -7
data/.gitignore
ADDED
data/CHANGELOG
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
v0.0.5
|
2
|
+
-- feature: before_action and after_action callbacks on state containers (see README).
|
3
|
+
|
4
|
+
v0.0.4
|
5
|
+
-- feature: couchrest_model persistence (see README).
|
6
|
+
|
7
|
+
v0.0.2
|
8
|
+
|
9
|
+
-- feature: minimum/maximum time limits on states. (see the `State Timers` section in the README).
|
10
|
+
-- feature: exceptions are now subclassed, so that you can easily catch them.
|
data/Gemfile
ADDED
data/PUBLIC_DOMAIN
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
This software is PUBLIC DOMAIN
|
2
|
+
|
3
|
+
|
4
|
+
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
|
5
|
+
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
|
6
|
+
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
|
7
|
+
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
|
8
|
+
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
|
9
|
+
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,;;iiii;;,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
|
10
|
+
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,;ijffffffffffffffffji;,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
|
11
|
+
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,;iffffffffffffffffffffffffffi;,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
|
12
|
+
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, iffffffffffffffffffffffffffffffi ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
|
13
|
+
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,ijffffffffffffffffffffffffffffffffffji,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
|
14
|
+
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,iffffffffffffffffffffffffffffffffffffffffi,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
|
15
|
+
,,,,,,,,,,,,,,,,,,,,,,,,,,,jffffffffffffffffffffffffffffffffffffffffffffj,,,,,,,,,,,,,,,,,,,,,,,,,,,
|
16
|
+
,,,,,,,,,,,,,,,,,,,,,,,,,,tfffffffffffffffffffffffffffffffffffffffffffffft,,,,,,,,,,,,,,,,,,,,,,,,,,
|
17
|
+
,,,,,,,,,,,,,,,,,,,,,,,,;ffffffffffffffffffffffffffffffffffffffffffffffffff;,,,,,,,,,,,,,,,,,,,,,,,,
|
18
|
+
,,,,,,,,,,,,,,,,,,,,,,,ffffffffffffffffffffffjt;;,,;;tjffffffffffffffffffffff,,,,,,,,,,,,,,,,,,,,,,,
|
19
|
+
,,,,,,,,,,,,,,,,,,,,,;fffffffffffffffffft: :tffffffffffffffffff;,,,,,,,,,,,,,,,,,,,,,
|
20
|
+
,,,,,,,,,,,,,,,,,,,,,jfffffffffffffffft. .tffffffffffffffffj,,,,,,,,,,,,,,,,,,,,,
|
21
|
+
,,,,,,,,,,,,,,,,,,,ifffffffffffffffi: :ifffffffffffffffi,,,,,,,,,,,,,,,,,,,
|
22
|
+
,,,,,,,,,,,,,,,,,,tffffffffffffffi ifffffffffffffft,,,,,,,,,,,,,,,,,,
|
23
|
+
,,,,,,,,,,,,,,,,,ifffffffffffff, ,fffffffffffffi,,,,,,,,,,,,,,,,,
|
24
|
+
,,,,,,,,,,,,,,,,,fffffffffffffi ifffffffffffff,,,,,,,,,,,,,,,,,
|
25
|
+
,,,,,,,,,,,,,,,;jffffffffffff ffffffffffffj;,,,,,,,,,,,,,,,
|
26
|
+
,,,,,,,,,,,,,,,ffffffffffff: jffffffffffffff,,,,,,,,,,,,,,,
|
27
|
+
,,,,,,,,,,,,,,ffffffffffff. jffffffffffffffff,,,,,,,,,,,,,,
|
28
|
+
,,,,,,,,,,,,,;ffffffffffft :fffffffffffffffff;,,,,,,,,,,,,,
|
29
|
+
,,,,,,,,,,,,,ffffffffffft ,tfffffft; jfffffffffffffffffff,,,,,,,,,,,,,
|
30
|
+
,,,,,,,,,,,,tffffffffff. ;ffffffffffffffff; jfffffffffffffffffffft,,,,,,,,,,,,
|
31
|
+
,,,,,,,,,,,jffffffffff: ,ffffffffffffffffffffff, jffffffffffffffffffffffj,,,,,,,,,,,
|
32
|
+
,,,,,,,,,,,fffffffffff :ffffffffffffffffffffffff: :ffffffffffffffffffffffff,,,,,,,,,,,
|
33
|
+
,,,,,,,,,,iffffffffff ,jfffffffffffffffffffffffff jfffffffffffffffffffffffffi,,,,,,,,,,
|
34
|
+
,,,,,,,,,,ffffffffffi tffffffffffffffffffffffffff jfffffffffffffff iffffffffff,,,,,,,,,,
|
35
|
+
,,,,,,,,,ifffffffff, jfffffffffffffffffffffffff, jfffffffffffffff ,fffffffffi,,,,,,,,,
|
36
|
+
,,,,,,,,,jfffffffff :ffffffffffffffffffffffffff :fffffffffffffff; fffffffffj,,,,,,,,,
|
37
|
+
,,,,,,,, fffffffffi jffffffffffffffffffffffffff jfffffffffffffff ifffffffff ,,,,,,,,
|
38
|
+
,,,,,,,,ifffffffff tffffffffffffffffffffffffff jfffffffffffffff fffffffffi,,,,,,,,
|
39
|
+
,,,,,,,;fffffffffi :fffffffffffffffffffffffff, jfffffffffffffff ifffffffff;,,,,,,,
|
40
|
+
,,,,,,,ifffffffff: jfffffffffffffffffffffffff :fffffffffffffff; :fffffffffi,,,,,,,
|
41
|
+
,,,,,,,ffffffffff :fffffffffffffffffffffffff jfffffffffffffff ffffffffff,,,,,,,
|
42
|
+
,,,,,,,ffffffffft ,fffffffffffffffff; jfffffffffffffff t, tfffffffff,,,,,,,
|
43
|
+
,,,,,,;fffffffff ffffffffffffffff jfffffffffffffff tff fffffffff;,,,,,,
|
44
|
+
,,,,,,ifffffffft fffffffffffffff, :fffffffffffffff;.fff tffffffffi,,,,,,
|
45
|
+
,,,,,,jffffffff: ;ffffffffffffff. jfffffffffffffff .ffff; :ffffffffj,,,,,,
|
46
|
+
,,,,,,fffffffff ffffffffffffff, jfffffffffffffff tffffff fffffffff,,,,,,
|
47
|
+
,,,,,,fffffffff fffffffffffff jfffffffffffffff tfffffff fffffffff,,,,,,
|
48
|
+
,,,,,,fffffffff fffffffffffff :fffffffffffffff; ........ fffffffff,,,,,,
|
49
|
+
,,,,,;ffffffffj ,ffffffffffff; jfffffffffffffff jffffffff;,,,,,
|
50
|
+
,,,,,;ffffffffi tffffffffffff jfffffffffffffff iffffffff;,,,,,
|
51
|
+
,,,,,;ffffffff; fffffffffffff jfffffffffffffff ;ffffffff;,,,,,
|
52
|
+
,,,,,;ffffffff; fffffffffffff :fffffffffffffff; ;ffffffff;,,,,,
|
53
|
+
,,,,,iffffffff, fffffffffffff jfffffffffffffff ,ffffffffi,,,,,
|
54
|
+
,,,,,iffffffff, fffffffffffff jfffffffffffffff ,ffffffffi,,,,,
|
55
|
+
,,,,,;ffffffff; fffffffffffff jfffffffffffffff ;ffffffff;,,,,,
|
56
|
+
,,,,,;ffffffff; fffffffffffff :fffffffffffffff; ;ffffffff;,,,,,
|
57
|
+
,,,,,;ffffffffi tffffffffffff jfffffffffffffff iffffffff;,,,,,
|
58
|
+
,,,,,;ffffffffj ,fffffffffff jfffffffffffffff jffffffff;,,,,,
|
59
|
+
,,,,,,fffffffff fffffffff, jfffffffffffffff jjjjjjjjjjjjj fffffffff,,,,,,
|
60
|
+
,,,,,,fffffffff fffffffff :fffffffffffffff; .fffffffffffff fffffffff,,,,,,
|
61
|
+
,,,,,,fffffffff ffffffff jfffffffffffffff ,ffffffffffffff fffffffff,,,,,,
|
62
|
+
,,,,,,jffffffff: ;ffffff jfffffffffffffff .ffffffffffffff; :ffffffffj,,,,,,
|
63
|
+
,,,,,,ifffffffft ffff, jfffffffffffffff ,fffffffffffffff tffffffffi,,,,,,
|
64
|
+
,,,,,,;fffffffff ffff :fffffffffffffff; ffffffffffffffff fffffffff;,,,,,,
|
65
|
+
,,,,,,,ffffffffft ,ff jfffffffffffffff ifffffffffffffffff, tfffffffff,,,,,,,
|
66
|
+
,,,,,,,ffffffffff : jfffffffffffffff tfffffffffffffffffffffff: ffffffffff,,,,,,,
|
67
|
+
,,,,,,,ifffffffff: jfffffffffffffff tfffffffffffffffffffffffj :fffffffffi,,,,,,,
|
68
|
+
,,,,,,,;fffffffffi :fffffffffffffff;.ffffffffffffffffffffffff: ifffffffff;,,,,,,,
|
69
|
+
,,,,,,,,ifffffffff jfffffffffffffff .fffffffffffffffffffffffft fffffffffi,,,,,,,,
|
70
|
+
,,,,,,,, fffffffffi jfffffffffffffff tffffffffffffffffffffffffj ifffffffff ,,,,,,,,
|
71
|
+
,,,,,,,,,jfffffffff jfffffffffffffff tffffffffffffffffffffffff: fffffffffj,,,,,,,,,
|
72
|
+
,,,,,,,,,ifffffffff, :fffffffffffffff;.ffffffffffffffffffffffffj ,fffffffffi,,,,,,,,,
|
73
|
+
,,,,,,,,,,ffffffffffi jfffffffffffffff .fffffffffffffffffffffffft iffffffffff,,,,,,,,,,
|
74
|
+
,,,,,,,,,,iffffffffff jfffffffffffffff tfffffffffffffffffffffffj, ffffffffffi,,,,,,,,,,
|
75
|
+
,,,,,,,,,,,ffffffffffffffffffffffffff tfffffffffffffffffffffff: fffffffffff,,,,,,,,,,,
|
76
|
+
,,,,,,,,,,,jffffffffffffffffffffffff; ,ffffffffffffffffffffff, :ffffffffffj,,,,,,,,,,,
|
77
|
+
,,,,,,,,,,,,tffffffffffffffffffffff ;ffffffffffffffff; .fffffffffft,,,,,,,,,,,,
|
78
|
+
,,,,,,,,,,,,,fffffffffffffffffffff ,tfffffft; tfffffffffff,,,,,,,,,,,,,
|
79
|
+
,,,,,,,,,,,,,;fffffffffffffffffff tfffffffffff;,,,,,,,,,,,,,
|
80
|
+
,,,,,,,,,,,,,,ffffffffffffffffff; .ffffffffffff,,,,,,,,,,,,,,
|
81
|
+
,,,,,,,,,,,,,,,ffffffffffffffff :ffffffffffff,,,,,,,,,,,,,,,
|
82
|
+
,,,,,,,,,,,,,,,;jfffffffffffff ffffffffffffj;,,,,,,,,,,,,,,,
|
83
|
+
,,,,,,,,,,,,,,,,,fffffffffffffi ifffffffffffff,,,,,,,,,,,,,,,,,
|
84
|
+
,,,,,,,,,,,,,,,,,ifffffffffffff, ,fffffffffffffi,,,,,,,,,,,,,,,,,
|
85
|
+
,,,,,,,,,,,,,,,,,,tffffffffffffffi ifffffffffffffft,,,,,,,,,,,,,,,,,,
|
86
|
+
,,,,,,,,,,,,,,,,,,,ifffffffffffffffi: :ifffffffffffffffi,,,,,,,,,,,,,,,,,,,
|
87
|
+
,,,,,,,,,,,,,,,,,,,,,jfffffffffffffffft. .tffffffffffffffffj,,,,,,,,,,,,,,,,,,,,,
|
88
|
+
,,,,,,,,,,,,,,,,,,,,,;fffffffffffffffffft: :tffffffffffffffffff;,,,,,,,,,,,,,,,,,,,,,
|
89
|
+
,,,,,,,,,,,,,,,,,,,,,,,ffffffffffffffffffffffjt;;,,;;tjffffffffffffffffffffff,,,,,,,,,,,,,,,,,,,,,,,
|
90
|
+
,,,,,,,,,,,,,,,,,,,,,,,,;ffffffffffffffffffffffffffffffffffffffffffffffffff;,,,,,,,,,,,,,,,,,,,,,,,,
|
91
|
+
,,,,,,,,,,,,,,,,,,,,,,,,,,tfffffffffffffffffffffffffffffffffffffffffffffft,,,,,,,,,,,,,,,,,,,,,,,,,,
|
92
|
+
,,,,,,,,,,,,,,,,,,,,,,,,,,,jffffffffffffffffffffffffffffffffffffffffffffj,,,,,,,,,,,,,,,,,,,,,,,,,,,
|
93
|
+
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,iffffffffffffffffffffffffffffffffffffffffi,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
|
94
|
+
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,ijffffffffffffffffffffffffffffffffffji,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
|
95
|
+
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, iffffffffffffffffffffffffffffffi ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
|
96
|
+
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,;iffffffffffffffffffffffffffi;,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
|
97
|
+
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,;ijffffffffffffffffji;,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
|
98
|
+
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,;;iiii;;,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
|
99
|
+
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
|
100
|
+
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
|
101
|
+
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
|
102
|
+
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
|
103
|
+
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
|
data/README.markdown
CHANGED
@@ -359,6 +359,183 @@ long time. Like, long enough to cause a state transition domino effect. Let's mo
|
|
359
359
|
Notice that this domino effect happened lazily when you call the `do!` method, or the `context.state.value` methods. Quite nice for systems where
|
360
360
|
you persist your state to a db.
|
361
361
|
|
362
|
+
|
363
|
+
## Persistence
|
364
|
+
|
365
|
+
How do you persist your state to a database? YASM will automatically persist/load your states to/from the database; it supports (or plans to support) the following ORMs:
|
366
|
+
|
367
|
+
* couchrest_model (as of version 0.0.4)
|
368
|
+
* mongoid (coming soon)
|
369
|
+
* active_record (coming soon)
|
370
|
+
|
371
|
+
For example, let's suppose our vending machine context was actually a CouchDB document, modelled with CouchRest::Model:
|
372
|
+
|
373
|
+
class VendingMachine < CouchRest::Model::Base
|
374
|
+
include Yasm::Context
|
375
|
+
|
376
|
+
start :waiting
|
377
|
+
end
|
378
|
+
|
379
|
+
#.....
|
380
|
+
|
381
|
+
By simply mixing Yasm::Context into the document, our states will be automatically persisted to the database and loaded from the database.
|
382
|
+
|
383
|
+
|
384
|
+
## Anonymous and Named States
|
385
|
+
|
386
|
+
Up till now, we've been utilizing the anonymous state on our context. In other words, because we didn't wrap our `start :waiting` inside a `state` call, YASM
|
387
|
+
assumed that we were simply going to be using the anonymous state on our class. Also, when we've called the `do!` method, we've called it directly on our context,
|
388
|
+
which again assumes that you're attempting to apply an action to the anonymous state on your context.
|
389
|
+
|
390
|
+
What's an example of a named state? Perhaps we'd like to manage the electricity on our vending machine with a state machine. To do so, we'd simply:
|
391
|
+
|
392
|
+
class VendingMachine
|
393
|
+
include Yasm::Context
|
394
|
+
|
395
|
+
start :waiting
|
396
|
+
|
397
|
+
state(:electricity) do
|
398
|
+
start :on
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
class Waiting; include Yasm::State; end
|
403
|
+
class Vending; include Yasm::State; end
|
404
|
+
class On; include Yasm::State; end
|
405
|
+
class Off; include Yasm::State; end
|
406
|
+
|
407
|
+
class Unplug
|
408
|
+
include Yasm::Action
|
409
|
+
|
410
|
+
triggers :off
|
411
|
+
end
|
412
|
+
|
413
|
+
class Plugin
|
414
|
+
include Yasm::Action
|
415
|
+
|
416
|
+
triggers :on
|
417
|
+
end
|
418
|
+
|
419
|
+
class Select
|
420
|
+
include Yasm::Action
|
421
|
+
|
422
|
+
triggers :vending
|
423
|
+
end
|
424
|
+
|
425
|
+
Now our VendingMachine has two managed states: the anonymous state (that start in the `Waiting` state), and the "electricity" state (that starts in the `On` state).
|
426
|
+
|
427
|
+
We can apply actions to each of these states independently:
|
428
|
+
|
429
|
+
v = VendingMachine.new
|
430
|
+
|
431
|
+
puts v.state.value
|
432
|
+
#==> Waiting
|
433
|
+
|
434
|
+
puts v.electricity.value
|
435
|
+
#==> On
|
436
|
+
|
437
|
+
v.do! Select
|
438
|
+
|
439
|
+
puts v.state.value
|
440
|
+
#==> Vending
|
441
|
+
|
442
|
+
v.electricity.do! Unplug
|
443
|
+
|
444
|
+
puts v.electricity.value
|
445
|
+
#==> Off
|
446
|
+
|
447
|
+
## Action Callbacks
|
448
|
+
|
449
|
+
How do you run a method before or after an action is applied to a yasm state within your context? Yasm::Context gives you the following two callback macros for this purpose:
|
450
|
+
`before_action` and `after_action`. They each accept two parameters: a symbol representing the method on the context you'd like called, and an options hash, where you
|
451
|
+
can specify `:only` or `:except` constraints.
|
452
|
+
|
453
|
+
For example:
|
454
|
+
|
455
|
+
class Human
|
456
|
+
include Yasm::Context
|
457
|
+
|
458
|
+
start :alive
|
459
|
+
before_action :weigh_options, :except => :jump_off_building
|
460
|
+
after_action :consider_results, :only => :jump_off_building
|
461
|
+
|
462
|
+
private
|
463
|
+
def weigh_options
|
464
|
+
puts "You could, alternatively, jump off a building."
|
465
|
+
end
|
466
|
+
|
467
|
+
def consider_results
|
468
|
+
puts "Splendid!"
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
class Alive; include Yasm::State; end
|
473
|
+
class Dead; include Yasm::State; end
|
474
|
+
|
475
|
+
class GoToWork
|
476
|
+
include Yasm::Action
|
477
|
+
end
|
478
|
+
|
479
|
+
class JumpOffBuilding
|
480
|
+
include Yasm::Action
|
481
|
+
triggers :dead
|
482
|
+
|
483
|
+
def execute
|
484
|
+
puts "Weeeeeee!"
|
485
|
+
end
|
486
|
+
end
|
487
|
+
|
488
|
+
Now, when we apply actions to the anonymous state, before and after actions will run when appropriate:
|
489
|
+
|
490
|
+
you = Human.new
|
491
|
+
|
492
|
+
you.do! GoToWork
|
493
|
+
#==> "You could, alternatively, jump off a building."
|
494
|
+
|
495
|
+
you.do! JumpOffBuilding
|
496
|
+
#==> "Weeeeeee!"
|
497
|
+
#==> "Splendid!"
|
498
|
+
|
499
|
+
Just as you can use `before_action` and `after_action` with the anonymous state, you can use it with named states as well:
|
500
|
+
|
501
|
+
class VendingMachine
|
502
|
+
include Yasm::Context
|
503
|
+
|
504
|
+
state(:electricity) do
|
505
|
+
start :on
|
506
|
+
before_action :warn, :only => :unplug
|
507
|
+
after_action :sigh
|
508
|
+
end
|
509
|
+
|
510
|
+
private
|
511
|
+
def warn
|
512
|
+
puts "Wait! Don't unplug me!!!"
|
513
|
+
end
|
514
|
+
|
515
|
+
def sigh
|
516
|
+
puts "sigh...."
|
517
|
+
end
|
518
|
+
end
|
519
|
+
|
520
|
+
class On; include Yasm::State; end
|
521
|
+
class Off; include Yasm::State; end
|
522
|
+
|
523
|
+
class Unplug
|
524
|
+
include Yasm::Action
|
525
|
+
triggers :off
|
526
|
+
|
527
|
+
def execute
|
528
|
+
puts "unplugging...."
|
529
|
+
end
|
530
|
+
end
|
531
|
+
|
532
|
+
v = VendingMachine.new
|
533
|
+
|
534
|
+
v.electricity.do! Unplug
|
535
|
+
#==> "Wait! Don't unplug me!!!"
|
536
|
+
#==> "unplugging...."
|
537
|
+
#==> "sigh...."
|
538
|
+
|
362
539
|
## PUBLIC DOMAIN
|
363
540
|
|
364
541
|
This software is committed to the public domain. No license. No copyright. DO ANYTHING!
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.6
|
@@ -0,0 +1,22 @@
|
|
1
|
+
Feature: Action Callbacks
|
2
|
+
As a programmer
|
3
|
+
I want to have before and after hooks into actions
|
4
|
+
So that I can customize my state machine
|
5
|
+
|
6
|
+
Scenario: After Action callback
|
7
|
+
Given a context that I intend to attach action callbacks to
|
8
|
+
When I create an after action callback with no constraints
|
9
|
+
Then that callback should be called after all actions
|
10
|
+
When I create an after action callback with an `only` constraint
|
11
|
+
Then that callback should be called only when the particular action(s) run
|
12
|
+
When I create an after action callback with an `except` constraint
|
13
|
+
Then that callback should not be called when the particular action(s) run
|
14
|
+
|
15
|
+
Scenario: Before Action callback
|
16
|
+
Given a context that I intend to attach before action callbacks to
|
17
|
+
When I create a before action callback with no constraints
|
18
|
+
Then that callback should be called before all actions
|
19
|
+
When I create a before action callback with an `only` constraint
|
20
|
+
Then that before callback should be called only when the particular action(s) run
|
21
|
+
When I create a before action callback with an `except` constraint
|
22
|
+
Then that before callback should not be called when the particular action(s) run
|
@@ -0,0 +1,9 @@
|
|
1
|
+
Feature: Actions
|
2
|
+
As a programmer
|
3
|
+
I want to be able to apply actions to a state
|
4
|
+
So that I can cause the state to transition
|
5
|
+
|
6
|
+
Scenario: Applying actions to a state
|
7
|
+
Given a context
|
8
|
+
When I apply an action to it that triggers a state transition
|
9
|
+
Then the state should transition appropriately
|
@@ -0,0 +1,14 @@
|
|
1
|
+
Feature:
|
2
|
+
As a programmer
|
3
|
+
I want to declare a state as FINAL
|
4
|
+
So that I can forbid any futher actions or state transitions
|
5
|
+
|
6
|
+
Scenario: Declaring a state FINAL
|
7
|
+
Given a state that I intend to declare final
|
8
|
+
When I declare it final
|
9
|
+
Then it should return true when asked if it's a FINAL state
|
10
|
+
|
11
|
+
Scenario: Applying an action to a FINAL state
|
12
|
+
Given a final state
|
13
|
+
When I attempt to apply an action to it
|
14
|
+
Then I should get an exception
|
@@ -0,0 +1,22 @@
|
|
1
|
+
@couch
|
2
|
+
Feature: CouchRest::Model Persistance
|
3
|
+
As a CouchDB hacker
|
4
|
+
I want the states on my CouchRest::Mode::Base context persisted to CouchDB
|
5
|
+
So that I can incorporate YASM into my relaxing database environment
|
6
|
+
|
7
|
+
Scenario: Yasm::Persistence::CouchRest::Model should be auto included when Yasm::Context is included inside a CouchRest::Model::Base derived class
|
8
|
+
Given a class that inherits from CouchRest::Model::Base
|
9
|
+
When I mix Yasm::Context into it
|
10
|
+
Then Yasm::Persistence::CouchRest::Model should be autoincluded as well
|
11
|
+
|
12
|
+
Scenario: Saving state to CouchRest::Model::Base derived classes
|
13
|
+
Given a couchrest model context
|
14
|
+
When I save that context to CouchDB
|
15
|
+
Then the states should be saved in the document
|
16
|
+
|
17
|
+
Scenario: Loading state from CouchRest::Model::Base derived classes
|
18
|
+
Given a couchrest model context with state saved in the database
|
19
|
+
When I load that context
|
20
|
+
Then the states should be restored
|
21
|
+
And the states should be fast forwarded
|
22
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
Feature: State's that limit actions
|
2
|
+
As a programmer
|
3
|
+
I want to limit the actions that can be applied to a state
|
4
|
+
So that I can control the workflow of my state machine
|
5
|
+
|
6
|
+
Scenario: Declaring valid actions
|
7
|
+
Given a state
|
8
|
+
When I declare that only certain actions can be applied to it
|
9
|
+
Then those actions should be stored on the state class
|
10
|
+
|
11
|
+
Scenario: Determing if an action is valid for a given state
|
12
|
+
Given a state with limited actions
|
13
|
+
Then I should be able to determine whether a given action is valid for a given state
|
@@ -0,0 +1,29 @@
|
|
1
|
+
Feature: Time limits on states
|
2
|
+
As a programmer
|
3
|
+
I want to be able to put minimum and maximum time limits on states
|
4
|
+
So that I can simulate better the real world
|
5
|
+
|
6
|
+
Scenario: Declaring a minimum time limit
|
7
|
+
Given a state that I intend to declare a minimum time limit on
|
8
|
+
When I declare a minimum time limit on it
|
9
|
+
Then it should store that time limit on the state class
|
10
|
+
|
11
|
+
Scenario: Applying an action to a state with a minimum time limit
|
12
|
+
Given a state that has a minimum time limit
|
13
|
+
When I apply an action to that state before its minimum time limit has been reached
|
14
|
+
Then I should get a minimum time limit exception
|
15
|
+
When I apply an action to that state after its minimum time limit has been reached
|
16
|
+
Then I should not get a minimum time limit exception
|
17
|
+
|
18
|
+
Scenario: Declaring a maximum time limit
|
19
|
+
Given a state that I intend to declare a maximum time limit on
|
20
|
+
When I declare a maximum time limit on it without an action
|
21
|
+
Then it should raise an argument error exception
|
22
|
+
When I declare a maximum time limit on it with an action
|
23
|
+
Then it should store that maximum time limit and action on the state class
|
24
|
+
|
25
|
+
Scenario: State transition dominoe with max time limits
|
26
|
+
Given a context with the potential for a max time limit dominoe effect
|
27
|
+
When I wait long enough to cause the dominoe effect
|
28
|
+
Then the dominoe effect should occur when I ask for the state
|
29
|
+
And the dominoe effect should occur when I attempt to apply an action to the context
|
@@ -0,0 +1,190 @@
|
|
1
|
+
Given /^a context that I intend to attach action callbacks to$/ do
|
2
|
+
class ActionCallbackContext
|
3
|
+
include Yasm::Context
|
4
|
+
start :action_callback_state
|
5
|
+
end
|
6
|
+
|
7
|
+
class ActionCallbackState
|
8
|
+
include Yasm::State
|
9
|
+
end
|
10
|
+
|
11
|
+
class Action1; include Yasm::Action; end
|
12
|
+
class Action2; include Yasm::Action; end
|
13
|
+
class Action3; include Yasm::Action; end
|
14
|
+
class Action4; include Yasm::Action; end
|
15
|
+
end
|
16
|
+
|
17
|
+
When /^I create an after action callback with no constraints$/ do
|
18
|
+
class ActionCallbackContext
|
19
|
+
attr_accessor :counter
|
20
|
+
after_action :increment_counter
|
21
|
+
|
22
|
+
def initialize
|
23
|
+
@counter = 0
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def increment_counter
|
28
|
+
@counter += 1
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
Then /^that callback should be called after all actions$/ do
|
34
|
+
context = ActionCallbackContext.new
|
35
|
+
context.counter.should == 0
|
36
|
+
context.do! Action1
|
37
|
+
context.counter.should == 1
|
38
|
+
context.do! Action2
|
39
|
+
context.counter.should == 2
|
40
|
+
context.do! Action3
|
41
|
+
context.counter.should == 3
|
42
|
+
context.do! Action4
|
43
|
+
context.counter.should == 4
|
44
|
+
end
|
45
|
+
|
46
|
+
When /^I create an after action callback with an `only` constraint$/ do
|
47
|
+
class ActionCallbackContext
|
48
|
+
after_action :decrement_counter, :only => [:action1, :action2]
|
49
|
+
|
50
|
+
private
|
51
|
+
def decrement_counter
|
52
|
+
@counter -= 1
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
Then /^that callback should be called only when the particular action\(s\) run$/ do
|
58
|
+
context = ActionCallbackContext.new
|
59
|
+
context.counter.should == 0
|
60
|
+
context.do! Action1
|
61
|
+
context.counter.should == 0
|
62
|
+
context.do! Action2
|
63
|
+
context.counter.should == 0
|
64
|
+
context.do! Action3
|
65
|
+
context.counter.should == 1
|
66
|
+
context.do! Action4
|
67
|
+
context.counter.should == 2
|
68
|
+
end
|
69
|
+
|
70
|
+
When /^I create an after action callback with an `except` constraint$/ do
|
71
|
+
class ActionCallbackContext
|
72
|
+
after_action :double_counter, :except => :action3
|
73
|
+
|
74
|
+
private
|
75
|
+
def double_counter
|
76
|
+
@counter *= 2
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
Then /^that callback should not be called when the particular action\(s\) run$/ do
|
82
|
+
context = ActionCallbackContext.new
|
83
|
+
context.counter.should == 0
|
84
|
+
context.do! Action3
|
85
|
+
context.counter.should == 1
|
86
|
+
context.do! Action3
|
87
|
+
context.counter.should == 2
|
88
|
+
context.do! Action4
|
89
|
+
context.counter.should == 6
|
90
|
+
context.do! Action4
|
91
|
+
context.counter.should == 14
|
92
|
+
context.do! Action1
|
93
|
+
context.counter.should == 28
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
Given /^a context that I intend to attach before action callbacks to$/ do
|
98
|
+
class BeforeActionCallbackContext
|
99
|
+
include Yasm::Context
|
100
|
+
start :action_callback_state
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
When /^I create a before action callback with no constraints$/ do
|
105
|
+
class BeforeActionCallbackContext
|
106
|
+
attr_accessor :counter
|
107
|
+
before_action :increment_counter
|
108
|
+
|
109
|
+
def initialize
|
110
|
+
@counter = 0
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
def increment_counter
|
115
|
+
@counter += 1
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
class ActionCallbackState
|
120
|
+
include Yasm::State
|
121
|
+
end
|
122
|
+
|
123
|
+
class Action1; include Yasm::Action; end
|
124
|
+
class Action2; include Yasm::Action; end
|
125
|
+
class Action3; include Yasm::Action; end
|
126
|
+
class Action4; include Yasm::Action; end
|
127
|
+
end
|
128
|
+
|
129
|
+
Then /^that callback should be called before all actions$/ do
|
130
|
+
context = BeforeActionCallbackContext.new
|
131
|
+
context.counter.should == 0
|
132
|
+
context.do! Action1
|
133
|
+
context.counter.should == 1
|
134
|
+
context.do! Action2
|
135
|
+
context.counter.should == 2
|
136
|
+
context.do! Action3
|
137
|
+
context.counter.should == 3
|
138
|
+
context.do! Action4
|
139
|
+
context.counter.should == 4
|
140
|
+
end
|
141
|
+
|
142
|
+
When /^I create a before action callback with an `only` constraint$/ do
|
143
|
+
class BeforeActionCallbackContext
|
144
|
+
before_action :decrement_counter, :only => [:action1, :action2]
|
145
|
+
|
146
|
+
private
|
147
|
+
def decrement_counter
|
148
|
+
@counter -= 1
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
Then /^that before callback should be called only when the particular action\(s\) run$/ do
|
154
|
+
context = BeforeActionCallbackContext.new
|
155
|
+
context.counter.should == 0
|
156
|
+
context.do! Action1
|
157
|
+
context.counter.should == 0
|
158
|
+
context.do! Action2
|
159
|
+
context.counter.should == 0
|
160
|
+
context.do! Action3
|
161
|
+
context.counter.should == 1
|
162
|
+
context.do! Action4
|
163
|
+
context.counter.should == 2
|
164
|
+
end
|
165
|
+
|
166
|
+
When /^I create a before action callback with an `except` constraint$/ do
|
167
|
+
class BeforeActionCallbackContext
|
168
|
+
before_action :double_counter, :except => :action3
|
169
|
+
|
170
|
+
private
|
171
|
+
def double_counter
|
172
|
+
@counter *= 2
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
Then /^that before callback should not be called when the particular action\(s\) run$/ do
|
178
|
+
context = BeforeActionCallbackContext.new
|
179
|
+
context.counter.should == 0
|
180
|
+
context.do! Action3
|
181
|
+
context.counter.should == 1
|
182
|
+
context.do! Action3
|
183
|
+
context.counter.should == 2
|
184
|
+
context.do! Action4
|
185
|
+
context.counter.should == 6
|
186
|
+
context.do! Action4
|
187
|
+
context.counter.should == 14
|
188
|
+
context.do! Action1
|
189
|
+
context.counter.should == 28
|
190
|
+
end
|