Class: StateFu::Binding
Instance Attribute Summary collapse
-
#field_name ⇒ Object
readonly
Returns the value of attribute field_name.
-
#machine ⇒ Object
(also: #workflow, #state_machine)
readonly
Returns the value of attribute machine.
-
#method_name ⇒ Object
readonly
Returns the value of attribute method_name.
-
#object ⇒ Object
(also: #o, #obj, #model, #instance)
readonly
Returns the value of attribute object.
-
#options ⇒ Object
readonly
Returns the value of attribute options.
-
#persister ⇒ Object
readonly
Returns the value of attribute persister.
-
#target ⇒ Object
readonly
Returns the value of attribute target.
-
#transitions(opts = {}) ⇒ Object
readonly
transition validation.
Instance Method Summary collapse
-
#==(other) ⇒ Object
let’s be == (and hence ===) the current_state_name as a symbol.
-
#can_transition?(event, target = nil, *args) ⇒ Boolean
event_name? [target], *args.
-
#current_state ⇒ Object
(also: #now, #state)
the current State.
-
#current_state_name ⇒ Object
(also: #name, #state_name, #to_sym)
the name, as a Symbol, of the binding’s current_state.
-
#cycle(event_or_array = nil, *args, &block) ⇒ Object
if there is one possible cyclical event, return a transition there otherwise, maybe we got an event name as an argument?.
-
#cycle!(event_or_array = nil, *args, &block) ⇒ Object
if there is a single possible cycle() transition, fire and return it otherwise raise an IllegalTransition.
-
#cycle?(event_or_array = nil, *args) ⇒ Boolean
if there is one possible cyclical event, evaluate its requirements (true/false), else nil.
-
#events ⇒ Object
(also: #events_from_current_state)
returns a list of Events which can fire from the current_state.
-
#find_transition(event, target = nil, *args) ⇒ Object
event_name [target], *args.
-
#fire_transition!(event, target = nil, *args) ⇒ Object
event_name! [target], *args.
-
#initialize(machine, object, method_name, options = {}) ⇒ Binding
constructor
the constructor should not be called manually; a binding is returned when an instance of a class with a StateFu::Machine calls:.
-
#inspect ⇒ Object
display something sensible that doesn’t take up the whole screen.
- #invalid_events(*args) ⇒ Object
-
#next!(*args, &block) ⇒ Object
(also: #next_transition!, #next_event!, #next_state!)
if there is a next_transition, create, fire & return it otherwise raise an IllegalTransition.
-
#next?(*args, &block) ⇒ Boolean
if there is a next_transition, return true / false depending on whether its requirements are met otherwise, nil.
-
#next_event(*args) ⇒ Object
if there is exactly one event which is valid with the given optional arguments, return it.
-
#next_state(*args, &block) ⇒ Object
if there is exactly one state reachable via a transition which is valid with the given optional arguments, return it.
-
#next_states ⇒ Object
all states which can be reached from the current_state.
-
#next_transition(*args, &block) ⇒ Object
if there is exactly one legal & valid transition which can be fired with the given (optional) arguments, return it.
-
#next_transition_excluding_cycles(*args, &block) ⇒ Object
as above but ignoring any transitions whose origin and target are the same.
-
#reload ⇒ Object
SPECME DOCME OR KILLME.
-
#singleton? ⇒ Boolean
TODO better name is this a binding unique to a specific instance (not bound to a class)?.
-
#state_fu(name = nil) ⇒ Object
little kludge - allows the binding to reuse the same method definitions as ‘object’ in MethodFactory#method_definitions_for.
-
#teleport!(target) ⇒ Object
change the current state of the binding without any requirements or other sanity checks, or any hooks firing.
-
#transition(event_or_array, *args, &block) ⇒ Object
initializes a new Transition to the given destination, with the given *args (to be passed to requirements and hooks).
-
#update!(*args, &block) ⇒ Object
next! without the raise if there’s no next transition TODO SPECME.
- #valid_events(*args) ⇒ Object
- #valid_next_states(*args) ⇒ Object
- #valid_transitions(*args) ⇒ Object
Constructor Details
#initialize(machine, object, method_name, options = {}) ⇒ Binding
the constructor should not be called manually; a binding is returned when an instance of a class with a StateFu::Machine calls:
instance.#state_fu (for the default machine which is called :state_fu), instance.#state_fu(:<machine_name>) ,or instance.#<machine_name>
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/binding.rb', line 14 def initialize( machine, object, method_name, ={} ) @machine = machine @object = object @method_name = method_name @transitions = [] @options = .symbolize_keys! if [:singleton] @target = object else @target = object.class @options = @target.[@method_name].merge() end @field_name = @options.delete(:field_name) || raise("No field_name supplied") @persister = Persistence.for self # define event methods on this binding and its @object MethodFactory.new(self).install! @machine.helpers.inject_into self end |
Instance Attribute Details
#field_name ⇒ Object (readonly)
Returns the value of attribute field_name.
4 5 6 |
# File 'lib/binding.rb', line 4 def field_name @field_name end |
#machine ⇒ Object (readonly) Also known as: workflow, state_machine
Returns the value of attribute machine.
4 5 6 |
# File 'lib/binding.rb', line 4 def machine @machine end |
#method_name ⇒ Object (readonly)
Returns the value of attribute method_name.
4 5 6 |
# File 'lib/binding.rb', line 4 def method_name @method_name end |
#object ⇒ Object (readonly) Also known as: o, obj, model, instance
Returns the value of attribute object.
4 5 6 |
# File 'lib/binding.rb', line 4 def object @object end |
#options ⇒ Object (readonly)
Returns the value of attribute options.
4 5 6 |
# File 'lib/binding.rb', line 4 def @options end |
#persister ⇒ Object (readonly)
Returns the value of attribute persister.
4 5 6 |
# File 'lib/binding.rb', line 4 def persister @persister end |
#target ⇒ Object (readonly)
Returns the value of attribute target.
4 5 6 |
# File 'lib/binding.rb', line 4 def target @target end |
#transitions(opts = {}) ⇒ Object (readonly)
transition validation
117 118 119 |
# File 'lib/binding.rb', line 117 def transitions @transitions end |
Instance Method Details
#==(other) ⇒ Object
let’s be == (and hence ===) the current_state_name as a symbol. a nice little convenience.
260 261 262 263 264 265 266 |
# File 'lib/binding.rb', line 260 def == other if other.respond_to?( :to_sym ) && current_state current_state_name == other.to_sym || super( other ) else super( other ) end end |
#can_transition?(event, target = nil, *args) ⇒ Boolean
event_name? [target], *args
79 80 81 82 83 84 85 86 87 |
# File 'lib/binding.rb', line 79 def can_transition?(event, target=nil, *args) begin if t = find_transition(event, target, *args) t.valid?(*args) end rescue IllegalTransition, UnknownTarget nil end end |
#current_state ⇒ Object Also known as: now, state
the current State
47 48 49 |
# File 'lib/binding.rb', line 47 def current_state persister.current_state end |
#current_state_name ⇒ Object Also known as: name, state_name, to_sym
the name, as a Symbol, of the binding’s current_state
54 55 56 57 58 59 60 |
# File 'lib/binding.rb', line 54 def current_state_name begin current_state.name.to_sym rescue NoMethodError nil end end |
#cycle(event_or_array = nil, *args, &block) ⇒ Object
if there is one possible cyclical event, return a transition there otherwise, maybe we got an event name as an argument?
201 202 203 204 205 206 207 208 |
# File 'lib/binding.rb', line 201 def cycle(event_or_array=nil, *args, &block) if event_or_array.nil? transitions.cyclic.with(*args, &block).singular || transitions.cyclic.with(*args, &block).valid.singular else transitions.cyclic.with(*args, &block).find(event_or_array) end end |
#cycle!(event_or_array = nil, *args, &block) ⇒ Object
if there is a single possible cycle() transition, fire and return it otherwise raise an IllegalTransition
212 213 214 215 216 217 218 |
# File 'lib/binding.rb', line 212 def cycle!(event_or_array=nil, *args, &block ) returning cycle(event_or_array, *args, &block ) do |t| raise TransitionNotFound.new( self, transitions.cyclic.with(*args,&block), "Cannot cycle! unless there is exactly one cyclic event") \ if t.nil? t.fire! end end |
#cycle?(event_or_array = nil, *args) ⇒ Boolean
if there is one possible cyclical event, evaluate its requirements (true/false), else nil
222 223 224 225 226 |
# File 'lib/binding.rb', line 222 def cycle?(event_or_array=nil, *args ) if t = cycle(event_or_array, *args ) t.requirements_met? end end |
#events ⇒ Object Also known as: events_from_current_state
returns a list of Events which can fire from the current_state
100 101 102 103 104 |
# File 'lib/binding.rb', line 100 def events machine.events.select do |e| e.can_transition_from? current_state end.extend EventArray end |
#find_transition(event, target = nil, *args) ⇒ Object
event_name [target], *args
71 72 73 74 75 |
# File 'lib/binding.rb', line 71 def find_transition(event, target=nil, *args) target ||= args.last[:to].to_sym rescue nil query = transitions.for_event(event).to(target).with(*args) query.find || query.valid.singular || nil end |
#fire_transition!(event, target = nil, *args) ⇒ Object
event_name! [target], *args
91 92 93 |
# File 'lib/binding.rb', line 91 def fire_transition!(event, target=nil, *args) find_transition(event, target, *args).fire! end |
#inspect ⇒ Object
display something sensible that doesn’t take up the whole screen
248 249 250 251 252 253 254 255 256 |
# File 'lib/binding.rb', line 248 def inspect '<#' + self.class.to_s + ' ' + attrs = [[:current_state, state_name.inspect], [:object_type , @object.class], [:method_name , method_name.inspect], [:field_name , field_name.inspect], [:machine , machine.to_s]]. map {|x| x.join('=') }.join( " " ) + '>' end |
#invalid_events(*args) ⇒ Object
133 134 135 |
# File 'lib/binding.rb', line 133 def invalid_events(*args) (events - valid_events(*args)).extend StateArray end |
#next!(*args, &block) ⇒ Object Also known as: next_transition!, next_event!, next_state!
if there is a next_transition, create, fire & return it otherwise raise an IllegalTransition
175 176 177 178 179 180 181 |
# File 'lib/binding.rb', line 175 def next!( *args, &block ) if t = next_transition( *args, &block ) t.fire! else raise TransitionNotFound.new( self, valid_transitions(*args), "Exactly 1 valid transition required.") end end |
#next?(*args, &block) ⇒ Boolean
if there is a next_transition, return true / false depending on whether its requirements are met otherwise, nil
189 190 191 192 193 |
# File 'lib/binding.rb', line 189 def next?( *args, &block ) if t = next_transition( *args, &block ) t.requirements_met? end end |
#next_event(*args) ⇒ Object
if there is exactly one event which is valid with the given optional arguments, return it
169 170 171 |
# File 'lib/binding.rb', line 169 def next_event( *args ) transitions.with(*args, &block).next_event end |
#next_state(*args, &block) ⇒ Object
if there is exactly one state reachable via a transition which is valid with the given optional arguments, return it.
163 164 165 |
# File 'lib/binding.rb', line 163 def next_state(*args, &block) transitions.with(*args, &block).next_state end |
#next_states ⇒ Object
all states which can be reached from the current_state. Does not check transition requirements, etc.
109 110 111 |
# File 'lib/binding.rb', line 109 def next_states events.map(&:targets).compact.flatten.uniq.extend StateArray end |
#next_transition(*args, &block) ⇒ Object
if there is exactly one legal & valid transition which can be fired with the given (optional) arguments, return it.
152 153 154 |
# File 'lib/binding.rb', line 152 def next_transition( *args, &block ) transitions.with(*args, &block).next end |
#next_transition_excluding_cycles(*args, &block) ⇒ Object
as above but ignoring any transitions whose origin and target are the same
157 158 159 |
# File 'lib/binding.rb', line 157 def next_transition_excluding_cycles( *args, &block ) transitions.not_cyclic.with(*args, &block).next end |
#reload ⇒ Object
SPECME DOCME OR KILLME
275 276 277 278 279 280 281 |
# File 'lib/binding.rb', line 275 def reload() if persister.is_a?( Persistence::ActiveRecord ) object.reload end persister.reload self end |
#singleton? ⇒ Boolean
TODO better name is this a binding unique to a specific instance (not bound to a class)?
270 271 272 |
# File 'lib/binding.rb', line 270 def singleton? [:singleton] end |
#state_fu(name = nil) ⇒ Object
little kludge - allows the binding to reuse the same method definitions as ‘object’ in MethodFactory#method_definitions_for
296 297 298 |
# File 'lib/binding.rb', line 296 def state_fu(name=nil) self end |
#teleport!(target) ⇒ Object
change the current state of the binding without any requirements or other sanity checks, or any hooks firing. Useful for test / spec scenarios, and abusing the framework.
243 244 245 |
# File 'lib/binding.rb', line 243 def teleport!( target ) persister.current_state=( machine.states[target] ) end |
#transition(event_or_array, *args, &block) ⇒ Object
initializes a new Transition to the given destination, with the given *args (to be passed to requirements and hooks).
If a block is given, it yields the Transition or is executed in its evaluation context, depending on the arity of the block.
143 144 145 |
# File 'lib/binding.rb', line 143 def transition( event_or_array, *args, &block ) return transitions.with(*args, &block).find(event_or_array) end |
#update!(*args, &block) ⇒ Object
next! without the raise if there’s no next transition TODO SPECME
230 231 232 233 234 |
# File 'lib/binding.rb', line 230 def update!( *args, &block ) if t = next_transition( *args, &block ) t.fire! end end |
#valid_events(*args) ⇒ Object
129 130 131 |
# File 'lib/binding.rb', line 129 def valid_events(*args) valid_transitions(*args).events end |
#valid_next_states(*args) ⇒ Object
125 126 127 |
# File 'lib/binding.rb', line 125 def valid_next_states(*args) valid_transitions(*args).targets end |
#valid_transitions(*args) ⇒ Object
121 122 123 |
# File 'lib/binding.rb', line 121 def valid_transitions(*args) transitions.valid.with(*args) end |