actionpack 1.9.1 → 1.10.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- data/CHANGELOG +237 -0
- data/README +12 -12
- data/lib/action_controller.rb +17 -12
- data/lib/action_controller/assertions.rb +119 -67
- data/lib/action_controller/base.rb +184 -102
- data/lib/action_controller/benchmarking.rb +35 -6
- data/lib/action_controller/caching.rb +115 -58
- data/lib/action_controller/cgi_ext/cgi_methods.rb +54 -21
- data/lib/action_controller/cgi_ext/cookie_performance_fix.rb +39 -35
- data/lib/action_controller/cgi_ext/raw_post_data_fix.rb +34 -21
- data/lib/action_controller/cgi_process.rb +23 -20
- data/lib/action_controller/components.rb +11 -2
- data/lib/action_controller/dependencies.rb +0 -5
- data/lib/action_controller/deprecated_redirects.rb +17 -0
- data/lib/action_controller/filters.rb +13 -9
- data/lib/action_controller/flash.rb +7 -7
- data/lib/action_controller/helpers.rb +1 -14
- data/lib/action_controller/layout.rb +40 -29
- data/lib/action_controller/macros/auto_complete.rb +52 -0
- data/lib/action_controller/macros/in_place_editing.rb +32 -0
- data/lib/action_controller/pagination.rb +44 -28
- data/lib/action_controller/request.rb +54 -40
- data/lib/action_controller/rescue.rb +8 -6
- data/lib/action_controller/routing.rb +77 -28
- data/lib/action_controller/scaffolding.rb +10 -14
- data/lib/action_controller/session/active_record_store.rb +36 -7
- data/lib/action_controller/session_management.rb +126 -0
- data/lib/action_controller/streaming.rb +14 -5
- data/lib/action_controller/templates/rescues/_request_and_response.rhtml +1 -1
- data/lib/action_controller/templates/rescues/_trace.rhtml +24 -0
- data/lib/action_controller/templates/rescues/diagnostics.rhtml +2 -13
- data/lib/action_controller/templates/rescues/template_error.rhtml +4 -2
- data/lib/action_controller/templates/scaffolds/list.rhtml +1 -1
- data/lib/action_controller/test_process.rb +35 -17
- data/lib/action_controller/upload_progress.rb +52 -0
- data/lib/action_controller/url_rewriter.rb +21 -16
- data/lib/action_controller/vendor/html-scanner/html/document.rb +2 -2
- data/lib/action_controller/vendor/html-scanner/html/node.rb +30 -3
- data/lib/action_pack/version.rb +9 -0
- data/lib/action_view.rb +1 -1
- data/lib/action_view/base.rb +204 -60
- data/lib/action_view/compiled_templates.rb +70 -0
- data/lib/action_view/helpers/active_record_helper.rb +7 -3
- data/lib/action_view/helpers/asset_tag_helper.rb +22 -12
- data/lib/action_view/helpers/capture_helper.rb +2 -10
- data/lib/action_view/helpers/date_helper.rb +21 -13
- data/lib/action_view/helpers/form_helper.rb +14 -10
- data/lib/action_view/helpers/form_options_helper.rb +4 -4
- data/lib/action_view/helpers/form_tag_helper.rb +59 -25
- data/lib/action_view/helpers/java_script_macros_helper.rb +188 -0
- data/lib/action_view/helpers/javascript_helper.rb +68 -133
- data/lib/action_view/helpers/javascripts/controls.js +427 -165
- data/lib/action_view/helpers/javascripts/dragdrop.js +256 -277
- data/lib/action_view/helpers/javascripts/effects.js +766 -277
- data/lib/action_view/helpers/javascripts/prototype.js +906 -218
- data/lib/action_view/helpers/javascripts/slider.js +258 -0
- data/lib/action_view/helpers/number_helper.rb +4 -3
- data/lib/action_view/helpers/pagination_helper.rb +42 -27
- data/lib/action_view/helpers/tag_helper.rb +25 -11
- data/lib/action_view/helpers/text_helper.rb +119 -13
- data/lib/action_view/helpers/upload_progress_helper.rb +2 -2
- data/lib/action_view/helpers/url_helper.rb +68 -21
- data/lib/action_view/partials.rb +17 -6
- data/lib/action_view/template_error.rb +19 -24
- data/rakefile +4 -3
- data/test/abstract_unit.rb +2 -1
- data/test/controller/action_pack_assertions_test.rb +62 -2
- data/test/controller/active_record_assertions_test.rb +5 -6
- data/test/controller/active_record_store_test.rb +23 -1
- data/test/controller/addresses_render_test.rb +4 -0
- data/test/controller/{base_tests.rb → base_test.rb} +4 -3
- data/test/controller/benchmark_test.rb +36 -0
- data/test/controller/caching_filestore.rb +22 -40
- data/test/controller/capture_test.rb +10 -1
- data/test/controller/cgi_test.rb +145 -23
- data/test/controller/components_test.rb +50 -0
- data/test/controller/custom_handler_test.rb +3 -3
- data/test/controller/fake_controllers.rb +24 -0
- data/test/controller/filters_test.rb +6 -6
- data/test/controller/flash_test.rb +6 -6
- data/test/controller/fragment_store_setting_test.rb +45 -0
- data/test/controller/helper_test.rb +1 -3
- data/test/controller/new_render_test.rb +119 -7
- data/test/controller/redirect_test.rb +11 -1
- data/test/controller/render_test.rb +34 -1
- data/test/controller/request_test.rb +14 -5
- data/test/controller/routing_test.rb +238 -42
- data/test/controller/send_file_test.rb +11 -10
- data/test/controller/session_management_test.rb +94 -0
- data/test/controller/test_test.rb +194 -5
- data/test/controller/url_rewriter_test.rb +46 -0
- data/test/fixtures/layouts/talk_from_action.rhtml +2 -0
- data/test/fixtures/layouts/yield.rhtml +2 -0
- data/test/fixtures/multipart/binary_file +0 -0
- data/test/fixtures/multipart/large_text_file +10 -0
- data/test/fixtures/multipart/mixed_files +0 -0
- data/test/fixtures/multipart/single_parameter +5 -0
- data/test/fixtures/multipart/text_file +10 -0
- data/test/fixtures/test/_customer_greeting.rhtml +1 -0
- data/test/fixtures/test/_hash_object.rhtml +1 -0
- data/test/fixtures/test/_person.rhtml +2 -0
- data/test/fixtures/test/action_talk_to_layout.rhtml +2 -0
- data/test/fixtures/test/content_for.rhtml +2 -0
- data/test/fixtures/test/potential_conflicts.rhtml +4 -0
- data/test/template/active_record_helper_test.rb +15 -8
- data/test/template/asset_tag_helper_test.rb +40 -16
- data/test/template/compiled_templates_tests.rb +63 -0
- data/test/template/date_helper_test.rb +80 -4
- data/test/template/form_helper_test.rb +48 -42
- data/test/template/form_options_helper_test.rb +40 -40
- data/test/template/form_tag_helper_test.rb +21 -15
- data/test/template/java_script_macros_helper_test.rb +56 -0
- data/test/template/javascript_helper_test.rb +70 -47
- data/test/template/number_helper_test.rb +2 -0
- data/test/template/tag_helper_test.rb +9 -0
- data/test/template/text_helper_test.rb +146 -1
- data/test/template/upload_progress_helper_testx.rb +11 -147
- data/test/template/url_helper_test.rb +90 -22
- data/test/testing_sandbox.rb +26 -0
- metadata +37 -7
- data/lib/action_controller/auto_complete.rb +0 -47
- data/lib/action_controller/deprecated_renders_and_redirects.rb +0 -76
- data/lib/action_controller/session.rb +0 -14
data/lib/action_view.rb
CHANGED
data/lib/action_view/base.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'erb'
|
2
2
|
|
3
3
|
module ActionView #:nodoc:
|
4
|
+
|
4
5
|
class ActionViewError < StandardError #:nodoc:
|
5
6
|
end
|
6
7
|
|
@@ -37,7 +38,7 @@ module ActionView #:nodoc:
|
|
37
38
|
# result of the rendering. The output embedding writes it to the current template.
|
38
39
|
#
|
39
40
|
# But you don't have to restrict yourself to static includes. Templates can share variables amongst themselves by using instance
|
40
|
-
# variables defined
|
41
|
+
# variables defined using the regular embedding tags. Like this:
|
41
42
|
#
|
42
43
|
# <% @page_title = "A Wonderful Hello" %>
|
43
44
|
# <%= render "shared/header" %>
|
@@ -59,10 +60,8 @@ module ActionView #:nodoc:
|
|
59
60
|
#
|
60
61
|
# == Template caching
|
61
62
|
#
|
62
|
-
#
|
63
|
-
#
|
64
|
-
# caching the loading of templates (reading from the file system), you can turn that on with
|
65
|
-
# <tt>ActionView::Base.cache_template_loading = true</tt>.
|
63
|
+
# By default, Rails will compile each template to a method in order to render it. When you alter a template, Rails will
|
64
|
+
# check the file's modification time and recompile it.
|
66
65
|
#
|
67
66
|
# == Builder
|
68
67
|
#
|
@@ -118,22 +117,47 @@ module ActionView #:nodoc:
|
|
118
117
|
# More builder documentation can be found at http://builder.rubyforge.org.
|
119
118
|
class Base
|
120
119
|
include ERB::Util
|
121
|
-
|
120
|
+
|
122
121
|
attr_reader :first_render
|
123
122
|
attr_accessor :base_path, :assigns, :template_extension
|
124
123
|
attr_accessor :controller
|
125
|
-
|
124
|
+
|
126
125
|
attr_reader :logger, :params, :response, :session, :headers, :flash
|
127
126
|
|
128
|
-
#
|
129
|
-
#
|
127
|
+
# Specify trim mode for the ERB compiler. Defaults to '-'.
|
128
|
+
# See ERB documentation for suitable values.
|
129
|
+
@@erb_trim_mode = '-'
|
130
|
+
cattr_accessor :erb_trim_mode
|
131
|
+
|
132
|
+
# Specify whether file modification times should be checked to see if a template needs recompilation
|
130
133
|
@@cache_template_loading = false
|
131
134
|
cattr_accessor :cache_template_loading
|
132
135
|
|
133
|
-
|
134
|
-
|
136
|
+
# Specify whether local_assigns should be able to use string keys.
|
137
|
+
# Defaults to +true+. String keys are deprecated and will be removed
|
138
|
+
# shortly.
|
139
|
+
@@local_assigns_support_string_keys = true
|
140
|
+
cattr_accessor :local_assigns_support_string_keys
|
141
|
+
|
135
142
|
@@template_handlers = {}
|
143
|
+
|
144
|
+
module CompiledTemplates #:nodoc:
|
145
|
+
# holds compiled template code
|
146
|
+
end
|
147
|
+
include CompiledTemplates
|
148
|
+
|
149
|
+
# maps inline templates to their method names
|
150
|
+
@@method_names = {}
|
151
|
+
# map method names to their compile time
|
152
|
+
@@compile_time = {}
|
153
|
+
# map method names to the names passed in local assigns so far
|
154
|
+
@@template_args = {}
|
155
|
+
# count the number of inline templates
|
156
|
+
@@inline_template_count = 0
|
136
157
|
|
158
|
+
class ObjectWrapper < Struct.new(:value) #:nodoc:
|
159
|
+
end
|
160
|
+
|
137
161
|
def self.load_helpers(helper_dir)#:nodoc:
|
138
162
|
Dir.foreach(helper_dir) do |helper_file|
|
139
163
|
next unless helper_file =~ /_helper.rb$/
|
@@ -144,13 +168,22 @@ module ActionView #:nodoc:
|
|
144
168
|
end
|
145
169
|
end
|
146
170
|
|
171
|
+
# Register a class that knows how to handle template files with the given
|
172
|
+
# extension. This can be used to implement new template types.
|
173
|
+
# The constructor for the class must take the ActiveView::Base instance
|
174
|
+
# as a parameter, and the class must implement a #render method that
|
175
|
+
# takes the contents of the template to render as well as the Hash of
|
176
|
+
# local assigns available to the template. The #render method ought to
|
177
|
+
# return the rendered template as a string.
|
147
178
|
def self.register_template_handler(extension, klass)
|
148
179
|
@@template_handlers[extension] = klass
|
149
180
|
end
|
150
181
|
|
151
182
|
def initialize(base_path = nil, assigns_for_first_render = {}, controller = nil)#:nodoc:
|
152
183
|
@base_path, @assigns = base_path, assigns_for_first_render
|
184
|
+
@assigns_added = nil
|
153
185
|
@controller = controller
|
186
|
+
@logger = controller && controller.logger
|
154
187
|
end
|
155
188
|
|
156
189
|
# Renders the template present at <tt>template_path</tt>. If <tt>use_full_path</tt> is set to true,
|
@@ -158,19 +191,19 @@ module ActionView #:nodoc:
|
|
158
191
|
# is made available as local variables.
|
159
192
|
def render_file(template_path, use_full_path = true, local_assigns = {})
|
160
193
|
@first_render = template_path if @first_render.nil?
|
161
|
-
|
194
|
+
|
162
195
|
if use_full_path
|
163
196
|
template_extension = pick_template_extension(template_path)
|
164
197
|
template_file_name = full_template_path(template_path, template_extension)
|
165
198
|
else
|
166
199
|
template_file_name = template_path
|
167
|
-
template_extension = template_path.split(
|
200
|
+
template_extension = template_path.split('.').last
|
168
201
|
end
|
169
|
-
|
170
|
-
template_source =
|
202
|
+
|
203
|
+
template_source = nil # Don't read the source until we know that it is required
|
171
204
|
|
172
205
|
begin
|
173
|
-
render_template(template_extension, template_source, local_assigns)
|
206
|
+
render_template(template_extension, template_source, template_file_name, local_assigns)
|
174
207
|
rescue Exception => e
|
175
208
|
if TemplateError === e
|
176
209
|
e.sub_template_of(template_file_name)
|
@@ -180,7 +213,7 @@ module ActionView #:nodoc:
|
|
180
213
|
end
|
181
214
|
end
|
182
215
|
end
|
183
|
-
|
216
|
+
|
184
217
|
# Renders the template present at <tt>template_path</tt> (relative to the template_root).
|
185
218
|
# The hash in <tt>local_assigns</tt> is made available as local variables.
|
186
219
|
def render(options = {}, old_local_assigns = {})
|
@@ -189,56 +222,77 @@ module ActionView #:nodoc:
|
|
189
222
|
elsif options.is_a?(Hash)
|
190
223
|
options[:locals] ||= {}
|
191
224
|
options[:use_full_path] = options[:use_full_path].nil? ? true : options[:use_full_path]
|
192
|
-
|
225
|
+
|
193
226
|
if options[:file]
|
194
227
|
render_file(options[:file], options[:use_full_path], options[:locals])
|
195
228
|
elsif options[:partial] && options[:collection]
|
196
229
|
render_partial_collection(options[:partial], options[:collection], options[:spacer_template], options[:locals])
|
197
230
|
elsif options[:partial]
|
198
|
-
render_partial(options[:partial], options[:object], options[:locals])
|
231
|
+
render_partial(options[:partial], ActionView::Base::ObjectWrapper.new(options[:object]), options[:locals])
|
199
232
|
elsif options[:inline]
|
200
|
-
render_template(options[:type] || :rhtml, options[:inline], options[:locals] || {})
|
233
|
+
render_template(options[:type] || :rhtml, options[:inline], nil, options[:locals] || {})
|
201
234
|
end
|
202
235
|
end
|
203
236
|
end
|
204
|
-
|
237
|
+
|
205
238
|
# Renders the +template+ which is given as a string as either rhtml or rxml depending on <tt>template_extension</tt>.
|
206
239
|
# The hash in <tt>local_assigns</tt> is made available as local variables.
|
207
|
-
def render_template(template_extension, template, local_assigns = {})
|
208
|
-
|
209
|
-
template,
|
240
|
+
def render_template(template_extension, template, file_path = nil, local_assigns = {})
|
241
|
+
if handler = @@template_handlers[template_extension]
|
242
|
+
template ||= read_template_file(file_path, template_extension) # Make sure that a lazyily-read template is loaded.
|
243
|
+
delegate_render(handler, template, local_assigns)
|
244
|
+
else
|
245
|
+
compile_and_render_template(template_extension, template, file_path, local_assigns)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
# Render the provided template with the given local assigns. If the template has not been rendered with the provided
|
250
|
+
# local assigns yet, or if the template has been updated on disk, then the template will be compiled to a method.
|
251
|
+
#
|
252
|
+
|
253
|
+
# Either, but not both, of template and file_path may be nil. If file_path is given, the template
|
254
|
+
# will only be read if it has to be compiled.
|
255
|
+
#
|
256
|
+
def compile_and_render_template(extension, template = nil, file_path = nil, local_assigns = {})
|
257
|
+
# compile the given template, if necessary
|
258
|
+
if compile_template?(template, file_path, local_assigns)
|
259
|
+
template ||= read_template_file(file_path, extension)
|
260
|
+
compile_template(extension, template, file_path, local_assigns)
|
261
|
+
end
|
262
|
+
|
263
|
+
# Get the method name for this template and run it
|
264
|
+
method_name = @@method_names[file_path || template]
|
265
|
+
evaluate_assigns
|
266
|
+
|
267
|
+
local_assigns = local_assigns.symbolize_keys if @@local_assigns_support_string_keys
|
268
|
+
|
269
|
+
send(method_name, local_assigns) do |*name|
|
270
|
+
instance_variable_get "@content_for_#{name.first || 'layout'}"
|
271
|
+
end
|
210
272
|
end
|
211
273
|
|
212
274
|
def pick_template_extension(template_path)#:nodoc:
|
213
275
|
if match = delegate_template_exists?(template_path)
|
214
276
|
match.first
|
215
277
|
elsif erb_template_exists?(template_path)
|
216
|
-
|
278
|
+
'rhtml'
|
217
279
|
elsif builder_template_exists?(template_path)
|
218
|
-
|
280
|
+
'rxml'
|
219
281
|
else
|
220
282
|
raise ActionViewError, "No rhtml, rxml, or delegate template found for #{template_path}"
|
221
283
|
end
|
222
284
|
end
|
223
|
-
|
224
|
-
def pick_rendering_method(template_extension)#:nodoc:
|
225
|
-
if @@template_handlers[template_extension]
|
226
|
-
"delegate_render"
|
227
|
-
else
|
228
|
-
(template_extension.to_s == "rxml" ? "rxml" : "rhtml") + "_render"
|
229
|
-
end
|
230
|
-
end
|
231
285
|
|
232
286
|
def delegate_template_exists?(template_path)#:nodoc:
|
233
287
|
@@template_handlers.find { |k,| template_exists?(template_path, k) }
|
234
288
|
end
|
235
289
|
|
236
290
|
def erb_template_exists?(template_path)#:nodoc:
|
237
|
-
template_exists?(template_path,
|
291
|
+
template_exists?(template_path, :rhtml)
|
238
292
|
end
|
239
293
|
|
240
294
|
def builder_template_exists?(template_path)#:nodoc:
|
241
|
-
template_exists?(template_path,
|
295
|
+
template_exists?(template_path, :rxml)
|
242
296
|
end
|
243
297
|
|
244
298
|
def file_exists?(template_path)#:nodoc:
|
@@ -247,7 +301,7 @@ module ActionView #:nodoc:
|
|
247
301
|
|
248
302
|
# Returns true is the file may be rendered implicitly.
|
249
303
|
def file_public?(template_path)#:nodoc:
|
250
|
-
template_path.split(
|
304
|
+
template_path.split('/').last[0,1] != '_'
|
251
305
|
end
|
252
306
|
|
253
307
|
private
|
@@ -256,43 +310,133 @@ module ActionView #:nodoc:
|
|
256
310
|
end
|
257
311
|
|
258
312
|
def template_exists?(template_path, extension)
|
259
|
-
|
260
|
-
|
313
|
+
file_path = full_template_path(template_path, extension)
|
314
|
+
@@method_names.has_key?(file_path) || FileTest.exists?(file_path)
|
315
|
+
end
|
316
|
+
|
317
|
+
# This method reads a template file.
|
318
|
+
def read_template_file(template_path, extension)
|
319
|
+
File.read(template_path)
|
261
320
|
end
|
262
321
|
|
263
|
-
def
|
264
|
-
unless
|
265
|
-
|
322
|
+
def evaluate_assigns
|
323
|
+
unless @assigns_added
|
324
|
+
assign_variables_from_controller
|
325
|
+
@assigns_added = true
|
266
326
|
end
|
327
|
+
end
|
267
328
|
|
268
|
-
|
329
|
+
def delegate_render(handler, template, local_assigns)
|
330
|
+
handler.new(self).render(template, local_assigns)
|
331
|
+
end
|
332
|
+
|
333
|
+
def assign_variables_from_controller
|
334
|
+
@assigns.each { |key, value| instance_variable_set("@#{key}", value) }
|
269
335
|
end
|
270
336
|
|
271
|
-
def evaluate_locals(local_assigns = {})
|
272
|
-
b = binding
|
273
337
|
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
338
|
+
# Return true if the given template was compiled for a superset of the keys in local_assigns
|
339
|
+
def supports_local_assigns?(render_symbol, local_assigns)
|
340
|
+
local_assigns.empty? ||
|
341
|
+
((args = @@template_args[render_symbol]) && local_assigns.all? { |k,_| args.has_key?(k) })
|
342
|
+
end
|
343
|
+
|
344
|
+
# Check whether compilation is necessary.
|
345
|
+
# Compile if the inline template or file has not been compiled yet.
|
346
|
+
# Or if local_assigns has a new key, which isn't supported by the compiled code yet.
|
347
|
+
# Or if the file has changed on disk and checking file mods hasn't been disabled.
|
348
|
+
def compile_template?(template, file_name, local_assigns)
|
349
|
+
method_key = file_name || template
|
350
|
+
render_symbol = @@method_names[method_key]
|
278
351
|
|
279
|
-
|
352
|
+
if @@compile_time[render_symbol] && supports_local_assigns?(render_symbol, local_assigns)
|
353
|
+
if file_name && !@@cache_template_loading
|
354
|
+
@@compile_time[render_symbol] < File.mtime(file_name)
|
355
|
+
end
|
356
|
+
else
|
357
|
+
true
|
358
|
+
end
|
280
359
|
end
|
281
360
|
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
361
|
+
# Create source code for given template
|
362
|
+
def create_template_source(extension, template, render_symbol, locals)
|
363
|
+
if extension && (extension.to_sym == :rxml)
|
364
|
+
body = "xml = Builder::XmlMarkup.new(:indent => 2)\n" +
|
365
|
+
"@controller.headers['Content-Type'] ||= 'text/xml'\n" +
|
366
|
+
template
|
367
|
+
else
|
368
|
+
body = ERB.new(template, nil, @@erb_trim_mode).src
|
369
|
+
end
|
370
|
+
|
371
|
+
@@template_args[render_symbol] ||= {}
|
372
|
+
locals_keys = @@template_args[render_symbol].keys | locals
|
373
|
+
@@template_args[render_symbol] = locals_keys.inject({}) { |h, k| h[k] = true; h }
|
374
|
+
|
375
|
+
locals_code = ""
|
376
|
+
locals_keys.each do |key|
|
377
|
+
locals_code << "#{key} = local_assigns[:#{key}] if local_assigns.has_key?(:#{key})\n"
|
378
|
+
end
|
379
|
+
|
380
|
+
"def #{render_symbol}(local_assigns)\n#{locals_code}#{body}\nend"
|
286
381
|
end
|
287
382
|
|
288
|
-
def
|
289
|
-
|
290
|
-
|
383
|
+
def assign_method_name(extension, template, file_name)
|
384
|
+
method_name = '_run_'
|
385
|
+
|
386
|
+
if extension && (extension.to_sym == :rxml)
|
387
|
+
method_name << 'xml_'
|
388
|
+
else
|
389
|
+
method_name << 'html_'
|
390
|
+
end
|
391
|
+
|
392
|
+
if file_name
|
393
|
+
file_path = File.expand_path(file_name)
|
394
|
+
base_path = File.expand_path(@base_path)
|
395
|
+
|
396
|
+
i = file_path.index(base_path)
|
397
|
+
l = base_path.length
|
398
|
+
|
399
|
+
method_name_file_part = i ? file_path[i+l+1,file_path.length-l-1] : file_path.clone
|
400
|
+
method_name_file_part.sub!(/\.r(ht|x)ml$/,'')
|
401
|
+
method_name_file_part.tr!('/:-', '_')
|
402
|
+
method_name_file_part.gsub!(/[^a-zA-Z0-9_]/){|s| s[0].to_s}
|
403
|
+
|
404
|
+
method_name += method_name_file_part
|
405
|
+
else
|
406
|
+
@@inline_template_count += 1
|
407
|
+
method_name << @@inline_template_count.to_s
|
408
|
+
end
|
409
|
+
|
410
|
+
@@method_names[file_name || template] = method_name.intern
|
291
411
|
end
|
292
412
|
|
293
|
-
def
|
294
|
-
|
295
|
-
|
413
|
+
def compile_template(extension, template, file_name, local_assigns)
|
414
|
+
method_key = file_name || template
|
415
|
+
|
416
|
+
render_symbol = @@method_names[method_key] || assign_method_name(extension, template, file_name)
|
417
|
+
render_source = create_template_source(extension, template, render_symbol, local_assigns.keys)
|
418
|
+
|
419
|
+
line_offset = @@template_args[render_symbol].size
|
420
|
+
line_offset += 2 if extension && (extension.to_sym == :rxml)
|
421
|
+
|
422
|
+
begin
|
423
|
+
unless file_name.blank?
|
424
|
+
CompiledTemplates.module_eval(render_source, file_name, -line_offset)
|
425
|
+
else
|
426
|
+
CompiledTemplates.module_eval(render_source, 'compiled-template', -line_offset)
|
427
|
+
end
|
428
|
+
rescue Object => e
|
429
|
+
if logger
|
430
|
+
logger.debug "ERROR: compiling #{render_symbol} RAISED #{e}"
|
431
|
+
logger.debug "Function body: #{render_source}"
|
432
|
+
logger.debug "Backtrace: #{e.backtrace.join("\n")}"
|
433
|
+
end
|
434
|
+
|
435
|
+
raise TemplateError.new(@base_path, method_key, @assigns, template, e)
|
436
|
+
end
|
437
|
+
|
438
|
+
@@compile_time[render_symbol] = Time.now
|
439
|
+
# logger.debug "Compiled template #{method_key}\n ==> #{render_symbol}" if logger
|
296
440
|
end
|
297
441
|
end
|
298
442
|
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
|
2
|
+
module ActionView
|
3
|
+
|
4
|
+
# CompiledTemplates modules hold methods that have been compiled.
|
5
|
+
# Templates are compiled into these methods so that they do not need to be
|
6
|
+
# re-read and re-parsed each request.
|
7
|
+
#
|
8
|
+
# Each template may be compiled into one or more methods. Each method accepts a given
|
9
|
+
# set of parameters which is used to implement local assigns passing.
|
10
|
+
#
|
11
|
+
# To use a compiled template module, create a new instance and include it into the class
|
12
|
+
# in which you want the template to be rendered.
|
13
|
+
class CompiledTemplates < Module
|
14
|
+
attr_reader :method_names
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
@method_names = Hash.new do |hash, key|
|
18
|
+
hash[key] = "__compiled_method_#{(hash.length + 1)}"
|
19
|
+
end
|
20
|
+
@mtimes = {}
|
21
|
+
end
|
22
|
+
|
23
|
+
# Return the full key for the given identifier and argument names
|
24
|
+
def full_key(identifier, arg_names)
|
25
|
+
[identifier, arg_names]
|
26
|
+
end
|
27
|
+
|
28
|
+
# Return the selector for this method or nil if it has not been compiled
|
29
|
+
def selector(identifier, arg_names)
|
30
|
+
key = full_key(identifier, arg_names)
|
31
|
+
method_names.key?(key) ? method_names[key] : nil
|
32
|
+
end
|
33
|
+
alias :compiled? :selector
|
34
|
+
|
35
|
+
# Return the time at which the method for the given identifier and argument names was compiled.
|
36
|
+
def mtime(identifier, arg_names)
|
37
|
+
@mtimes[full_key(identifier, arg_names)]
|
38
|
+
end
|
39
|
+
|
40
|
+
# Compile the provided source code for the given argument names and with the given initial line number.
|
41
|
+
# The identifier should be unique to this source.
|
42
|
+
#
|
43
|
+
# The file_name, if provided will appear in backtraces. If not provded, the file_name defaults
|
44
|
+
# to the identifier.
|
45
|
+
#
|
46
|
+
# This method will return the selector for the compiled version of this method.
|
47
|
+
def compile_source(identifier, arg_names, source, initial_line_number = 0, file_name = nil)
|
48
|
+
file_name ||= identifier
|
49
|
+
name = method_names[full_key(identifier, arg_names)]
|
50
|
+
arg_desc = arg_names.empty? ? '' : "(#{arg_names * ', '})"
|
51
|
+
fake_file_name = "#{file_name}#{arg_desc}" # Include the arguments for this version (for now)
|
52
|
+
|
53
|
+
method_def = wrap_source(name, arg_names, source)
|
54
|
+
|
55
|
+
begin
|
56
|
+
module_eval(method_def, fake_file_name, initial_line_number)
|
57
|
+
@mtimes[full_key(identifier, arg_names)] = Time.now
|
58
|
+
rescue Object => e
|
59
|
+
e.blame_file! identifier
|
60
|
+
raise
|
61
|
+
end
|
62
|
+
name
|
63
|
+
end
|
64
|
+
|
65
|
+
# Wrap the provided source in a def ... end block.
|
66
|
+
def wrap_source(name, arg_names, source)
|
67
|
+
"def #{name}(#{arg_names * ', '})\n#{source}\nend"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|