yasm 0.0.3 → 0.0.6
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/.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
|