Class: WebFlow::FlowStep
- Inherits:
-
Object
- Object
- WebFlow::FlowStep
- Defined in:
- lib/webflow/flow_step.rb
Overview
The FlowStep is a superclass from which every step type inherits. It’s methods are therefore available to any step type present in the WebFlow framework.
Mapping instructions
The mapping instructions common to every step type are the following.
on
The on
instruction is used to map a returned event name to a subsequent step. Here’s a simple example of it’s usage.
action_step :example_step do
(...)
on :success => :next_step_name
on :back => :previous_step_name
end
In the previous example, the example step will route the flow to the step named next_step_name
if the step definition returns an event which is named success
. If the step definition returns a back
event, the flow will then call the previous_step_name
step.
upon
The upon
instruction is used to map a raised error class to a subsequent step. Here’s a simple example of it’s usage.
action_step :example_step do
(...)
upon :StandardError => :next_step_name
end
In the previous example, the example step will route the flow to the step named next_step_name
if the step definition raises an error which is a kind of StandardError
. If the upon instruction is used more than once, the first declaration has priority. Also note that the kind_of?
method is used to validate the correspondence, so subclasses of mapped error classes will be included as well.
method
The method
instruction is meant to override the default step definition name. By default, the definition of a given step has to be declared with the same name as the step name in the mapping. If a step is named my_jolly_step
, the controller has to implement the step logic with a def
block which is named my_jolly_step
.
The method
instruction will tell the WebFlow framework to look for a definition of the given value instead of looking for the same name. This allows to reuse business logic and decouple the mapping from the step implementation. One could then do something like :
class MyController < WebFlow::Base
def initialize
(...)
action_step :step_1 do
method :shared_implementation
(...)
end
action_step :step_2 do
method :shared_implementation
(...)
end
end
def shared_implementation
(...)
end
end
Developer infos
This class defines a basic skeleton for different step types used by the WebFlow framework. All new step types must inherit of this superclass to be usable in the WebFlow controller.
It is also the responsibility of any subclass to add it’s declaration method in the WebFlow::Base class. See view_step.rb for an example.
Also, subclasses can change the @definition_required instance variable value to tell the WebFlow framework that it can handle the execution without the user controller defining explicitly a step implementation. See view_step.rb(initialize) for an example.
Event outcomes are defined in the @outcomes instance variable while the error handlers are defined in the @handlers instance variable. Those variables are protected, so any subclasses of FlowStep can access them and hack the mechanism if required.
Direct Known Subclasses
Instance Method Summary collapse
-
#definition_required? ⇒ Boolean
Used to know if the step needs an explicitly declared step definition or if it can manage the task with a default behavior.
-
#execute(*args) ⇒ Object
Method signature to override in implementing classes.
-
#handler(error_class) ⇒ Object
Returns the appropriate step name to execute upon the given error class.
-
#handles?(error_class) ⇒ Boolean
Tells if the error class passed as an argument is handled.
-
#has_an_outcome_for?(event_name) ⇒ Boolean
Tells if the given event name is a possibe outcome of this step.
-
#method(method_name) ⇒ Object
Maps a method name to execute instead of searching the controller for a method name who is the same as the step name.
-
#on(options) ⇒ Object
Maps an event to a method call.
-
#outcome(event_name) ⇒ Object
Returns the step name associated to the given event.
-
#upon(hash) ⇒ Object
Maps an error class to a step name to execute.
Instance Method Details
#definition_required? ⇒ Boolean
Used to know if the step needs an explicitly declared step definition or if it can manage the task with a default behavior.
150 151 152 153 154 155 156 157 158 159 |
# File 'lib/webflow/flow_step.rb', line 150 def definition_required? # We have to distinguish the false value from the non # existence of the variable. Therefore the ||= operator # can't help us. if @definition_required.class.kind_of?(NilClass) @definition_required = true else @definition_required end end |
#execute(*args) ⇒ Object
Method signature to override in implementing classes. Does the ‘dirty job’ once it is required.
Each implementing step HAS TO VERIFY THE VALUE OF THE lookup_method_to_call method. Or else, the ‘method’ instruction won’t be respected if the user has used the ‘method’ instruction.
141 142 143 144 145 |
# File 'lib/webflow/flow_step.rb', line 141 def execute(*args) raise(WebFlowError.new, "You can't directly use FlowStep as a step. As a matter of fact, I don't even know how you were able in the first place anyways...") end |
#handler(error_class) ⇒ Object
Returns the appropriate step name to execute upon the given error class
275 276 277 278 |
# File 'lib/webflow/flow_step.rb', line 275 def handler(error_class) error_class.kind_of?(String) ? key = error_class : key = error_class.to_s handlers.has_key?(key) ? handlers.fetch(key) : raise(WebFlowError.new, "There's no handler defined for the error class '#{key}'.") end |
#handles?(error_class) ⇒ Boolean
Tells if the error class passed as an argument is handled
267 268 269 |
# File 'lib/webflow/flow_step.rb', line 267 def handles?(error_class) handlers.has_key?(error_class) end |
#has_an_outcome_for?(event_name) ⇒ Boolean
Tells if the given event name is a possibe outcome of this step
282 283 284 |
# File 'lib/webflow/flow_step.rb', line 282 def has_an_outcome_for?(event_name) outcomes.has_key? event_name.to_s end |
#method(method_name) ⇒ Object
Maps a method name to execute instead of searching the controller for a method name who is the same as the step name.
Use it as :
action_step :my_step do
method :call_this_instead
end
259 260 261 262 263 |
# File 'lib/webflow/flow_step.rb', line 259 def method(method_name) @_method = method_name.to_s end |
#on(options) ⇒ Object
Maps an event to a method call. Use in a mapping like this :
implemented_step_type :id_of_step do
on :event => :method
end
This is also possible :
implemented_step_type :id_of_step do
on { :event => :method,
:event2 => :method2 }
end
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/webflow/flow_step.rb', line 176 def on() # Make sure we received a hash raise(WebFlowError.new, "The 'on' method takes a Hash object as a parameter.") unless .kind_of? Hash # Make sure the key is not used twice in a definition # to enforce coherence of the mapping. .each_key do |key| raise(WebFlowError.new, "An event in this step scope already uses the name '#{key}'.") if outcomes.has_key?(key.to_s) raise(WebFlowError.new, "#{key} is a reserved event keyword.") if WebFlow::Base.reserved_event?(key.to_s) end # Store the values in the possible outcomes hash .each { |key,value| outcomes[key.to_s] = value.to_s } end |
#outcome(event_name) ⇒ Object
Returns the step name associated to the given event.
288 289 290 |
# File 'lib/webflow/flow_step.rb', line 288 def outcome(event_name) outcomes.has_key?(event_name.to_s) ? outcomes.fetch(event_name.to_s) : raise(WebFlowError.new, "There's no outcome defined for the event name '#{event_name}'.") end |
#upon(hash) ⇒ Object
Maps an error class to a step name to execute. Use in a mapping like this :
implemented_step_type :id_of_step do
upon :WebFlowError => :step_name
end
This is also possible :
implemented_step_type :id_of_step do
upon { :WebFlowError => :step_name,
:WhateverError => :step_name }
end
Only subclasses of StandardError will be rescued. This means that RuntimeError cannot be handled.
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
# File 'lib/webflow/flow_step.rb', line 232 def upon(hash) # Make sure we received a hash raise(WebFlowError.new, "The 'upon' method takes a Hash object as a parameter. Go back to the API documents since you've obviously didn't read them well enough...") unless hash.kind_of? Hash # Make sure the key is not used twice in a definition # to enforce coherence of the mapping. hash.each_key do |key| raise(WebFlowError.new, "An error of the class '#{key}' is already mapped. They must be unique within a step scope.") if handlers.has_key?(key.to_s) end # Store the values in the handlers hash hash.each { |key,value| handlers.store key.to_s, value.to_s } end |