reactive-mvc 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +21 -0
- data/Manifest +34 -0
- data/README +30 -0
- data/Rakefile +5 -0
- data/lib/reactive-mvc.rb +26 -0
- data/lib/reactive-mvc/controller.rb +16 -0
- data/lib/reactive-mvc/controller/base.rb +405 -0
- data/lib/reactive-mvc/controller/filters.rb +767 -0
- data/lib/reactive-mvc/controller/flash.rb +161 -0
- data/lib/reactive-mvc/controller/helpers.rb +203 -0
- data/lib/reactive-mvc/controller/layout.rb +285 -0
- data/lib/reactive-mvc/controller/output.rb +262 -0
- data/lib/reactive-mvc/controller/rescue.rb +208 -0
- data/lib/reactive-mvc/dispatcher.rb +133 -0
- data/lib/reactive-mvc/view.rb +18 -0
- data/lib/reactive-mvc/view/base.rb +388 -0
- data/lib/reactive-mvc/view/helpers.rb +38 -0
- data/lib/reactive-mvc/view/partials.rb +207 -0
- data/lib/reactive-mvc/view/paths.rb +125 -0
- data/lib/reactive-mvc/view/renderable.rb +98 -0
- data/lib/reactive-mvc/view/renderable_partial.rb +49 -0
- data/lib/reactive-mvc/view/template.rb +110 -0
- data/lib/reactive-mvc/view/template_error.rb +9 -0
- data/lib/reactive-mvc/view/template_handler.rb +9 -0
- data/lib/reactive-mvc/view/template_handlers.rb +43 -0
- data/lib/reactive-mvc/view/template_handlers/builder.rb +15 -0
- data/lib/reactive-mvc/view/template_handlers/erb.rb +20 -0
- data/lib/reactive-mvc/view/template_handlers/ruby_code.rb +9 -0
- data/reactive_app_generators/mvc/USAGE +10 -0
- data/reactive_app_generators/mvc/mvc_generator.rb +48 -0
- data/reactive_app_generators/mvc/templates/application_controller.rb +2 -0
- data/reactive_generators/controller/USAGE +7 -0
- data/reactive_generators/controller/controller_generator.rb +24 -0
- data/reactive_generators/controller/templates/controller.rb +2 -0
- metadata +113 -0
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2008-2009 Pascal Hurni
|
2
|
+
Copyright (c) 2004-2007 David Heinemeier Hansson
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
a copy of this software and associated documentation files (the
|
6
|
+
"Software"), to deal in the Software without restriction, including
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Manifest
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
LICENSE
|
2
|
+
Manifest
|
3
|
+
README
|
4
|
+
Rakefile
|
5
|
+
lib/reactive-mvc.rb
|
6
|
+
lib/reactive-mvc/controller.rb
|
7
|
+
lib/reactive-mvc/controller/base.rb
|
8
|
+
lib/reactive-mvc/controller/filters.rb
|
9
|
+
lib/reactive-mvc/controller/flash.rb
|
10
|
+
lib/reactive-mvc/controller/helpers.rb
|
11
|
+
lib/reactive-mvc/controller/layout.rb
|
12
|
+
lib/reactive-mvc/controller/output.rb
|
13
|
+
lib/reactive-mvc/controller/rescue.rb
|
14
|
+
lib/reactive-mvc/dispatcher.rb
|
15
|
+
lib/reactive-mvc/view.rb
|
16
|
+
lib/reactive-mvc/view/base.rb
|
17
|
+
lib/reactive-mvc/view/helpers.rb
|
18
|
+
lib/reactive-mvc/view/partials.rb
|
19
|
+
lib/reactive-mvc/view/paths.rb
|
20
|
+
lib/reactive-mvc/view/renderable.rb
|
21
|
+
lib/reactive-mvc/view/renderable_partial.rb
|
22
|
+
lib/reactive-mvc/view/template.rb
|
23
|
+
lib/reactive-mvc/view/template_error.rb
|
24
|
+
lib/reactive-mvc/view/template_handler.rb
|
25
|
+
lib/reactive-mvc/view/template_handlers.rb
|
26
|
+
lib/reactive-mvc/view/template_handlers/builder.rb
|
27
|
+
lib/reactive-mvc/view/template_handlers/erb.rb
|
28
|
+
lib/reactive-mvc/view/template_handlers/ruby_code.rb
|
29
|
+
reactive_app_generators/mvc/USAGE
|
30
|
+
reactive_app_generators/mvc/mvc_generator.rb
|
31
|
+
reactive_app_generators/mvc/templates/application_controller.rb
|
32
|
+
reactive_generators/controller/USAGE
|
33
|
+
reactive_generators/controller/controller_generator.rb
|
34
|
+
reactive_generators/controller/templates/controller.rb
|
data/README
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
== reactive-mvc
|
2
|
+
|
3
|
+
Reactive plugin that dispatches requests to a local MVC machinery.
|
4
|
+
|
5
|
+
Version:: 0.2.0
|
6
|
+
Author:: Pascal Hurni
|
7
|
+
Email:: phi@ruby-reactive.org
|
8
|
+
Homepage:: http://www.ruby-reactive.org
|
9
|
+
|
10
|
+
== Description
|
11
|
+
|
12
|
+
Provides a local MVC machinery to handle requests of the reactive application.
|
13
|
+
The machinery is mapped to what is done in RubyOnRails, so you'll have rails like
|
14
|
+
controllers, rails like views and helpers.
|
15
|
+
|
16
|
+
Because Reactive is Model and View agnostic, this plugin alone will
|
17
|
+
not do the complete job.
|
18
|
+
|
19
|
+
== Configuration
|
20
|
+
|
21
|
+
<paths> :mvc:: Path to the root of the mvc files. Defaults to "app"
|
22
|
+
<paths> :model:: Path for model files. Defaults to ":mvc/models"
|
23
|
+
<paths> :views:: Array of paths for views. Defaults to ":mvc/views"
|
24
|
+
<paths> :controller:: Path for controllers. Defaults to ":mvc/controllers"
|
25
|
+
<paths> :helper:: Path for view helpers. Defaults to ":mvc/helpers"
|
26
|
+
|
27
|
+
== Requirements
|
28
|
+
|
29
|
+
* reactive-core >= 0.2.0
|
30
|
+
* activesupport >= 2.0.0
|
data/Rakefile
ADDED
data/lib/reactive-mvc.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
Reactive::Initializer.configure :mvc do
|
2
|
+
Reactive.configuration.paths[:mvc] = Reactive.configuration.reactive_mvc.root_path || Reactive.path_for("app")
|
3
|
+
Reactive.configuration.paths[:views] = Reactive.configuration.reactive_mvc.view_paths || [Reactive.path_for(:mvc, "views")]
|
4
|
+
Reactive.configuration.paths[:model] = Reactive.configuration.reactive_mvc.model_path || Reactive.path_for(:mvc, "models")
|
5
|
+
Reactive.configuration.paths[:helper] = Reactive.configuration.reactive_mvc.helper_path || Reactive.path_for(:mvc, "helpers")
|
6
|
+
Reactive.configuration.paths[:controller] = Reactive.configuration.reactive_mvc.controller_path || Reactive.path_for(:mvc, "controllers")
|
7
|
+
Reactive.configuration.paths[:test] = Reactive.configuration.reactive_mvc.test_path || Reactive.path_for("test")
|
8
|
+
end
|
9
|
+
|
10
|
+
Reactive::Initializer.init :mvc do
|
11
|
+
require 'reactive-mvc/dispatcher'
|
12
|
+
require 'reactive-mvc/controller'
|
13
|
+
require 'reactive-mvc/view'
|
14
|
+
|
15
|
+
# TODO: Seems that this is not required? So how does ruby load application_controller.rb ???
|
16
|
+
# ActiveSupport::Dependencies.load_paths |= [:model, :helper, :controller].collect {|dir_id| Reactive.path_for dir_id}
|
17
|
+
|
18
|
+
Reactive::Mvc::Controller::Base.logger = Reactive::Mvc::View::Base.logger = Reactive.configuration.reactive_mvc.logger || Reactive.logger
|
19
|
+
|
20
|
+
Reactive::Dispatcher::Base.register(:mvc, Reactive::Mvc::Dispatcher)
|
21
|
+
|
22
|
+
ActiveSupport::Dependencies.load_paths.push Reactive.configuration.paths[:model], Reactive.configuration.paths[:helper], Reactive.configuration.paths[:controller]
|
23
|
+
|
24
|
+
# TODO: modify the behaviour of paths directly in Controller::Base
|
25
|
+
Reactive::Mvc::Controller::Base.view_paths = Reactive.configuration.paths[:views]
|
26
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'reactive-mvc/controller/base'
|
2
|
+
require 'reactive-mvc/controller/rescue'
|
3
|
+
require 'reactive-mvc/controller/flash'
|
4
|
+
require 'reactive-mvc/controller/filters'
|
5
|
+
require 'reactive-mvc/controller/layout'
|
6
|
+
require 'reactive-mvc/controller/helpers'
|
7
|
+
require 'reactive-mvc/controller/output'
|
8
|
+
|
9
|
+
Reactive::Mvc::Controller::Base.class_eval do
|
10
|
+
include Reactive::Mvc::Controller::Flash
|
11
|
+
include Reactive::Mvc::Controller::Filters
|
12
|
+
include Reactive::Mvc::Controller::Layout
|
13
|
+
include Reactive::Mvc::Controller::Rescue
|
14
|
+
include Reactive::Mvc::Controller::Helpers
|
15
|
+
include Reactive::Mvc::Controller::Output
|
16
|
+
end
|
@@ -0,0 +1,405 @@
|
|
1
|
+
module Reactive::Mvc
|
2
|
+
module Controller
|
3
|
+
class Error < Reactive::Error #:nodoc:
|
4
|
+
end
|
5
|
+
|
6
|
+
class MethodNotAllowed < Error #:nodoc:
|
7
|
+
attr_reader :allowed_methods
|
8
|
+
|
9
|
+
def initialize(*allowed_methods)
|
10
|
+
super("Only #{allowed_methods.to_sentence} requests are allowed.")
|
11
|
+
@allowed_methods = allowed_methods
|
12
|
+
end
|
13
|
+
|
14
|
+
def allowed_methods_header
|
15
|
+
allowed_methods.map { |method_symbol| method_symbol.to_s.upcase } * ', '
|
16
|
+
end
|
17
|
+
|
18
|
+
def handle_response!(response)
|
19
|
+
response.headers['Allow'] ||= allowed_methods_header
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class NotImplemented < MethodNotAllowed #:nodoc:
|
24
|
+
end
|
25
|
+
|
26
|
+
class UnknownController < Error #:nodoc:
|
27
|
+
end
|
28
|
+
|
29
|
+
class UnknownAction < Error #:nodoc:
|
30
|
+
end
|
31
|
+
|
32
|
+
class MissingFile < Error #:nodoc:
|
33
|
+
end
|
34
|
+
|
35
|
+
class RenderError < Error #:nodoc:
|
36
|
+
end
|
37
|
+
|
38
|
+
class DoubleRenderError < Error #:nodoc:
|
39
|
+
DEFAULT_MESSAGE = "Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like \"redirect_to(...) and return\"."
|
40
|
+
|
41
|
+
def initialize(message = nil)
|
42
|
+
super(message || DEFAULT_MESSAGE)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class Base
|
47
|
+
|
48
|
+
# Controller specific instance variables which will not be accessible inside views.
|
49
|
+
cattr_reader :protected_instance_variables
|
50
|
+
@@protected_instance_variables = %w(@assigns @performed_redirect @performed_render @parent_controller
|
51
|
+
@action_name @before_filter_chain_aborted @_params @_flash @_response)
|
52
|
+
|
53
|
+
# The logger is used for generating information on the action run-time (including benchmarking) if available.
|
54
|
+
# Can be set to nil for no logging. Compatible with both Ruby's own Logger and Log4r loggers.
|
55
|
+
cattr_accessor :logger
|
56
|
+
|
57
|
+
# Returns the name of the action this controller is processing.
|
58
|
+
attr_reader :action_name
|
59
|
+
|
60
|
+
# Holds the request object that will be used by the dispatcher.
|
61
|
+
attr_internal :request
|
62
|
+
|
63
|
+
# Holds the response object that will be used by the dispatcher.
|
64
|
+
attr_internal :response
|
65
|
+
|
66
|
+
# Holds a hash of all the parameters passed to the action. Accessed like <tt>params["post_id"]</tt>
|
67
|
+
# to get the post_id. No type casts are made, so all values are of the initial type of the request.
|
68
|
+
attr_internal :params
|
69
|
+
|
70
|
+
@@template_classes = {}
|
71
|
+
|
72
|
+
class << self
|
73
|
+
|
74
|
+
def process(request, response) #, method = :perform_action, *arguments)
|
75
|
+
new.process(request, response) #, method, *arguments)
|
76
|
+
end
|
77
|
+
|
78
|
+
def register_template_class(format, klass)
|
79
|
+
@@template_classes[format.to_sym] = klass
|
80
|
+
end
|
81
|
+
|
82
|
+
# Converts the class name from something like "OneModule::TwoModule::NeatController" to "NeatController".
|
83
|
+
def controller_class_name
|
84
|
+
@controller_class_name ||= name.demodulize
|
85
|
+
end
|
86
|
+
|
87
|
+
# Converts the class name from something like "OneModule::TwoModule::NeatController" to "neat".
|
88
|
+
def controller_name
|
89
|
+
@controller_name ||= controller_class_name.sub(/Controller$/, '').underscore
|
90
|
+
end
|
91
|
+
|
92
|
+
# Converts the class name from something like "OneModule::TwoModule::NeatController" to "one_module/two_module/neat".
|
93
|
+
def controller_path
|
94
|
+
@controller_path ||= name.gsub(/Controller$/, '').underscore
|
95
|
+
end
|
96
|
+
|
97
|
+
# Return an array containing the names of public methods that have been marked hidden from the action processor.
|
98
|
+
# By default, all methods defined in ActionController::Base and included modules are hidden.
|
99
|
+
# More methods can be hidden using <tt>hide_actions</tt>.
|
100
|
+
def hidden_actions
|
101
|
+
read_inheritable_attribute(:hidden_actions) || write_inheritable_attribute(:hidden_actions, [])
|
102
|
+
end
|
103
|
+
|
104
|
+
# Hide each of the given methods from being callable as actions.
|
105
|
+
def hide_action(*names)
|
106
|
+
write_inheritable_attribute(:hidden_actions, hidden_actions | names.map(&:to_s))
|
107
|
+
end
|
108
|
+
|
109
|
+
## View load paths determine the bases from which template references can be made. So a call to
|
110
|
+
## render("test/template") will be looked up in the view load paths array and the closest match will be
|
111
|
+
## returned.
|
112
|
+
def view_paths
|
113
|
+
@view_paths || superclass.view_paths
|
114
|
+
end
|
115
|
+
|
116
|
+
def view_paths=(value)
|
117
|
+
@view_paths = value
|
118
|
+
end
|
119
|
+
|
120
|
+
# Adds a view_path to the front of the view_paths array.
|
121
|
+
# If the current class has no view paths, copy them from
|
122
|
+
# the superclass. This change will be visible for all future requests.
|
123
|
+
#
|
124
|
+
# ArticleController.prepend_view_path("views/default")
|
125
|
+
# ArticleController.prepend_view_path(["views/default", "views/custom"])
|
126
|
+
#
|
127
|
+
def prepend_view_path(path)
|
128
|
+
@view_paths = superclass.view_paths.dup if @view_paths.nil?
|
129
|
+
@view_paths.unshift(*path)
|
130
|
+
end
|
131
|
+
|
132
|
+
# Adds a view_path to the end of the view_paths array.
|
133
|
+
# If the current class has no view paths, copy them from
|
134
|
+
# the superclass. This change will be visible for all future requests.
|
135
|
+
#
|
136
|
+
# ArticleController.append_view_path("views/default")
|
137
|
+
# ArticleController.append_view_path(["views/default", "views/custom"])
|
138
|
+
#
|
139
|
+
def append_view_path(path)
|
140
|
+
@view_paths = superclass.view_paths.dup if @view_paths.nil?
|
141
|
+
@view_paths.push(*path)
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
# Extracts the action_name from the request parameters and performs that action.
|
147
|
+
def process(request, response, method = :perform_action, *arguments) #:nodoc:
|
148
|
+
assign_params(request)
|
149
|
+
initialize_template_class(response)
|
150
|
+
assign_shortcuts(request, response)
|
151
|
+
|
152
|
+
log_processing
|
153
|
+
send(method, *arguments)
|
154
|
+
|
155
|
+
response
|
156
|
+
ensure
|
157
|
+
process_cleanup
|
158
|
+
end
|
159
|
+
|
160
|
+
# Converts the class name from something like "OneModule::TwoModule::NeatController" to "NeatController".
|
161
|
+
def controller_class_name
|
162
|
+
self.class.controller_class_name
|
163
|
+
end
|
164
|
+
|
165
|
+
# Converts the class name from something like "OneModule::TwoModule::NeatController" to "neat".
|
166
|
+
def controller_name
|
167
|
+
self.class.controller_name
|
168
|
+
end
|
169
|
+
|
170
|
+
# Converts the class name from something like "OneModule::TwoModule::NeatController" to "one_module/two_module/neat".
|
171
|
+
def controller_path
|
172
|
+
self.class.controller_path
|
173
|
+
end
|
174
|
+
|
175
|
+
self.view_paths = []
|
176
|
+
|
177
|
+
# View load paths for controller.
|
178
|
+
def view_paths
|
179
|
+
(@template || self.class).view_paths
|
180
|
+
end
|
181
|
+
|
182
|
+
def view_paths=(value)
|
183
|
+
(@template || self.class).view_paths = value
|
184
|
+
end
|
185
|
+
|
186
|
+
# Adds a view_path to the front of the view_paths array.
|
187
|
+
# This change affects the current request only.
|
188
|
+
#
|
189
|
+
# self.prepend_view_path("views/default")
|
190
|
+
# self.prepend_view_path(["views/default", "views/custom"])
|
191
|
+
#
|
192
|
+
def prepend_view_path(path)
|
193
|
+
(@template || self.class).prepend_view_path(path)
|
194
|
+
end
|
195
|
+
|
196
|
+
# Adds a view_path to the end of the view_paths array.
|
197
|
+
# This change affects the current request only.
|
198
|
+
#
|
199
|
+
# self.append_view_path("views/default")
|
200
|
+
# self.append_view_path(["views/default", "views/custom"])
|
201
|
+
#
|
202
|
+
def append_view_path(path)
|
203
|
+
(@template || self.class).append_view_path(path)
|
204
|
+
end
|
205
|
+
|
206
|
+
protected
|
207
|
+
# render
|
208
|
+
def render(options = nil, &block) #:doc:
|
209
|
+
raise DoubleRenderError, "Can only render or redirect once per action" if performed?
|
210
|
+
|
211
|
+
if options.nil?
|
212
|
+
return render(:file => default_template_name, :layout => true)
|
213
|
+
elsif !options.is_a?(Hash)
|
214
|
+
raise RenderError, "You called render with invalid options : #{options.inspect}"
|
215
|
+
end
|
216
|
+
|
217
|
+
layout = pick_layout(options)
|
218
|
+
logger.info("Rendering template within #{layout}") if logger && layout
|
219
|
+
|
220
|
+
if options.has_key?(:text)
|
221
|
+
text = layout ? @template.render(options.merge(:text => options[:text], :layout => layout)) : options[:text]
|
222
|
+
render_for_text(text, options[:status])
|
223
|
+
|
224
|
+
else
|
225
|
+
if file = options[:file]
|
226
|
+
render_for_file(file, options[:status], layout, options[:locals] || {})
|
227
|
+
|
228
|
+
elsif template = options[:template]
|
229
|
+
render_for_file(template, options[:status], layout, options[:locals] || {})
|
230
|
+
|
231
|
+
elsif inline = options[:inline]
|
232
|
+
render_for_text(@template.render(options.merge(:layout => layout)), options[:status])
|
233
|
+
|
234
|
+
elsif action_name = options[:action]
|
235
|
+
render_for_file(default_template_name(action_name.to_s), options[:status], layout)
|
236
|
+
|
237
|
+
elsif options[:partial]
|
238
|
+
options[:partial] = default_template_name if options[:partial] == true
|
239
|
+
if layout
|
240
|
+
render_for_text(@template.render(:text => @template.render(options), :layout => layout), options[:status])
|
241
|
+
else
|
242
|
+
render_for_text(@template.render(options), options[:status])
|
243
|
+
end
|
244
|
+
|
245
|
+
elsif options[:nothing]
|
246
|
+
render_for_text("", options[:status])
|
247
|
+
|
248
|
+
else
|
249
|
+
render_for_file(default_template_name, options[:status], layout)
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
# Renders according to the same rules as <tt>render</tt>, but returns the result in a string instead
|
255
|
+
# of sending it as the response body to the browser.
|
256
|
+
def render_to_string(options = nil, &block) #:doc:
|
257
|
+
render(options, &block)
|
258
|
+
ensure
|
259
|
+
erase_render_results
|
260
|
+
reset_variables_added_to_assigns
|
261
|
+
end
|
262
|
+
|
263
|
+
# Clears the rendered results, allowing for another render to be performed.
|
264
|
+
def erase_render_results #:nodoc:
|
265
|
+
response.clear
|
266
|
+
@performed_render = false
|
267
|
+
end
|
268
|
+
|
269
|
+
# Redirects to the target specified in +options+. This parameter can take one of three forms:
|
270
|
+
#
|
271
|
+
# * <tt>Hash</tt> - The URL will be generated by calling url_for with the +options+.
|
272
|
+
# * <tt>Record</tt> - The URL will be generated by calling url_for with the +options+, which will reference a named URL for that record.
|
273
|
+
#
|
274
|
+
# Examples:
|
275
|
+
# redirect_to :action => "show", :id => 5
|
276
|
+
# redirect_to post
|
277
|
+
# redirect_to articles_url
|
278
|
+
#
|
279
|
+
def redirect_to(options = {}) #:doc:
|
280
|
+
raise DoubleRenderError if performed?
|
281
|
+
logger.info("Redirected to #{options}") if logger && logger.info?
|
282
|
+
response.redirected_to = options
|
283
|
+
@performed_redirect = true
|
284
|
+
end
|
285
|
+
|
286
|
+
private
|
287
|
+
|
288
|
+
def render_for_file(template_path, status = nil, layout = nil, locals = {}) #:nodoc:
|
289
|
+
logger.info("Rendering #{template_path}" + (status ? " (#{status})" : '')) if logger
|
290
|
+
render_for_text(@template.render(:file => template_path, :locals => locals, :layout => layout), status)
|
291
|
+
end
|
292
|
+
|
293
|
+
def render_for_text(text = nil, status = nil) #:nodoc:
|
294
|
+
@performed_render = true
|
295
|
+
(instance_variable_names - protected_instance_variables).each {|name| response.variables[name[1..-1].to_sym] = instance_variable_get(name)}
|
296
|
+
response.body = text.to_s
|
297
|
+
# when will we get a proc? TODO investigate: response.body = text.is_a?(Proc) ? text : text.to_s
|
298
|
+
end
|
299
|
+
|
300
|
+
def assign_params(request)
|
301
|
+
@action_name = request.params[:action] || 'index'
|
302
|
+
@format = request.format
|
303
|
+
@_params = request.params.clone
|
304
|
+
@_params.delete(:controller)
|
305
|
+
@_params.delete(:action)
|
306
|
+
end
|
307
|
+
|
308
|
+
def initialize_template_class(response)
|
309
|
+
# Find the suitable Template class for the format of the request TODO: use class inheritable attr instead
|
310
|
+
template_class = @@template_classes[@format] || Reactive::Mvc::View::Base
|
311
|
+
#unless template_class = @@template_classes[@format]
|
312
|
+
# raise "You must assign a template class through Reactive::Controller::Base.register_template_class before processing a request\n" +
|
313
|
+
# "This may also happen when no view provider is configured. Check that you have one in config/environment.rb with config.gem 'your_view_provider'"
|
314
|
+
#end
|
315
|
+
|
316
|
+
response.template = template_class.new(view_paths, self)
|
317
|
+
response.template.extend self.class.master_helper_module
|
318
|
+
response.redirected_to = nil
|
319
|
+
@performed_render = @performed_redirect = false
|
320
|
+
end
|
321
|
+
|
322
|
+
def assign_shortcuts(request, response)
|
323
|
+
@_request = request
|
324
|
+
@_response = response
|
325
|
+
@template = response.template
|
326
|
+
end
|
327
|
+
|
328
|
+
def log_processing
|
329
|
+
if logger && logger.info?
|
330
|
+
logger.info "Processing #{controller_class_name}\##{action_name}"
|
331
|
+
logger.info " Parameters: #{respond_to?(:filter_parameters) ? filter_parameters(@_params).inspect : @_params.inspect}"
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
def default_render #:nodoc:
|
336
|
+
render
|
337
|
+
end
|
338
|
+
|
339
|
+
def perform_action
|
340
|
+
if action_methods.include?(action_name)
|
341
|
+
send(action_name)
|
342
|
+
default_render unless performed?
|
343
|
+
elsif respond_to? :method_missing
|
344
|
+
method_missing action_name
|
345
|
+
default_render unless performed?
|
346
|
+
elsif template_exists?
|
347
|
+
default_render
|
348
|
+
else
|
349
|
+
raise UnknownAction, "No action responded to #{action_name}", caller
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
def performed?
|
354
|
+
@performed_render || @performed_redirect
|
355
|
+
end
|
356
|
+
|
357
|
+
def action_methods
|
358
|
+
self.class.action_methods
|
359
|
+
end
|
360
|
+
|
361
|
+
def self.action_methods
|
362
|
+
@action_methods ||=
|
363
|
+
# All public instance methods of this class, including ancestors
|
364
|
+
public_instance_methods(true).map { |m| m.to_s }.to_set -
|
365
|
+
# Except for public instance methods of Base and its ancestors
|
366
|
+
Base.public_instance_methods(true).map { |m| m.to_s } +
|
367
|
+
# Be sure to include shadowed public instance methods of this class
|
368
|
+
public_instance_methods(false).map { |m| m.to_s } -
|
369
|
+
# And always exclude explicitly hidden actions
|
370
|
+
hidden_actions
|
371
|
+
end
|
372
|
+
|
373
|
+
def reset_variables_added_to_assigns
|
374
|
+
@template.instance_variable_set("@assigns_added", nil)
|
375
|
+
end
|
376
|
+
|
377
|
+
def template_exists?(template_name = default_template_name)
|
378
|
+
@template.template_exists?(template_name) # TODO: Contract with the View provider!!!
|
379
|
+
end
|
380
|
+
|
381
|
+
def default_template_name(action_name = self.action_name)
|
382
|
+
if action_name
|
383
|
+
action_name = action_name.to_s
|
384
|
+
if action_name.include?('/') && template_path_includes_controller?(action_name)
|
385
|
+
action_name = strip_out_controller(action_name)
|
386
|
+
end
|
387
|
+
end
|
388
|
+
"#{self.controller_path}/#{action_name}"
|
389
|
+
end
|
390
|
+
|
391
|
+
def strip_out_controller(path)
|
392
|
+
path.split('/', 2).last
|
393
|
+
end
|
394
|
+
|
395
|
+
def template_path_includes_controller?(path)
|
396
|
+
self.controller_path.split('/')[-1] == path.split('/')[0]
|
397
|
+
end
|
398
|
+
|
399
|
+
def process_cleanup
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
403
|
+
end
|
404
|
+
|
405
|
+
end
|