simple_machine 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/README.rdoc +26 -13
- data/lib/simple_machine.rb +18 -7
- data/spec/spec_simple_machine.rb +47 -3
- metadata +4 -4
data/README.rdoc
CHANGED
@@ -15,16 +15,24 @@ After requiring 'simple_machine' inject state machine in your class like this:
|
|
15
15
|
|
16
16
|
class Phone
|
17
17
|
include SimpleMachine
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
18
|
+
implement_state_machine_for :my_state do
|
19
|
+
initial_state :off
|
20
|
+
other_states :ready, :dialing, :busy
|
21
|
+
allow_transition :turn_on, :from => :off, :to => :ready
|
22
|
+
allow_transition :dial, :from => :ready, :to => :dialing
|
23
|
+
allow_transition :hangup, :from => :dialing, :to => :ready
|
24
|
+
allow_transition :hangup, :from => :busy, :to => :ready
|
25
|
+
allow_transition :turn_off, :from => :ready, :to => :off do
|
26
|
+
# self is set to phone instance
|
27
|
+
puts my_state #=> :ready
|
28
|
+
# do something before transition ...
|
29
|
+
true # state will be changed to :off if block returns true
|
30
|
+
end
|
31
|
+
after_transition do
|
32
|
+
# self is set to phone instance
|
33
|
+
puts "New state is '#{my_state}'"
|
34
|
+
end
|
35
|
+
end
|
28
36
|
end
|
29
37
|
|
30
38
|
This chunk of code produces following effects:
|
@@ -56,11 +64,16 @@ In this case even if +dial+ is allowed transition from +ready+ state this is wha
|
|
56
64
|
|
57
65
|
=== Callback
|
58
66
|
|
59
|
-
After each transition callback is invoked
|
67
|
+
After each transition callback is invoked if it is defined:
|
60
68
|
|
61
69
|
class Phone
|
62
|
-
|
63
|
-
|
70
|
+
include SimpleMachine
|
71
|
+
implement_state_machine_for :my_state do
|
72
|
+
# ...
|
73
|
+
after_transition do
|
74
|
+
# self is set to phone instance
|
75
|
+
puts "New state is '#{my_state}'"
|
76
|
+
end
|
64
77
|
end
|
65
78
|
end
|
66
79
|
|
data/lib/simple_machine.rb
CHANGED
@@ -38,7 +38,10 @@ module SimpleMachine
|
|
38
38
|
result = @defined_transitions[from_state].inject(false) { |sum, hash| sum || hash[:transition] == transition }
|
39
39
|
return result
|
40
40
|
end
|
41
|
-
def
|
41
|
+
def after_transition(&block)
|
42
|
+
@after_transition = block
|
43
|
+
end
|
44
|
+
def allow_transition(transition, options, &block)
|
42
45
|
@defined_transitions ||= {}
|
43
46
|
raise "Unknown source state #{options[:from]}. Please define it first as initial_state or in other_states." unless all_states.include?(options[:from])
|
44
47
|
raise "Unknown target state #{options[:to]}. Please define it first as initial_state or in other_states." unless all_states.include?(options[:to])
|
@@ -47,6 +50,8 @@ module SimpleMachine
|
|
47
50
|
@defined_transitions[options[:from]] = [] unless @defined_transitions.has_key?(options[:from])
|
48
51
|
@defined_transitions[options[:from]] << { :transition => transition, :target_state => options[:to] }
|
49
52
|
|
53
|
+
transition_block = block_given? ? block : false
|
54
|
+
|
50
55
|
class_eval do
|
51
56
|
define_method "can_#{transition}?" do
|
52
57
|
allowed_transitions.include? transition
|
@@ -58,11 +63,17 @@ module SimpleMachine
|
|
58
63
|
else
|
59
64
|
raise "Invalid transition ##{transition.to_s.gsub '_', ' '} from '#{current_state}' state"
|
60
65
|
end unless allowed_transitions.include? transition
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
+
|
67
|
+
if !transition_block or @owner.instance_eval( &transition_block )
|
68
|
+
variable = "@#{self.class.parents_state_field_name}"
|
69
|
+
result = @owner.instance_eval { instance_variable_set variable, options[:to] }
|
70
|
+
# after_transition callback
|
71
|
+
after_transition_block = self.class.instance_eval { @after_transition }
|
72
|
+
@owner.instance_eval &after_transition_block if after_transition_block
|
73
|
+
result
|
74
|
+
else
|
75
|
+
false
|
76
|
+
end
|
66
77
|
end
|
67
78
|
end
|
68
79
|
end
|
@@ -70,7 +81,7 @@ module SimpleMachine
|
|
70
81
|
end
|
71
82
|
|
72
83
|
module ClassMethods
|
73
|
-
|
84
|
+
|
74
85
|
def implement_state_machine_for(state_field_name, &block)
|
75
86
|
machine_property_name = "#{state_field_name}_machine".to_sym
|
76
87
|
default_state_field_name = "#{state_field_name}_default_state".to_sym
|
data/spec/spec_simple_machine.rb
CHANGED
@@ -108,9 +108,50 @@ describe SimpleMachine, "for :dispatch_state field on Job, when state machine is
|
|
108
108
|
|
109
109
|
job.dispatch_state.should be(:assigned)
|
110
110
|
end
|
111
|
-
it "calls
|
112
|
-
|
113
|
-
Job.new
|
111
|
+
it "calls after_transition callback if defined" do
|
112
|
+
rspec = self
|
113
|
+
job = Job.new
|
114
|
+
@inner_state_machine_class.after_transition do
|
115
|
+
puts "After transition"
|
116
|
+
dispatch_state.should rspec.be(:assigned)
|
117
|
+
self.should rspec.be(job)
|
118
|
+
end
|
119
|
+
job.dispatch_state_machine.assign.should be(:assigned)
|
120
|
+
|
121
|
+
@inner_state_machine_class.instance_eval { instance_variable_set :@after_transition, nil }
|
122
|
+
end
|
123
|
+
context "when block is given" do
|
124
|
+
before :each do
|
125
|
+
@inner_state_machine_class.expects(:defined_transition?).with(:assign, :waiting).returns(false)
|
126
|
+
end
|
127
|
+
it "executes block" do
|
128
|
+
rspec = self
|
129
|
+
job = Job.new
|
130
|
+
@inner_state_machine_class.allow_transition :assign, :from => :waiting, :to => :assigned do
|
131
|
+
dispatch_state.should rspec.be(:waiting)
|
132
|
+
self.should rspec.be(job)
|
133
|
+
true
|
134
|
+
end
|
135
|
+
|
136
|
+
job.dispatch_state_machine.assign.should be(:assigned)
|
137
|
+
end
|
138
|
+
it "changes state if block returned true" do
|
139
|
+
@inner_state_machine_class.allow_transition :assign, :from => :waiting, :to => :assigned do
|
140
|
+
true
|
141
|
+
end
|
142
|
+
|
143
|
+
job = Job.new
|
144
|
+
job.dispatch_state_machine.assign.should be(:assigned)
|
145
|
+
end
|
146
|
+
it "doesn't change state if block returned false" do
|
147
|
+
@inner_state_machine_class.allow_transition :assign, :from => :waiting, :to => :assigned do
|
148
|
+
false
|
149
|
+
end
|
150
|
+
|
151
|
+
job = Job.new
|
152
|
+
job.dispatch_state_machine.assign.should be(false)
|
153
|
+
job.dispatch_state.should be(:waiting)
|
154
|
+
end
|
114
155
|
end
|
115
156
|
end
|
116
157
|
context "when it is not valid transition from current state" do
|
@@ -159,7 +200,10 @@ describe SimpleMachine, "for :dispatch_state field on Job, when state machine is
|
|
159
200
|
end
|
160
201
|
context "when there are more job instances" do
|
161
202
|
before :all do
|
203
|
+
Job.new.dispatch_state_machine.class.expects(:defined_transition?).with(:assign, :waiting).returns false
|
204
|
+
Job.new.dispatch_state_machine.class.expects(:defined_transition?).with(:accept, :assigned)
|
162
205
|
Job.implement_state_machine_for :dispatch_state do
|
206
|
+
allow_transition :assign, :from => :waiting, :to => :assigned
|
163
207
|
allow_transition :accept, :from => :assigned, :to => :accepted
|
164
208
|
end
|
165
209
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: simple_machine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 21
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 1.0.
|
9
|
+
- 1
|
10
|
+
version: 1.0.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Milan Burmaja
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-12-
|
18
|
+
date: 2010-12-16 00:00:00 +01:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|