Class: StateManager::Base
- Inherits:
-
State
- Object
- State
- StateManager::Base
show all
- Extended by:
- DSL::Base
- Defined in:
- lib/state_manager/base.rb,
lib/state_manager/dsl.rb,
lib/state_manager/serialization.rb,
lib/state_manager/serialization.rb
Overview
The base StateManager class is responsible for tracking the current state
of an object as well as managing the transitions between states.
Instance Attribute Summary collapse
Attributes inherited from State
#name, #parent_state, #states
Class Method Summary
collapse
Instance Method Summary
collapse
Methods included from DSL::Base
resource_class, resource_name, state_property
Methods inherited from State
create_resource_accessor!, #enter, #entered, #exit, #exited, #find_state, #find_states, #has_event?, #initial_state, #leaf?, #path, #perform_event, #to_sym
Methods included from DSL::State
#event, #initial_state, #state
#delayed_events, #entered, #exited
Constructor Details
#initialize(resource, context = {}) ⇒ Base
Returns a new instance of Base.
18
19
20
21
22
23
24
25
26
27
|
# File 'lib/state_manager/base.rb', line 18
def initialize(resource, context={})
super(nil, nil)
self.resource = resource
self.context = context
if perform_initial_transition?
initial_path = current_state && current_state.path || initial_state.path
transition_to initial_path, nil
end
end
|
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
in the class StateManager::State
Instance Attribute Details
#context ⇒ Object
Returns the value of attribute context.
16
17
18
|
# File 'lib/state_manager/base.rb', line 16
def context
@context
end
|
#resource ⇒ Object
Returns the value of attribute resource.
16
17
18
|
# File 'lib/state_manager/base.rb', line 16
def resource
@resource
end
|
Class Method Details
.added_to_resource(klass, property, options) ⇒ Object
181
182
|
# File 'lib/state_manager/base.rb', line 181
def self.added_to_resource(klass, property, options)
end
|
.infer_resource_name! ⇒ Object
168
169
170
171
172
173
174
|
# File 'lib/state_manager/base.rb', line 168
def self.infer_resource_name!
return if _resource_name
if name =~ /States/
self._resource_name = name.demodulize.gsub(/States/, '').underscore
create_resource_accessor!(_resource_name)
end
end
|
.inherited(base) ⇒ Object
176
177
178
179
|
# File 'lib/state_manager/base.rb', line 176
def self.inherited(base)
super(base)
base.infer_resource_name!
end
|
.yaml_new(klass, tag, val) ⇒ Object
7
8
9
|
# File 'lib/state_manager/serialization.rb', line 7
def self.yaml_new(klass, tag, val)
klass.new(val['resource'], val['context'])
end
|
Instance Method Details
#available_events ⇒ Object
All events the current state will respond to
158
159
160
161
162
163
164
165
166
|
# File 'lib/state_manager/base.rb', line 158
def available_events
state = current_state
ret = {}
while(state) do
ret = state.class.specification.events.merge(ret)
state = state.parent_state
end
ret
end
|
#current_state ⇒ Object
76
77
78
79
|
# File 'lib/state_manager/base.rb', line 76
def current_state
path = read_state
find_state(path) if path && !path.empty?
end
|
#current_state=(value) ⇒ Object
81
82
83
|
# File 'lib/state_manager/base.rb', line 81
def current_state=(value)
write_state(value)
end
|
#did_transition(from, to, event) ⇒ Object
154
155
|
# File 'lib/state_manager/base.rb', line 154
def did_transition(from, to, event)
end
|
#encode_with(coder) ⇒ Object
19
20
21
22
23
24
|
# File 'lib/state_manager/serialization.rb', line 19
def encode_with(coder)
coder.map = {
"resource" => resource,
"context" => context
}
end
|
#find_state_for_event(name) ⇒ Object
104
105
106
107
108
109
110
|
# File 'lib/state_manager/base.rb', line 104
def find_state_for_event(name)
state = current_state
while(state) do
return state if state.has_event?(name)
state = state.parent_state
end
end
|
#has_state? ⇒ Boolean
Will not have a state if the state is invalid or nil
135
136
137
|
# File 'lib/state_manager/base.rb', line 135
def has_state?
!!current_state
end
|
#in_state?(path) ⇒ Boolean
Returns true if the underlying object is in the state specified by the
given path. An object is 'in' a state if the state lies at any point of
the current state's path. E.g:
state_manager.current_state.path state_manager.in_state? 'outer' state_manager.in_state? 'outer.inner' state_manager.in_state? 'inner'
130
131
132
|
# File 'lib/state_manager/base.rb', line 130
def in_state?(path)
self.find_states(current_state.path).include? find_state(path)
end
|
#init_with(coder) ⇒ Object
26
27
28
|
# File 'lib/state_manager/serialization.rb', line 26
def init_with(coder)
initialize(coder["resource"], coder["context"])
end
|
In the case of a new model, we wan't to transition into the initial state
and fire the appropriate callbacks. The default behavior is to just check
if the state field is nil.
32
33
34
|
# File 'lib/state_manager/base.rb', line 32
def perform_initial_transition?
!current_state
end
|
#persist_state ⇒ Object
148
149
|
# File 'lib/state_manager/base.rb', line 148
def persist_state
end
|
#read_state ⇒ Object
144
145
146
|
# File 'lib/state_manager/base.rb', line 144
def read_state
resource.send self.class._state_property
end
|
#respond_to_event?(name) ⇒ Boolean
100
101
102
|
# File 'lib/state_manager/base.rb', line 100
def respond_to_event?(name)
!!find_state_for_event(name)
end
|
#send_event(name, *args) ⇒ Object
91
92
93
94
95
96
97
98
|
# File 'lib/state_manager/base.rb', line 91
def send_event(name, *args)
self.current_event = name
state = find_state_for_event(name)
raise(InvalidEvent, name) unless state
result = state.perform_event name, *args
self.current_event = nil
result
end
|
#send_event!(name, *args) ⇒ Object
85
86
87
88
89
|
# File 'lib/state_manager/base.rb', line 85
def send_event!(name, *args)
result = send_event(name, *args)
persist_state
result
end
|
#state_manager ⇒ Object
112
113
114
|
# File 'lib/state_manager/base.rb', line 112
def state_manager
self
end
|
#to_s ⇒ Object
116
117
118
119
|
# File 'lib/state_manager/base.rb', line 116
def to_s
path = "#{current_state.path}" if current_state
"#<%s:0x%x:%s>" % [self.class, object_id, path]
end
|
#to_yaml_properties ⇒ Object
11
12
13
|
# File 'lib/state_manager/serialization.rb', line 11
def to_yaml_properties
['@resource', '@context']
end
|
#transition_to(path, current_state = self.current_state) ⇒ Object
Transitions to the state at the specified path. The path can be relative
to any state along the current state's path.
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
# File 'lib/state_manager/base.rb', line 38
def transition_to(path, current_state=self.current_state)
path = path.to_s
state = current_state || self
exit_states = []
new_states = state.find_states(path)
while(!new_states) do
exit_states << state
state = state.parent_state
raise(StateNotFound, path) unless state
new_states = state.find_states(path)
end
new_states.unshift(self) unless has_state?
raise(InvalidTransition, path) unless new_states.last.leaf?
enter_states = new_states - exit_states
exit_states = exit_states - new_states
from_state = current_state
to_state = enter_states.last || from_state
run_before_callbacks(from_state, to_state, current_event, enter_states, exit_states)
self.current_state = to_state
run_after_callbacks(from_state, to_state, current_event, enter_states, exit_states)
end
|
#will_transition(from, to, event) ⇒ Object
151
152
|
# File 'lib/state_manager/base.rb', line 151
def will_transition(from, to, event)
end
|
#write_state(value) ⇒ Object
These methods can be overriden by an adapter
140
141
142
|
# File 'lib/state_manager/base.rb', line 140
def write_state(value)
resource.send "#{self.class._state_property.to_s}=", value.path
end
|