Class: Golem::Model::StateMachine
- Inherits:
-
Object
- Object
- Golem::Model::StateMachine
- Defined in:
- lib/golem/model/state_machine.rb
Instance Attribute Summary collapse
-
#events ⇒ Object
readonly
Returns the value of attribute events.
-
#name ⇒ Object
Returns the value of attribute name.
-
#on_all_events ⇒ Object
Callback executed on every successful event.
-
#on_all_transitions ⇒ Object
Callback executed on every successful transition.
-
#state_attribute ⇒ Object
Returns the value of attribute state_attribute.
-
#state_attribute_reader ⇒ Object
Returns the value of attribute state_attribute_reader.
-
#state_attribute_writer ⇒ Object
Returns the value of attribute state_attribute_writer.
-
#states ⇒ Object
readonly
Returns the value of attribute states.
-
#transition_errors ⇒ Object
Returns the value of attribute transition_errors.
Instance Method Summary collapse
- #all_events ⇒ Object
- #all_states ⇒ Object
- #determine_transition_on_event(obj, event, *args) ⇒ Object
- #fire_event(obj, event, *args) ⇒ Object
- #fire_event_with_exceptions(obj, event, *args) ⇒ Object
- #fire_event_without_exceptions(obj, event, *args) ⇒ Object
- #get_current_state_of(obj) ⇒ Object
- #get_or_define_event(event) ⇒ Object
- #get_or_define_state(state) ⇒ Object
- #init(obj) ⇒ Object
- #initial_state ⇒ Object
- #initial_state=(state) ⇒ Object
-
#initialize(name) ⇒ StateMachine
constructor
A new instance of StateMachine.
-
#is_transitioning? ⇒ Boolean
true if this statemachine is currently in the middle of a transition.
- #set_current_state_of(obj, state) ⇒ Object
Constructor Details
#initialize(name) ⇒ StateMachine
Returns a new instance of StateMachine.
25 26 27 28 29 30 31 32 |
# File 'lib/golem/model/state_machine.rb', line 25 def initialize(name) @name = name @states = Golem::Util::ElementCollection.new(Golem::Model::State) @events = Golem::Util::ElementCollection.new(Golem::Model::Event) @transition_errors = [] @throw_exceptions = false @is_transitioning = false end |
Instance Attribute Details
#events ⇒ Object (readonly)
Returns the value of attribute events.
16 17 18 |
# File 'lib/golem/model/state_machine.rb', line 16 def events @events end |
#name ⇒ Object
Returns the value of attribute name.
11 12 13 |
# File 'lib/golem/model/state_machine.rb', line 11 def name @name end |
#on_all_events ⇒ Object
Callback executed on every successful event.
23 24 25 |
# File 'lib/golem/model/state_machine.rb', line 23 def on_all_events @on_all_events end |
#on_all_transitions ⇒ Object
Callback executed on every successful transition.
20 21 22 |
# File 'lib/golem/model/state_machine.rb', line 20 def on_all_transitions @on_all_transitions end |
#state_attribute ⇒ Object
Returns the value of attribute state_attribute.
12 13 14 |
# File 'lib/golem/model/state_machine.rb', line 12 def state_attribute @state_attribute end |
#state_attribute_reader ⇒ Object
Returns the value of attribute state_attribute_reader.
13 14 15 |
# File 'lib/golem/model/state_machine.rb', line 13 def state_attribute_reader @state_attribute_reader end |
#state_attribute_writer ⇒ Object
Returns the value of attribute state_attribute_writer.
14 15 16 |
# File 'lib/golem/model/state_machine.rb', line 14 def state_attribute_writer @state_attribute_writer end |
#states ⇒ Object (readonly)
Returns the value of attribute states.
15 16 17 |
# File 'lib/golem/model/state_machine.rb', line 15 def states @states end |
#transition_errors ⇒ Object
Returns the value of attribute transition_errors.
17 18 19 |
# File 'lib/golem/model/state_machine.rb', line 17 def transition_errors @transition_errors end |
Instance Method Details
#all_events ⇒ Object
47 48 49 |
# File 'lib/golem/model/state_machine.rb', line 47 def all_events @events end |
#all_states ⇒ Object
43 44 45 |
# File 'lib/golem/model/state_machine.rb', line 43 def all_states @states end |
#determine_transition_on_event(obj, event, *args) ⇒ Object
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/golem/model/state_machine.rb', line 121 def determine_transition_on_event(obj, event, *args) event = @events[event] unless event.is_a?(Golem::Model::Event) from_state = states[get_current_state_of(obj)] possible_transitions = from_state.transitions_on_event[event.name] selected_transition = determine_transition(possible_transitions, obj, *args) if selected_transition.nil? if @cannot_transition_because.blank? msg = "#{event.name.to_s.inspect} is not a valid action for #{obj} because no outgoing transitions are available when #{name.blank? ? "the state" : "#{name} "} is #{from_state}." msg << "\n\tPossible transitions are: \n\t\t#{possible_transitions.collect.collect{|t| t.to_s}.join("\n\t\t")}" unless possible_transitions.blank? elsif @cannot_transition_because.length == 1 msg = "#{event.name.to_s.inspect} is not a valid action for #{obj} because #{@cannot_transition_because.first}." else msg = "#{event.name.to_s.inspect} is not a valid action for #{obj} because #{@cannot_transition_because.uniq.join(" and ")}" end if @throw_exceptions raise Golem::ImpossibleEvent.new(msg, event, obj, @cannot_transition_because) else obj.transition_errors << msg end end return selected_transition end |
#fire_event(obj, event, *args) ⇒ Object
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/golem/model/state_machine.rb', line 79 def fire_event(obj, event, *args) @transition_errors = [] transition = determine_transition_on_event(obj, event, *args) on_all_events.call(obj, event, args) if on_all_events if transition @is_transitioning = true before_state = states[get_current_state_of(obj)] before_state.callbacks[:on_exit].call(obj, *args) if before_state.callbacks[:on_exit] set_current_state_of(obj, transition.to.name) transition.callbacks[:on_transition].call(obj, *args) if transition.callbacks[:on_transition] on_all_transitions.call(obj, event, transition, *args) if on_all_transitions after_state = states[get_current_state_of(obj)] after_state.callbacks[:on_enter].call(obj, *args) if after_state.callbacks[:on_enter] @is_transitioning = false save_result = true if obj.respond_to?(:save!) if @throw_exceptions save_result = obj.save! else (save_result = obj.save!) rescue return false end elsif obj.respond_to?(:save) if @throw_exceptions save_result = obj.save else (save_result = obj.save) rescue return false end end return save_result else return false end end |
#fire_event_with_exceptions(obj, event, *args) ⇒ Object
69 70 71 72 |
# File 'lib/golem/model/state_machine.rb', line 69 def fire_event_with_exceptions(obj, event, *args) @throw_exceptions = true fire_event(obj, event, *args) end |
#fire_event_without_exceptions(obj, event, *args) ⇒ Object
74 75 76 77 |
# File 'lib/golem/model/state_machine.rb', line 74 def fire_event_without_exceptions(obj, event, *args) @throw_exceptions = false fire_event(obj, event, *args) end |
#get_current_state_of(obj) ⇒ Object
56 57 58 |
# File 'lib/golem/model/state_machine.rb', line 56 def get_current_state_of(obj) obj.send(state_attribute) end |
#get_or_define_event(event) ⇒ Object
164 165 166 167 168 169 170 171 172 173 174 175 176 177 |
# File 'lib/golem/model/state_machine.rb', line 164 def get_or_define_event(event) if events[event] return events[event] else case event when Golem::Model::Event return events[event] = event when String, Symbol return events[event] = Golem::Model::Event.new(event) else raise ArgumentError, "Event must be a Golem::Model::Event, String, or Symbol but is a #{event.class}" end end end |
#get_or_define_state(state) ⇒ Object
149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
# File 'lib/golem/model/state_machine.rb', line 149 def get_or_define_state(state) if states[state] return states[state] else case state when Golem::Model::State return states[state] = state when String, Symbol return states[state] = Golem::Model::State.new(state) else raise ArgumentError, "State must be a Golem::Model::State, String, or Symbol but is a #{state.class}" end end end |
#init(obj) ⇒ Object
64 65 66 67 |
# File 'lib/golem/model/state_machine.rb', line 64 def init(obj) # set the initial state set_current_state_of(obj, get_current_state_of(obj) || initial_state) end |
#initial_state ⇒ Object
34 35 36 |
# File 'lib/golem/model/state_machine.rb', line 34 def initial_state @initial_state end |
#initial_state=(state) ⇒ Object
38 39 40 41 |
# File 'lib/golem/model/state_machine.rb', line 38 def initial_state=(state) # for the sake of readability in debugging, we store initial state by name rather than by reference to a State object @initial_state = state.name end |
#is_transitioning? ⇒ Boolean
true if this statemachine is currently in the middle of a transition
52 53 54 |
# File 'lib/golem/model/state_machine.rb', line 52 def is_transitioning? @is_transitioning end |
#set_current_state_of(obj, state) ⇒ Object
60 61 62 |
# File 'lib/golem/model/state_machine.rb', line 60 def set_current_state_of(obj, state) obj.send("#{state_attribute}=".to_sym, state) end |