webflow 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +6 -0
- data/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/README +0 -0
- data/Rakefile +1 -0
- data/lib/plugins/controller_level_error_handler.rb +79 -0
- data/lib/plugins/flow_resume_validations.rb +48 -0
- data/lib/plugins/new_flow_validations.rb +52 -0
- data/lib/webflow.rb +18 -0
- data/lib/webflow/action_step.rb +114 -0
- data/lib/webflow/base.rb +723 -0
- data/lib/webflow/base_helper.rb +312 -0
- data/lib/webflow/event.rb +82 -0
- data/lib/webflow/exceptions.rb +80 -0
- data/lib/webflow/flow_step.rb +324 -0
- data/lib/webflow/plugin.rb +77 -0
- data/lib/webflow/random_generator.rb +48 -0
- data/lib/webflow/session_handler.rb +315 -0
- data/lib/webflow/state.rb +70 -0
- data/lib/webflow/version.rb +3 -0
- data/lib/webflow/view_step.rb +238 -0
- data/webflow.gemspec +24 -0
- metadata +69 -0
@@ -0,0 +1,315 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2007 The World in General
|
3
|
+
#
|
4
|
+
# Released under the Creative Commons Attribution-Share Alike 3.0 License.
|
5
|
+
# Licence details available at : http://creativecommons.org/licenses/by-sa/3.0/
|
6
|
+
#
|
7
|
+
# Created by Luc Boudreau ( lucboudreau at gmail )
|
8
|
+
#
|
9
|
+
# The above copyright notice and this permission notice shall be
|
10
|
+
# included in all copies or substantial portions of the Software.
|
11
|
+
#
|
12
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
13
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
14
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
15
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
16
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
17
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
18
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
19
|
+
#++
|
20
|
+
|
21
|
+
|
22
|
+
# Simply put, this module makes sure that the operations to the state
|
23
|
+
# registry associated to a user are transparent to the business logic.
|
24
|
+
#
|
25
|
+
# Session and it's flow states are all stored inside a session variable
|
26
|
+
# called WebFlow::SessionHandler.session_flow_data_prefix followed by
|
27
|
+
# 32 random characters.
|
28
|
+
#
|
29
|
+
|
30
|
+
WebFlow::Base.class_eval do
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
# Prefix of the variables which will be created in the user session
|
35
|
+
# to store the flow data.
|
36
|
+
@@session_flow_data_prefix = 'flow_data-'
|
37
|
+
cattr_accessor :session_flow_data_prefix
|
38
|
+
|
39
|
+
# Prefix of the variables which will be created in the flow's user session
|
40
|
+
# to store the state data.
|
41
|
+
@@session_state_data_prefix = 'state_data-'
|
42
|
+
cattr_accessor :session_state_data_prefix
|
43
|
+
|
44
|
+
# Name of the variables which will be created in the flow's user session
|
45
|
+
# to store the user data.
|
46
|
+
@@session_user_data_name = 'user_data'
|
47
|
+
cattr_accessor :session_user_data_name
|
48
|
+
|
49
|
+
# Used to detect flow data keys in the session hash
|
50
|
+
Session_data_prefix_regex = /^#{session_flow_data_prefix}[0-9]{32}$/
|
51
|
+
|
52
|
+
# Name of the key in the flow hash stored in the session which tells when was
|
53
|
+
# this flow last executed
|
54
|
+
@@session_timestamp_placeholder = 'updated_at'
|
55
|
+
cattr_accessor :session_timestamp_placeholder
|
56
|
+
|
57
|
+
# Defines for how long a flow execution data is maintained in the session
|
58
|
+
# placeholder.
|
59
|
+
@@session_ttl = 1.hour
|
60
|
+
cattr_accessor :session_ttl
|
61
|
+
|
62
|
+
# Defines where to store the name of the last executed step
|
63
|
+
@@last_step_placeholder = 'last_step_name'
|
64
|
+
cattr_accessor :last_step_placeholder
|
65
|
+
|
66
|
+
# Cleans the flows data for flows which have not been executed since
|
67
|
+
# the value defined by Session_ttl and Session_timestamp_placeholder.
|
68
|
+
def cleanup
|
69
|
+
|
70
|
+
# Iterate over the real session keys to find flow placeholders
|
71
|
+
session.keys.each do |key|
|
72
|
+
|
73
|
+
# Check if the key is a flow placeholder
|
74
|
+
if key =~ Session_data_prefix_regex
|
75
|
+
|
76
|
+
# Delete it if the flow has expired
|
77
|
+
session.delete(key) if (session[key].fetch(session_timestamp_placeholder) < (Time.now - session_ttl))
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
# Saves the current flow state data and makes sure that everything will be available
|
87
|
+
# to restore the flow state later on.
|
88
|
+
#def serialize
|
89
|
+
#
|
90
|
+
# # Update the flow timestamp
|
91
|
+
# update_timestamp
|
92
|
+
#
|
93
|
+
# # Copy the current state data
|
94
|
+
# old_state = (state).deep_copy
|
95
|
+
#
|
96
|
+
# # Generate a new flow id.
|
97
|
+
# # With old flows, we use the first 8 characters of the last execution id
|
98
|
+
# # but we generate 56 new ones which we append
|
99
|
+
# #
|
100
|
+
# # Fix for bug #10559 added. Collisions are prevented.
|
101
|
+
# continue = true
|
102
|
+
# while continue
|
103
|
+
#
|
104
|
+
# # Generate a new state id to test
|
105
|
+
# new_id = WebFlow::RandomGenerator.random_string(32)
|
106
|
+
#
|
107
|
+
# # Test it
|
108
|
+
# continue = current_flow_data.has_key?(new_id)
|
109
|
+
#
|
110
|
+
# end
|
111
|
+
#
|
112
|
+
# # We can update the flow id
|
113
|
+
# @flow_id = @flow_id[0, 9] + new_id
|
114
|
+
#
|
115
|
+
# # Initialize the flow session storage for this execution (state)
|
116
|
+
# init_state_session_space
|
117
|
+
#
|
118
|
+
# # Copy the shadow session state into the new state to freeze it
|
119
|
+
# state = old_state.deep_copy
|
120
|
+
#
|
121
|
+
# # Return nil
|
122
|
+
# nil
|
123
|
+
#
|
124
|
+
#end
|
125
|
+
|
126
|
+
|
127
|
+
#
|
128
|
+
# Cleans all data concerning the flow from the session.
|
129
|
+
#
|
130
|
+
def terminate
|
131
|
+
|
132
|
+
# Destroy the flow placeholder in the session
|
133
|
+
session.delete(flow_session_name)
|
134
|
+
|
135
|
+
nil
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
# Does everything needed to store data concerning a new flow execution
|
141
|
+
def start_new_flow_session_storage
|
142
|
+
|
143
|
+
# With new flows, we define a completely new 32 characters id
|
144
|
+
@flow_id = WebFlow::RandomGenerator.random_string(32)
|
145
|
+
|
146
|
+
# Initialize the flow session storage for the flow itself, since it will
|
147
|
+
# then contain all the states
|
148
|
+
init_flow_session_space
|
149
|
+
|
150
|
+
# Initialize the flow session state storage for this execution
|
151
|
+
init_state_session_space
|
152
|
+
|
153
|
+
# Initialize the flow session user storage for this execution
|
154
|
+
init_user_session_space
|
155
|
+
|
156
|
+
end
|
157
|
+
|
158
|
+
|
159
|
+
# Updates the timestamp for the current flow. Is to be called on each session
|
160
|
+
# modification.
|
161
|
+
def update_timestamp
|
162
|
+
|
163
|
+
# Update the timestamp for the current flow
|
164
|
+
session[flow_session_name].store session_timestamp_placeholder, Time.now
|
165
|
+
|
166
|
+
end
|
167
|
+
|
168
|
+
|
169
|
+
# Adds the last step name to the current flow data so we can interpret the
|
170
|
+
# returned event correctly once the user submits data back.
|
171
|
+
def persist_last_step_name(state_name)
|
172
|
+
|
173
|
+
# Store the last step name in the correct placeholder
|
174
|
+
current_flow_data.fetch(state_session_name).store(last_step_placeholder, state_name.to_s)
|
175
|
+
|
176
|
+
# Return nil
|
177
|
+
nil
|
178
|
+
|
179
|
+
end
|
180
|
+
|
181
|
+
|
182
|
+
# Adds the last step name to the current flow data so we can interpret the
|
183
|
+
# returned event correctly once the user submits data back.
|
184
|
+
def fetch_last_step_name
|
185
|
+
|
186
|
+
# Fetch the last step name from the correct placeholder
|
187
|
+
current_flow_data.fetch(state_session_name).fetch(last_step_placeholder)
|
188
|
+
|
189
|
+
end
|
190
|
+
|
191
|
+
|
192
|
+
# Validates that the given flow key corresponds to a stored flow data
|
193
|
+
def validate_flow_existence
|
194
|
+
|
195
|
+
!current_flow_data.nil? && !state.nil?
|
196
|
+
|
197
|
+
end
|
198
|
+
|
199
|
+
|
200
|
+
# Initializes the session variables needed to save the flow data.
|
201
|
+
def init_flow_session_space
|
202
|
+
|
203
|
+
# The placeholder for the flow will be named...
|
204
|
+
flow_placeholder = flow_session_name
|
205
|
+
|
206
|
+
# Create a new placeholder for this flow data in the real session space
|
207
|
+
session[flow_placeholder] = HashWithIndifferentAccess.new
|
208
|
+
|
209
|
+
# Timestamp the creation time
|
210
|
+
update_timestamp
|
211
|
+
|
212
|
+
# Return nil
|
213
|
+
nil
|
214
|
+
|
215
|
+
end
|
216
|
+
|
217
|
+
|
218
|
+
# Initializes the session variables needed to save the state data.
|
219
|
+
def init_state_session_space
|
220
|
+
|
221
|
+
# Create a new placeholder for this state data in the real session space
|
222
|
+
# reserved for this flow data
|
223
|
+
current_flow_data.store state_session_name, HashWithIndifferentAccess.new
|
224
|
+
|
225
|
+
# Return nil
|
226
|
+
nil
|
227
|
+
|
228
|
+
end
|
229
|
+
|
230
|
+
|
231
|
+
# Initializes the session variables needed to save the user data.
|
232
|
+
def init_user_session_space
|
233
|
+
|
234
|
+
# Create a new placeholder for this user data in the real session space
|
235
|
+
# reserved for this flow data
|
236
|
+
current_flow_data.store session_user_data_name, HashWithIndifferentAccess.new
|
237
|
+
|
238
|
+
# Return nil
|
239
|
+
nil
|
240
|
+
|
241
|
+
end
|
242
|
+
|
243
|
+
|
244
|
+
# Returns the name of the variable used in the real session data hash
|
245
|
+
# to store this flow data
|
246
|
+
def flow_session_name
|
247
|
+
(session_flow_data_prefix + @flow_id).to_s
|
248
|
+
end
|
249
|
+
|
250
|
+
|
251
|
+
# Returns the name of the variable used in the flow session data hash
|
252
|
+
# to store this state data
|
253
|
+
def state_session_name
|
254
|
+
(session_state_data_prefix + @flow_id).to_s
|
255
|
+
end
|
256
|
+
|
257
|
+
|
258
|
+
# Returns the current flow data hash from within the
|
259
|
+
# user session.
|
260
|
+
def current_flow_data
|
261
|
+
session[flow_session_name]
|
262
|
+
end
|
263
|
+
|
264
|
+
|
265
|
+
# Returns the current flow user data hash from within the user session.
|
266
|
+
#
|
267
|
+
# @returns current flow user session hash
|
268
|
+
#
|
269
|
+
def current_flow_user_data
|
270
|
+
current_flow_data.fetch session_user_data_name
|
271
|
+
end
|
272
|
+
|
273
|
+
|
274
|
+
# Saves or updates data to the current flow session data hash.
|
275
|
+
#
|
276
|
+
# @params values hash containing values to be added to the flow user session
|
277
|
+
# @params options hash containing options
|
278
|
+
#
|
279
|
+
# @returns nil
|
280
|
+
#
|
281
|
+
def store_flow_data(values, options = {})
|
282
|
+
update = options[:update] || true
|
283
|
+
|
284
|
+
current_flow_user_data.merge!(values) { |key, val1, val2| update ? val2 : val1 }
|
285
|
+
|
286
|
+
update_timestamp
|
287
|
+
|
288
|
+
nil
|
289
|
+
end
|
290
|
+
|
291
|
+
|
292
|
+
public
|
293
|
+
|
294
|
+
# Returns the current flow user data hash from within the user session.
|
295
|
+
#
|
296
|
+
# @returns current flow user session hash
|
297
|
+
#
|
298
|
+
def current_flow_user_data
|
299
|
+
current_flow_data.fetch session_user_data_name
|
300
|
+
end
|
301
|
+
|
302
|
+
end
|
303
|
+
|
304
|
+
|
305
|
+
# Used to add a deep copy mechanism to objects
|
306
|
+
Object.class_eval do
|
307
|
+
|
308
|
+
# Performs a deep copy of an object and returns a copy of the source and all it's sub objects
|
309
|
+
# as copies. Useful for example when a hash contains objects and you want a copy of the Hash
|
310
|
+
# and copies of the objects it contains and not the objects themselves
|
311
|
+
def deep_copy
|
312
|
+
Marshal.load(Marshal.dump(self))
|
313
|
+
end
|
314
|
+
|
315
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2007 The World in General
|
3
|
+
#
|
4
|
+
# Released under the Creative Commons Attribution-Share Alike 3.0 License.
|
5
|
+
# Licence details available at : http://creativecommons.org/licenses/by-sa/3.0/
|
6
|
+
#
|
7
|
+
# Created by Luc Boudreau ( lucboudreau at gmail )
|
8
|
+
#
|
9
|
+
# The above copyright notice and this permission notice shall be
|
10
|
+
# included in all copies or substantial portions of the Software.
|
11
|
+
#
|
12
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
13
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
14
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
15
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
16
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
17
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
18
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
19
|
+
#++
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
|
24
|
+
# The State module is simply a method inclusion mechanism which allows
|
25
|
+
# the user to store data relevant to a flow state. It is used exactly like
|
26
|
+
# the 'session' attribute of the ActionController::Base. See the WebFlow
|
27
|
+
# wiki for more details.
|
28
|
+
|
29
|
+
WebFlow::Base.class_eval do
|
30
|
+
|
31
|
+
|
32
|
+
# TODO Send the state method to the ActionViews
|
33
|
+
|
34
|
+
protected
|
35
|
+
|
36
|
+
|
37
|
+
# Returns the state data hash
|
38
|
+
def state
|
39
|
+
|
40
|
+
session[ flow_session_name ].fetch( state_session_name )
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
# Changes the state hash for another one
|
45
|
+
def state=(hash)
|
46
|
+
session[ flow_session_name ].store( state_session_name, hash )
|
47
|
+
state
|
48
|
+
end
|
49
|
+
|
50
|
+
# Does the same as state(k,v)
|
51
|
+
#def []=(k, v)
|
52
|
+
# return session[ flow_session_name ].fetch( state_session_name ).store( k.to_s, v )
|
53
|
+
#end
|
54
|
+
|
55
|
+
|
56
|
+
# Does the same as state(k)
|
57
|
+
#def [](k)
|
58
|
+
|
59
|
+
# return session[ flow_session_name ].fetch( state_session_name ).fetch( k )
|
60
|
+
#
|
61
|
+
#end
|
62
|
+
|
63
|
+
|
64
|
+
# Adds ActionView helper methods
|
65
|
+
def self.included(base)
|
66
|
+
base.send :helper_method, :state
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
|
@@ -0,0 +1,238 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2007 The World in General
|
3
|
+
#
|
4
|
+
# Released under the Creative Commons Attribution-Share Alike 3.0 License.
|
5
|
+
# Licence details available at : http://creativecommons.org/licenses/by-sa/3.0/
|
6
|
+
#
|
7
|
+
# Created by Luc Boudreau ( lucboudreau at gmail )
|
8
|
+
#
|
9
|
+
# The above copyright notice and this permission notice shall be
|
10
|
+
# included in all copies or substantial portions of the Software.
|
11
|
+
#
|
12
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
13
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
14
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
15
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
16
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
17
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
18
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
19
|
+
#++
|
20
|
+
|
21
|
+
#require 'flow_step'
|
22
|
+
#require 'base'
|
23
|
+
#require 'event'
|
24
|
+
|
25
|
+
module WebFlow
|
26
|
+
|
27
|
+
# This class allows the controllers to create view steps. It adds the
|
28
|
+
# view_step method to the WebFlow::Base class evaluation so we can
|
29
|
+
# define view steps from the controllers.
|
30
|
+
#
|
31
|
+
# == Simple usage
|
32
|
+
#
|
33
|
+
# view_step :view_name do
|
34
|
+
# on :success => :another_step
|
35
|
+
# on :back => :yet_another_step
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# The view name will be stored in the @view_name instance variable
|
39
|
+
# until it is needed.
|
40
|
+
#
|
41
|
+
# If no method corresponding to @view_name is defined inside the
|
42
|
+
# calling controller upon execution, the ViewStep tries to render
|
43
|
+
# a file with the same name as the @view_step value. Therefore,
|
44
|
+
# it is not mandatory to define view_step methods in the flow controller.
|
45
|
+
#
|
46
|
+
# The view_step instruction can also be used to batch define view steps.
|
47
|
+
# Just pass a comma separated list of view names. Note that the mappings
|
48
|
+
# defined in the following block will be applied to all the view steps
|
49
|
+
# in the given list.
|
50
|
+
#
|
51
|
+
# view_step :view_name, :another_view_step
|
52
|
+
#
|
53
|
+
# == Advanced usage
|
54
|
+
#
|
55
|
+
# You can define how to render the view steps directly in the mapping,
|
56
|
+
# instead of doing it in the action itself. This gives a more clean code
|
57
|
+
# and separates the rendering concern from the business logic. The to_render
|
58
|
+
# instruction does this job. Here's a simple usage.
|
59
|
+
#
|
60
|
+
# view_step :view_name do
|
61
|
+
#
|
62
|
+
# (...)
|
63
|
+
#
|
64
|
+
# to_render :my_event do
|
65
|
+
# render 'template/path'
|
66
|
+
# end
|
67
|
+
# end
|
68
|
+
#
|
69
|
+
# The to_render instruction tells the view step that upon the returning of the
|
70
|
+
# my_event event from the step implementation, we must render the 'template/path'
|
71
|
+
# file. As a matter of fact, all the to_render does is to call the given block
|
72
|
+
# right after the step definition execution. One could use the to_render mechanism
|
73
|
+
# as he wishes and therefore perform actions other than rendering.
|
74
|
+
#
|
75
|
+
# The to_render can also take many event names as arguments simultaneously,
|
76
|
+
# as shown here :
|
77
|
+
#
|
78
|
+
# view_step :view_name do
|
79
|
+
#
|
80
|
+
# (...)
|
81
|
+
#
|
82
|
+
# to_render :my_event, :some_other_event, :yet_more_events do
|
83
|
+
# render 'template/path'
|
84
|
+
# end
|
85
|
+
# end
|
86
|
+
#
|
87
|
+
# == Inherited instructions
|
88
|
+
#
|
89
|
+
# The ViewStep class inherits all the standard step methods defined in FlowStep class.
|
90
|
+
#
|
91
|
+
#
|
92
|
+
class ViewStep < WebFlow::FlowStep
|
93
|
+
|
94
|
+
# Initializes the instance
|
95
|
+
def initialize( m_view_name )
|
96
|
+
|
97
|
+
# Holds the view name to render once the execution is complete
|
98
|
+
@view_name = m_view_name
|
99
|
+
|
100
|
+
# Tells the framework that no method definition is required for
|
101
|
+
# this step type
|
102
|
+
@definition_required = false
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
# This method is required by the WebFlow::Base and will be called
|
108
|
+
# once it relays the execution to this step instance
|
109
|
+
def execute(*args)
|
110
|
+
|
111
|
+
# Verify if the controller answers to the @view_name value
|
112
|
+
if args[0].respond_to? lookup_method_to_call(@view_name)
|
113
|
+
|
114
|
+
# The controller defines a method with the same name as @view_name.
|
115
|
+
# Kewl! A 'someone else problem' !!!
|
116
|
+
|
117
|
+
# Launch execution
|
118
|
+
result = args[0].send( lookup_method_to_call(@view_name) )
|
119
|
+
|
120
|
+
else
|
121
|
+
|
122
|
+
# Do we have to do everything here? lazy user...
|
123
|
+
|
124
|
+
# Render something but only if the user hasn't
|
125
|
+
# defined a custom render block.
|
126
|
+
args[0].send :render, :action => lookup_method_to_call(@view_name) unless renders.has_key?('render')
|
127
|
+
|
128
|
+
# Return the :render event
|
129
|
+
result = WebFlow::Event.new(:render)
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
# Verify if we have to override the render result.
|
134
|
+
# Execute if necessary.
|
135
|
+
# Also validate that the return type is an event, or let go and it will
|
136
|
+
# crash as soon as execution completes anyways...
|
137
|
+
if result.kind_of?(WebFlow::Event) && renders.has_key?(result.name)
|
138
|
+
|
139
|
+
# Execute the render block
|
140
|
+
args[0].instance_eval( &renders.fetch( result.name ) )
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
result
|
145
|
+
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
# Used to specify the render action to be taken by the step.
|
150
|
+
# The render result defined here overrides the one defined in the step
|
151
|
+
# definition.
|
152
|
+
# Use it as :
|
153
|
+
#
|
154
|
+
# class Controller < WebFlow::Base
|
155
|
+
#
|
156
|
+
# def initialize
|
157
|
+
#
|
158
|
+
# to_render [:some_event_name, :some_other_event_name] do
|
159
|
+
# render(:action => :whatever )
|
160
|
+
# end
|
161
|
+
#
|
162
|
+
# end
|
163
|
+
#
|
164
|
+
# end
|
165
|
+
#def to_render(*events, &block)
|
166
|
+
#
|
167
|
+
# # Make sure we have a block as a parameter
|
168
|
+
# raise(WebFlow::WebFlowError.new, "The renders instruction takes a block as a parameter. Use the 'do' format. See API.") unless block_given?
|
169
|
+
#
|
170
|
+
# # Iterate over the events to map
|
171
|
+
# events.each do |name|
|
172
|
+
#
|
173
|
+
# # Associate each event name with the received block
|
174
|
+
# renders.store name.to_s, block
|
175
|
+
#
|
176
|
+
# end
|
177
|
+
#
|
178
|
+
#end
|
179
|
+
|
180
|
+
|
181
|
+
def on_render(&block)
|
182
|
+
|
183
|
+
# Make sure we have a block as a parameter
|
184
|
+
raise(WebFlow::WebFlowError.new, "The renders instruction takes a block as a parameter. Use the 'do' format. See API.") unless block_given?
|
185
|
+
|
186
|
+
# Associate render event with the received block
|
187
|
+
renders.store "render", block
|
188
|
+
|
189
|
+
end
|
190
|
+
|
191
|
+
private
|
192
|
+
|
193
|
+
# Returns the mapped rendering overrides hash.
|
194
|
+
def renders
|
195
|
+
|
196
|
+
@_renders ||= {}
|
197
|
+
|
198
|
+
end
|
199
|
+
|
200
|
+
end
|
201
|
+
|
202
|
+
|
203
|
+
end
|
204
|
+
|
205
|
+
# Let's create the view_step definition inside the WebFlow::Base
|
206
|
+
# controller class
|
207
|
+
WebFlow::Base.class_eval do
|
208
|
+
|
209
|
+
protected
|
210
|
+
|
211
|
+
# Called to define a step into a flow. Example of usage :
|
212
|
+
#
|
213
|
+
# view_step :view_name do
|
214
|
+
# on :success => :another_step
|
215
|
+
# on :back => :yet_another_step
|
216
|
+
# end
|
217
|
+
#
|
218
|
+
# See the ViewStep class documentation for more options.
|
219
|
+
#
|
220
|
+
def view_step(*view_name, &block)
|
221
|
+
|
222
|
+
# Instantiate a ViewStep object if symbol or string received
|
223
|
+
view_name.each do |name|
|
224
|
+
|
225
|
+
step = WebFlow::ViewStep.new(name.to_s)
|
226
|
+
|
227
|
+
# Register this step in the flow repository
|
228
|
+
register name.to_s, step
|
229
|
+
|
230
|
+
# Execute the config block
|
231
|
+
step.instance_eval(&block) if block_given?
|
232
|
+
|
233
|
+
end
|
234
|
+
|
235
|
+
end
|
236
|
+
|
237
|
+
|
238
|
+
end
|