dcadenas-state_pattern 1.0.0 → 1.0.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/VERSION +1 -1
- data/lib/state_pattern.rb +42 -52
- data/state_pattern.gemspec +1 -1
- data/test/state_pattern_test.rb +10 -0
- data/test/transition_validations_test.rb +28 -16
- metadata +1 -1
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0.
|
1
|
+
1.0.1
|
data/lib/state_pattern.rb
CHANGED
@@ -3,73 +3,67 @@ require 'state_pattern/invalid_transition_exception'
|
|
3
3
|
|
4
4
|
module StatePattern
|
5
5
|
def self.included(base)
|
6
|
-
base.
|
7
|
-
|
8
|
-
@state_classes ||= []
|
9
|
-
end
|
6
|
+
base.extend ClassMethods
|
7
|
+
end
|
10
8
|
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
module ClassMethods
|
10
|
+
def state_classes
|
11
|
+
@state_classes ||= []
|
12
|
+
end
|
14
13
|
|
15
|
-
|
16
|
-
|
17
|
-
|
14
|
+
def initial_state_class
|
15
|
+
@initial_state_class
|
16
|
+
end
|
18
17
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
23
|
-
end
|
18
|
+
def set_initial_state(state_class)
|
19
|
+
@initial_state_class = state_class
|
20
|
+
end
|
24
21
|
|
25
|
-
|
26
|
-
|
22
|
+
def add_states(*state_classes)
|
23
|
+
state_classes.each do |state_class|
|
24
|
+
add_state_class(state_class)
|
27
25
|
end
|
26
|
+
end
|
28
27
|
|
29
|
-
|
30
|
-
|
31
|
-
|
28
|
+
def add_state_class(state_class)
|
29
|
+
state_classes << state_class
|
30
|
+
end
|
32
31
|
|
33
|
-
|
34
|
-
|
32
|
+
def valid_transitions(transitions_hash)
|
33
|
+
@transitions_hash = transitions_hash
|
34
|
+
@transitions_hash.each do |key, value|
|
35
|
+
if !value.respond_to?(:to_ary)
|
36
|
+
@transitions_hash[key] = [value]
|
37
|
+
end
|
35
38
|
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def transitions_hash
|
42
|
+
@transitions_hash
|
43
|
+
end
|
36
44
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
end
|
45
|
+
def delegate_all_state_events
|
46
|
+
state_methods.each do |state_method|
|
47
|
+
define_method state_method do |*args|
|
48
|
+
delegate_to_event(state_method)
|
42
49
|
end
|
43
50
|
end
|
51
|
+
end
|
44
52
|
|
45
|
-
|
46
|
-
|
47
|
-
end
|
53
|
+
def state_methods
|
54
|
+
state_classes.map{|state_class| state_class.public_instance_methods(false)}.flatten.uniq
|
48
55
|
end
|
49
56
|
end
|
50
57
|
|
51
|
-
attr_accessor :current_state, :current_event
|
58
|
+
attr_accessor :current_state, :current_event
|
52
59
|
def initialize(*args)
|
53
60
|
super(*args)
|
54
|
-
self.states = {}
|
55
|
-
add_state_instances
|
56
61
|
set_state(self.class.initial_state_class)
|
57
62
|
self.class.delegate_all_state_events
|
58
63
|
end
|
59
64
|
|
60
65
|
def set_state(state_class)
|
61
|
-
|
62
|
-
self.current_state = self.states[state_class]
|
63
|
-
end
|
64
|
-
|
65
|
-
def add_state_instances
|
66
|
-
self.class.state_classes.map do |state_class|
|
67
|
-
add_state_instance(state_class)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def add_state_instance(state_class)
|
72
|
-
self.states[state_class] = state_class.new(self) if !self.states.has_key?(state_class) || self.states[state_class].nil?
|
66
|
+
self.current_state = state_class.new(self)
|
73
67
|
end
|
74
68
|
|
75
69
|
def delegate_to_event(method_name, *args)
|
@@ -85,13 +79,9 @@ module StatePattern
|
|
85
79
|
def valid_transition?(from_module, to_module)
|
86
80
|
trans = self.class.transitions_hash
|
87
81
|
return true if trans.nil?
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
(trans[from_module] == to_module ||
|
92
|
-
trans[from_module].include?(to_module)) ||
|
93
|
-
trans.has_key?([from_module, current_event]) &&
|
94
|
-
(trans[[from_module, current_event]] == to_module || trans[[from_module, current_event]].include?(to_module))
|
82
|
+
|
83
|
+
valid_transition_targets = trans[from_module] || trans[[from_module, current_event]]
|
84
|
+
valid_transition_targets && valid_transition_targets.include?(to_module)
|
95
85
|
end
|
96
86
|
|
97
87
|
def state
|
data/state_pattern.gemspec
CHANGED
data/test/state_pattern_test.rb
CHANGED
@@ -87,6 +87,16 @@ Expectations do
|
|
87
87
|
button2.press
|
88
88
|
end
|
89
89
|
end
|
90
|
+
|
91
|
+
expect ["ping", "on", "pong", "off"] do
|
92
|
+
with_test_class("PingPong", :states => ["Ping", "Pong"], :initial_state => "Pong", :transitions => {["Ping", :do_it] => "Pong", ["Pong", :do_it] => "Ping"}) do
|
93
|
+
with_test_class("Button", :states => ["On", "Off"], :initial_state => "Off", :transitions => {["On", :press] => "Off", ["Off", :press] => "On"}) do
|
94
|
+
pingpong = PingPong.new
|
95
|
+
button = Button.new
|
96
|
+
[pingpong.do_it, button.press, pingpong.do_it, button.press]
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
90
100
|
end
|
91
101
|
|
92
102
|
|
@@ -4,9 +4,9 @@ Expectations do
|
|
4
4
|
expect "up" do
|
5
5
|
with_test_class("Switch", :states => ["Up", "Down", "Middle"], :initial_state => "Middle",
|
6
6
|
:transitions => {["Up", :push_down] => "Middle",
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
["Down", :push_up] => "Middle",
|
8
|
+
["Middle", :push_up] => "Up",
|
9
|
+
["Middle", :push_down] => "Down"}) do
|
10
10
|
switch = Switch.new
|
11
11
|
switch.push_up
|
12
12
|
end
|
@@ -15,13 +15,13 @@ Expectations do
|
|
15
15
|
expect "up" do
|
16
16
|
with_test_class("Switch", :states => ["Up", "Down", "Middle"], :initial_state => "Middle",
|
17
17
|
:transitions => {["Up", :push_down] => "Middle",
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
18
|
+
["Down", :push_up] => "Middle",
|
19
|
+
["Middle", :push_up] => "Up",
|
20
|
+
["Middle", :push_down] => "Down"},
|
21
|
+
:valid_transitions => {["Up", :push_down] => "Middle",
|
22
|
+
["Down", :push_up] => "Middle",
|
23
|
+
["Middle", :push_up] => "Up",
|
24
|
+
["Middle", :push_down] => "Down"}) do
|
25
25
|
switch = Switch.new
|
26
26
|
switch.push_up
|
27
27
|
end
|
@@ -30,12 +30,24 @@ Expectations do
|
|
30
30
|
expect StatePattern::InvalidTransitionException do
|
31
31
|
with_test_class("Switch", :states => ["Up", "Down", "Middle"], :initial_state => "Middle",
|
32
32
|
:transitions => {["Up", :push_down] => "Middle",
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
33
|
+
["Down", :push_up] => "Middle",
|
34
|
+
["Middle", :push_up] => "Up",
|
35
|
+
["Middle", :push_down] => "Down"},
|
36
|
+
:valid_transitions => {["Up", :push_down] => "Middle",
|
37
|
+
["Down", :push_up] => "Middle",
|
38
|
+
["Middle", :push_down] => "Down"}) do
|
39
|
+
switch = Switch.new
|
40
|
+
switch.push_up
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
expect StatePattern::InvalidTransitionException do
|
45
|
+
with_test_class("Switch", :states => ["Up", "Down", "Middle"], :initial_state => "Middle",
|
46
|
+
:transitions => {["Up", :push_down] => "Middle",
|
47
|
+
["Down", :push_up] => "Middle",
|
48
|
+
["Middle", :push_up] => "Up",
|
49
|
+
["Middle", :push_down] => "Down"},
|
50
|
+
:valid_transitions => {"Up" => "Middle", "Down" => "Middle", "Middle" => "Down"}) do
|
39
51
|
switch = Switch.new
|
40
52
|
switch.push_up
|
41
53
|
end
|