Class: StateFu::Transition
- Includes:
- Enumerable, HasOptions, Applicable
- Defined in:
- lib/transition.rb
Overview
TODO - make transition evaluate as true if accepted, false if failed, or nil unless fired
Instance Attribute Summary collapse
-
#args ⇒ Object
(also: #arguments)
Returns the value of attribute args.
-
#binding ⇒ Object
readonly
Returns the value of attribute binding.
-
#current_hook ⇒ Object
readonly
Returns the value of attribute current_hook.
-
#current_hook_slot ⇒ Object
readonly
Returns the value of attribute current_hook_slot.
-
#errors ⇒ Object
readonly
Returns the value of attribute errors.
-
#event ⇒ Object
readonly
Returns the value of attribute event.
-
#machine ⇒ Object
readonly
Returns the value of attribute machine.
-
#object ⇒ Object
(also: #obj, #instance, #model)
readonly
Returns the value of attribute object.
-
#origin ⇒ Object
(also: #original_state, #initial_state, #from)
readonly
Returns the value of attribute origin.
-
#target ⇒ Object
(also: #destination, #final_state, #to)
readonly
Returns the value of attribute target.
Instance Method Summary collapse
-
#==(other) ⇒ Object
an accepted transition == true an unaccepted transition == false same for === (for case equality).
- #accepted? ⇒ Boolean (also: #complete?)
-
#check_requirements!(revalidate = false, fail_fast = true) ⇒ Object
raise a RequirementError unless all requirements are met.
- #current_state ⇒ Object
- #cycle? ⇒ Boolean
- #each(*a, &b) ⇒ Object
- #evaluate(method_name_or_proc) ⇒ Object (also: #call)
-
#fire!(*arguments) ⇒ Object
actually fire the transition.
- #fired? ⇒ Boolean
- #first_unmet_requirement(revalidate = false) ⇒ Object
- #first_unmet_requirement_message(revalidate = false) ⇒ Object
-
#halt!(message) ⇒ Object
halt a transition with a message can be used to back out of a transition inside eg a state entry hook.
- #halted? ⇒ Boolean
- #hooks ⇒ Object
-
#hooks_for(element, slot) ⇒ Object
Hooks.
-
#initialize(binding, event, target = nil, *argument_list, &block) ⇒ Transition
constructor
A new instance of Transition.
-
#inspect ⇒ Object
display nice and short.
-
#requirement_errors(revalidate = false, fail_fast = false) ⇒ Object
return a hash of requirement_name => evaluated message.
-
#requirements ⇒ Object
Requirements.
-
#requirements_met?(revalidate = false, fail_fast = false) ⇒ Boolean
TODO.
- #run_hook(hook) ⇒ Object
-
#unmet_requirement_messages(revalidate = false, fail_fast = false) ⇒ Object
(also: #error_messages)
TODO.
- #unmet_requirements(revalidate = false, fail_fast = false) ⇒ Object
- #valid?(*args) ⇒ Boolean
- #with(*args) ⇒ Object
- #with?(*args) ⇒ Boolean (also: #valid_with?)
Methods included from HasOptions
Methods included from Applicable
Constructor Details
#initialize(binding, event, target = nil, *argument_list, &block) ⇒ Transition
Returns a new instance of Transition.
28 29 30 31 32 33 34 35 36 37 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 |
# File 'lib/transition.rb', line 28 def initialize( binding, event, target=nil, *argument_list, &block ) # ensure we have an Event event = binding.machine.events[event] if event.is_a?(Symbol) raise( UnknownTarget.new(self, "Not an event: #{event} #{self.inspect}" )) unless event.is_a? Event @binding = binding @machine = binding.machine @object = binding.object @origin = binding.current_state # ensure we have a target target = find_event_target( event, target ) || raise( UnknownTarget.new(self, "target cannot be determined: #{target.inspect} #{self.inspect}")) @target = target @event = event @errors = [] if event.target_for_origin(origin) == target # it's a "sequence" # which is a hacky way of emulating simpler state machines with # state-local events - and in which case, the targets & origins are # valid. Quite likely this notion will be removed in time. else # ensure target is valid for the event unless event.targets.include? target raise IllegalTransition.new self, "Illegal target #{target} for #{event}" end # ensure current_state is a valid origin for the event unless event.origins.include? origin raise IllegalTransition.new( self, "Illegal event #{event.name} for current state #{binding.state_name}" ) end end machine.inject_helpers_into( self ) self.args = argument_list apply!(argument_list, &block ) # initialize arguments and eval block last end |
Instance Attribute Details
#args ⇒ Object Also known as: arguments
Returns the value of attribute args.
15 16 17 |
# File 'lib/transition.rb', line 15 def args @args end |
#binding ⇒ Object (readonly)
Returns the value of attribute binding.
15 16 17 |
# File 'lib/transition.rb', line 15 def binding @binding end |
#current_hook ⇒ Object (readonly)
Returns the value of attribute current_hook.
15 16 17 |
# File 'lib/transition.rb', line 15 def current_hook @current_hook end |
#current_hook_slot ⇒ Object (readonly)
Returns the value of attribute current_hook_slot.
15 16 17 |
# File 'lib/transition.rb', line 15 def current_hook_slot @current_hook_slot end |
#errors ⇒ Object (readonly)
Returns the value of attribute errors.
15 16 17 |
# File 'lib/transition.rb', line 15 def errors @errors end |
#event ⇒ Object (readonly)
Returns the value of attribute event.
15 16 17 |
# File 'lib/transition.rb', line 15 def event @event end |
#machine ⇒ Object (readonly)
Returns the value of attribute machine.
15 16 17 |
# File 'lib/transition.rb', line 15 def machine @machine end |
#object ⇒ Object (readonly) Also known as: obj, instance, model
Returns the value of attribute object.
15 16 17 |
# File 'lib/transition.rb', line 15 def object @object end |
#origin ⇒ Object (readonly) Also known as: original_state, initial_state, from
Returns the value of attribute origin.
15 16 17 |
# File 'lib/transition.rb', line 15 def origin @origin end |
#target ⇒ Object (readonly) Also known as: destination, final_state, to
Returns the value of attribute target.
15 16 17 |
# File 'lib/transition.rb', line 15 def target @target end |
Instance Method Details
#==(other) ⇒ Object
an accepted transition == true an unaccepted transition == false same for === (for case equality)
267 268 269 270 271 272 273 274 275 276 277 278 279 280 |
# File 'lib/transition.rb', line 267 def == other case other when true accepted? when false !accepted? when State, Symbol current_state == other.to_sym when Transition inspect == other.inspect else super( other ) end end |
#accepted? ⇒ Boolean Also known as: complete?
229 230 231 |
# File 'lib/transition.rb', line 229 def accepted? !!@accepted end |
#check_requirements!(revalidate = false, fail_fast = true) ⇒ Object
raise a RequirementError unless all requirements are met.
136 137 138 |
# File 'lib/transition.rb', line 136 def check_requirements!(revalidate=false, fail_fast=true) # TODO raise RequirementError.new( self, .inspect ) unless requirements_met?(revalidate, fail_fast) end |
#current_state ⇒ Object
234 235 236 |
# File 'lib/transition.rb', line 234 def current_state binding.current_state end |
#cycle? ⇒ Boolean
260 261 262 |
# File 'lib/transition.rb', line 260 def cycle? origin == target end |
#each(*a, &b) ⇒ Object
217 218 219 |
# File 'lib/transition.rb', line 217 def each *a, &b .each *a, &b end |
#evaluate(method_name_or_proc) ⇒ Object Also known as: call
295 296 297 |
# File 'lib/transition.rb', line 295 def evaluate(method_name_or_proc) executioner.evaluate(method_name_or_proc) end |
#fire!(*arguments) ⇒ Object
actually fire the transition
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
# File 'lib/transition.rb', line 176 def fire!(*arguments) # block? raise TransitionAlreadyFired.new(self) if fired? self.args = arguments unless arguments.empty? check_requirements! @fired = true begin # duplicated: see #hooks method StateFu::Hooks::ALL_HOOKS.map do |owner, slot| [ [owner, slot], send(owner).hooks[slot] ] end.each do |address, hooks| Logging.info("running #{address.inspect} hooks for #{object.class} #{object}") owner,slot = *address hooks.each do |hook| Logging.info("running hook #{hooks} for #{object.class} #{object}") @current_hook_slot = address @current_hook = hook run_hook hook end if slot == :entry @accepted = true @binding.persister.current_state = @target Logging.info("State is now :#{@target.name} for #{object.class} #{object}") end end # transition complete @current_hook_slot = nil @current_hook = nil rescue TransitionHalted => e Logging.info("Transition halted for #{object.class} #{object}: #{e.inspect}") @errors << e end self end |
#fired? ⇒ Boolean
225 226 227 |
# File 'lib/transition.rb', line 225 def fired? !!@fired end |
#first_unmet_requirement(revalidate = false) ⇒ Object
113 114 115 |
# File 'lib/transition.rb', line 113 def first_unmet_requirement(revalidate=false) unmet_requirements(revalidate, fail_fast=true)[0] end |
#first_unmet_requirement_message(revalidate = false) ⇒ Object
131 132 133 |
# File 'lib/transition.rb', line 131 def (revalidate=false) (first_unmet_requirement(revalidate), revalidate) end |
#halt!(message) ⇒ Object
halt a transition with a message can be used to back out of a transition inside eg a state entry hook
167 168 169 |
# File 'lib/transition.rb', line 167 def halt! raise StateFu::TransitionHalted.new( self, ) end |
#halted? ⇒ Boolean
221 222 223 |
# File 'lib/transition.rb', line 221 def halted? !@errors.empty? end |
#hooks ⇒ Object
151 152 153 154 155 |
# File 'lib/transition.rb', line 151 def hooks StateFu::Hooks::ALL_HOOKS.map do |owner, slot| [ [owner, slot], send(owner).hooks[slot] ] end end |
#hooks_for(element, slot) ⇒ Object
Hooks
147 148 149 |
# File 'lib/transition.rb', line 147 def hooks_for(element, slot) send(element).hooks[slot] end |
#inspect ⇒ Object
display nice and short
283 284 285 286 287 288 289 290 291 292 293 |
# File 'lib/transition.rb', line 283 def inspect s = self.to_s s = s[0,s.length-1] s << " event=#{event.to_sym.inspect}" if event s << " origin=#{origin.to_sym.inspect}" if origin s << " target=#{target.to_sym.inspect}" if target s << " args=#{args.inspect}" if args s << " options=#{.inspect}" if s << ">" s end |
#requirement_errors(revalidate = false, fail_fast = false) ⇒ Object
return a hash of requirement_name => evaluated message
125 126 127 128 129 |
# File 'lib/transition.rb', line 125 def requirement_errors(revalidate=false, fail_fast=false) unmet_requirements(revalidate, fail_fast). map { |requirement| [requirement, (requirement)]}. to_h end |
#requirements ⇒ Object
Requirements
92 93 94 |
# File 'lib/transition.rb', line 92 def requirements origin.exit_requirements + target.entry_requirements + event.requirements end |
#requirements_met?(revalidate = false, fail_fast = false) ⇒ Boolean
TODO
140 141 142 |
# File 'lib/transition.rb', line 140 def requirements_met?(revalidate=false, fail_fast=false) # TODO unmet_requirements(revalidate, fail_fast).empty? end |
#run_hook(hook) ⇒ Object
157 158 159 |
# File 'lib/transition.rb', line 157 def run_hook hook evaluate hook end |
#unmet_requirement_messages(revalidate = false, fail_fast = false) ⇒ Object Also known as: error_messages
TODO
117 118 119 120 121 |
# File 'lib/transition.rb', line 117 def (revalidate=false, fail_fast=false) # TODO unmet_requirements(revalidate, fail_fast).map do |requirement| (requirement, revalidate) end.extend MessageArray end |
#unmet_requirements(revalidate = false, fail_fast = false) ⇒ Object
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/transition.rb', line 96 def unmet_requirements(revalidate=false, fail_fast=false) if revalidate @unmet_requirements = nil else return @unmet_requirements if @unmet_requirements end result = [requirements].flatten.uniq.inject([]) do |unmet, requirement| unmet << requirement unless evaluate(requirement) break(unmet) if fail_fast && !unmet.empty? unmet end raise self.inspect if result.nil? # don't cache result if it might @unmet_requirements = result unless (fail_fast && unmet_requirements.length != 0) result end |
#valid?(*args) ⇒ Boolean
68 69 70 71 |
# File 'lib/transition.rb', line 68 def valid?(*args) self.args = args unless args.empty? requirements_met?(true, true) # revalidate; exit on first failure end |
#with(*args) ⇒ Object
78 79 80 81 |
# File 'lib/transition.rb', line 78 def with(*args) self.args = args unless args.empty? self end |
#with?(*args) ⇒ Boolean Also known as: valid_with?
83 84 85 |
# File 'lib/transition.rb', line 83 def with?(*args) valid? end |