| Class | StateMachine::Branch |
| In: |
lib/state_machine/branch.rb
|
| Parent: | Object |
Represents a set of requirements that must be met in order for a transition or callback to occur. Branches verify that the event, from state, and to state of the transition match, in addition to if/unless conditionals for an object‘s state.
| event_requirement | [R] | The requirement for verifying the event being matched |
| if_condition | [R] | The condition that must be met on an object |
| known_states | [R] |
A list of all of the states known to this branch. This will pull states
from the following options (in the same order):
|
| state_requirements | [R] | One or more requirements for verifying the states being matched. All requirements contain a mapping of {:from => matcher, :to => matcher}. |
| unless_condition | [R] | The condition that must not be met on an object |
Draws a representation of this branch on the given graph. This will draw an edge between every state this branch matches from to either the configured to state or, if none specified, then a loopback to the from state.
For example, if the following from states are configured:
…and the to state is parked, then the following edges will be created:
Each edge will be labeled with the name of the event that would cause the transition.
The collection of edges generated on the graph will be returned.
# File lib/state_machine/branch.rb, line 145
145: def draw(graph, event, valid_states)
146: state_requirements.inject([]) do |edges, state_requirement|
147: # From states determined based on the known valid states
148: from_states = state_requirement[:from].filter(valid_states)
149:
150: # If a to state is not specified, then it's a loopback and each from
151: # state maps back to itself
152: if state_requirement[:to].values.empty?
153: loopback = true
154: else
155: to_state = state_requirement[:to].values.first
156: to_state = to_state ? to_state.to_s : 'nil'
157: loopback = false
158: end
159:
160: # Generate an edge between each from and to state
161: from_states.each do |from_state|
162: from_state = from_state ? from_state.to_s : 'nil'
163: edges << graph.add_edge(from_state, loopback ? from_state : to_state, :label => event.to_s)
164: end
165:
166: edges
167: end
168: end
Attempts to match the given object / query against the set of requirements configured for this branch. In addition to matching the event, from state, and to state, this will also check whether the configured :if/:unless conditions pass on the given object.
If a match is found, then the event/state requirements that the query passed successfully will be returned. Otherwise, nil is returned if there was no match.
Query options:
branch = StateMachine::Branch.new(:parked => :idling, :on => :ignite)
branch.match(object, :on => :ignite) # => {:to => ..., :from => ..., :on => ...}
branch.match(object, :on => :park) # => nil
# File lib/state_machine/branch.rb, line 118
118: def match(object, query = {})
119: assert_valid_keys(query, :from, :to, :on, :guard)
120:
121: if (match = match_query(query)) && matches_conditions?(object, query)
122: match
123: end
124: end
Determines whether the given object / query matches the requirements configured for this branch. In addition to matching the event, from state, and to state, this will also check whether the configured :if/:unless conditions pass on the given object.
branch = StateMachine::Branch.new(:parked => :idling, :on => :ignite) # Successful branch.matches?(object, :on => :ignite) # => true branch.matches?(object, :from => nil) # => true branch.matches?(object, :from => :parked) # => true branch.matches?(object, :to => :idling) # => true branch.matches?(object, :from => :parked, :to => :idling) # => true branch.matches?(object, :on => :ignite, :from => :parked, :to => :idling) # => true # Unsuccessful branch.matches?(object, :on => :park) # => false branch.matches?(object, :from => :idling) # => false branch.matches?(object, :to => :first_gear) # => false branch.matches?(object, :from => :parked, :to => :first_gear) # => false branch.matches?(object, :on => :park, :from => :parked, :to => :idling) # => false
# File lib/state_machine/branch.rb, line 89
89: def matches?(object, query = {})
90: !match(object, query).nil?
91: end
Builds a matcher strategy to use for the given options. If neither a whitelist nor a blacklist option is specified, then an AllMatcher is built.
# File lib/state_machine/branch.rb, line 174
174: def build_matcher(options, whitelist_option, blacklist_option)
175: assert_exclusive_keys(options, whitelist_option, blacklist_option)
176:
177: if options.include?(whitelist_option)
178: WhitelistMatcher.new(options[whitelist_option])
179: elsif options.include?(blacklist_option)
180: BlacklistMatcher.new(options[blacklist_option])
181: else
182: AllMatcher.instance
183: end
184: end
Verifies that the event requirement matches the given query
# File lib/state_machine/branch.rb, line 198
198: def match_event(query)
199: matches_requirement?(query, :on, event_requirement)
200: end
Verifies that all configured requirements (event and state) match the given query. If a match is found, then a hash containing the event/state requirements that passed will be returned; otherwise, nil.
# File lib/state_machine/branch.rb, line 189
189: def match_query(query)
190: query ||= {}
191:
192: if match_event(query) && (state_requirement = match_states(query))
193: state_requirement.merge(:on => event_requirement)
194: end
195: end
Verifies that the state requirements match the given query. If a matching requirement is found, then it is returned.
# File lib/state_machine/branch.rb, line 204
204: def match_states(query)
205: state_requirements.detect do |state_requirement|
206: [:from, :to].all? {|option| matches_requirement?(query, option, state_requirement[option])}
207: end
208: end
Verifies that the conditionals for this branch evaluate to true for the given object
# File lib/state_machine/branch.rb, line 218
218: def matches_conditions?(object, query)
219: query[:guard] == false ||
220: Array(if_condition).all? {|condition| evaluate_method(object, condition)} &&
221: !Array(unless_condition).any? {|condition| evaluate_method(object, condition)}
222: end