Ticket #11024: template_class.patch
| File template_class.patch, 23.9 kB (added by lifofifo, 7 months ago) |
|---|
-
a/actionpack/lib/action_controller/base.rb
old new 5 5 require 'action_controller/resources' 6 6 require 'action_controller/url_rewriter' 7 7 require 'action_controller/status_codes' 8 require 'action_view/template' 8 9 require 'action_view/template_finder' 9 10 require 'drb' 10 11 require 'set' … … 866 867 867 868 elsif inline = options[:inline] 868 869 add_variables_to_assigns 869 render_for_text(@template.render_template(options[:type], inline, nil, options[:locals] || {}), options[:status]) 870 tmpl = ActionView::Template.new(@template, options[:inline], false, options[:locals], true, options[:type]) 871 render_for_text(@template.render_template(tmpl), options[:status]) 870 872 871 873 elsif action_name = options[:action] 872 874 template = default_template_name(action_name.to_s) -
a/actionpack/lib/action_view.rb
old new 28 28 require 'action_view/template_handlers/rjs' 29 29 30 30 require 'action_view/template_finder' 31 require 'action_view/template' 31 32 32 33 require 'action_view/base' 33 34 require 'action_view/partials' -
a/actionpack/lib/action_view/base.rb
old new 150 150 class Base 151 151 include ERB::Util 152 152 153 attr_reader :fi rst_render, :finder154 attr_accessor :base_path, :assigns, :template_extension 153 attr_reader :finder 154 attr_accessor :base_path, :assigns, :template_extension, :first_render 155 155 attr_accessor :controller 156 156 157 157 attr_reader :logger, :response, :headers … … 173 173 # Should be +false+ for development environments. Defaults to +true+. 174 174 @@cache_template_extensions = true 175 175 cattr_accessor :cache_template_extensions 176 177 # Specify whether local_assigns should be able to use string keys.178 # Defaults to +true+. String keys are deprecated and will be removed179 # shortly.180 @@local_assigns_support_string_keys = true181 cattr_accessor :local_assigns_support_string_keys182 176 183 177 # Specify whether RJS responses should be wrapped in a try/catch block 184 178 # that alert()s the caught exception (and then re-raises it). … … 282 276 END_ERROR 283 277 end 284 278 285 # Clear the forward slash at the beginning if exists 286 template_path = template_path.sub(/^\//, '') if use_full_path 287 288 @first_render ||= template_path 289 template_path_without_extension, template_extension = @finder.path_and_extension(template_path) 290 if use_full_path 291 if template_extension 292 template_file_name = @finder.pick_template(template_path_without_extension, template_extension) 293 else 294 template_extension = @finder.pick_template_extension(template_path).to_s 295 unless template_extension 296 raise ActionViewError, "No template found for #{template_path} in #{@finder.view_paths.inspect}" 297 end 298 template_file_name = @finder.pick_template(template_path, template_extension) 299 template_extension = template_extension.gsub(/^.+\./, '') # strip off any formats 300 end 301 else 302 template_file_name = template_path 303 end 304 305 template_source = nil # Don't read the source until we know that it is required 306 307 if template_file_name.blank? 308 raise ActionViewError, "Couldn't find template file for #{template_path} in #{@finder.view_paths.inspect}" 309 end 310 279 template = Template.new(self, template_path, use_full_path, local_assigns) 280 311 281 begin 312 render_template(template _extension, template_source, template_file_name, local_assigns)282 render_template(template) 313 283 rescue Exception => e 314 284 if TemplateError === e 315 e.sub_template_of(template _file_name)285 e.sub_template_of(template.filename) 316 286 raise e 317 287 else 318 raise TemplateError.new(@finder.find_base_path_for("#{template_path_without_extension}.#{template_extension}") || 319 @finder.view_paths.first, template_file_name, @assigns, template_source, e) 288 raise TemplateError.new(template, @assigns, e) 320 289 end 321 290 end 322 291 end … … 350 319 elsif options[:partial] 351 320 render_partial(options[:partial], ActionView::Base::ObjectWrapper.new(options[:object]), options[:locals]) 352 321 elsif options[:inline] 353 render_template(options[:type], options[:inline], nil, options[:locals]) 322 template = Template.new(self, options[:inline], false, options[:locals], true, options[:type]) 323 render_template(template) 354 324 end 355 325 end 356 326 end 357 327 358 328 # Renders the +template+ which is given as a string as either erb or builder depending on <tt>template_extension</tt>. 359 329 # The hash in <tt>local_assigns</tt> is made available as local variables. 360 def render_template(template _extension, template, file_path = nil, local_assigns = {}) #:nodoc:361 handler = self.class.handler_class_for_extension(template_extension).new(self)362 @current_render_extension = template _extension330 def render_template(template) #:nodoc: 331 handler = template.handler 332 @current_render_extension = template.extension 363 333 364 334 if handler.compilable? 365 compile_and_render_template(handler, template , file_path, local_assigns)335 compile_and_render_template(handler, template) 366 336 else 367 template ||= handler.read_template_file(file_path, template_extension) # Make sure that a lazyily-read template is loaded. 368 handler.render(template, local_assigns) 337 handler.render(template.source, template.locals) 369 338 end 370 339 end 371 340 … … 407 376 # Either, but not both, of template and file_path may be nil. If file_path is given, the template 408 377 # will only be read if it has to be compiled. 409 378 # 410 def compile_and_render_template(handler, template = nil, file_path = nil, local_assigns = {}) #:nodoc: 411 # convert string keys to symbols if requested 412 local_assigns = local_assigns.symbolize_keys if @@local_assigns_support_string_keys 413 379 def compile_and_render_template(handler, template) #:nodoc: 414 380 # compile the given template, if necessary 415 handler.compile_template(template , file_path, local_assigns)381 handler.compile_template(template) 416 382 417 383 # Get the method name for this template and run it 418 method_name = @@method_names[ file_path || template]384 method_name = @@method_names[template.method_key] 419 385 evaluate_assigns 420 386 421 send(method_name, local_assigns) do |*name|387 send(method_name, template.locals) do |*name| 422 388 instance_variable_get "@content_for_#{name.first || 'layout'}" 423 389 end 424 390 end -
/dev/null
old new 1 module ActionView #:nodoc: 2 class Template #:nodoc: 3 4 attr_accessor :locals 5 attr_reader :handler, :path, :source, :extension, :filename, :path_without_extension 6 7 def initialize(view, path_or_source, use_full_path, locals = {}, inline = false, inline_type = nil) 8 @view = view 9 @finder = @view.finder 10 11 unless inline 12 # Clear the forward slash at the beginning if exists 13 @path = use_full_path ? path_or_source.sub(/^\//, '') : path_or_source 14 @view.first_render ||= @path 15 @source = nil # Don't read the source until we know that it is required 16 set_extension_and_file_name(use_full_path) 17 else 18 @source = path_or_source 19 @extension = inline_type 20 end 21 @locals = locals || {} 22 end 23 24 def source 25 @source ||= File.read(self.filename) 26 end 27 28 def method_key 29 @method_key ||= (@filename || @source) 30 end 31 32 def handler 33 @handler ||= @view.class.handler_class_for_extension(@extension).new(@view) 34 end 35 36 def base_path_for_exception 37 @finder.find_base_path_for("#{@path_without_extension}.#{@extension}") || @finder.view_paths.first 38 end 39 40 private 41 42 def set_extension_and_file_name(use_full_path) 43 @path_without_extension, @extension = @finder.path_and_extension(@path) 44 if use_full_path 45 if @extension 46 @filename = @finder.pick_template(@path_without_extension, @extension) 47 else 48 @extension = @finder.pick_template_extension(@path).to_s 49 unless @extension 50 raise ActionViewError, "No template found for #{@path} in #{@finder.view_paths.inspect}" 51 end 52 @filename = @finder.pick_template(@path, @extension) 53 @extension = @extension.gsub(/^.+\./, '') # strip off any formats 54 end 55 else 56 @filename = @path 57 end 58 59 if @filename.blank? 60 raise ActionViewError, "Couldn't find template file for #{@path} in #{@finder.view_paths.inspect}" 61 end 62 end 63 64 end 65 end -
a/actionpack/lib/action_view/template_error.rb
old new 6 6 7 7 attr_reader :original_exception 8 8 9 def initialize( base_path, file_path, assigns, source, original_exception)10 @base_path , @assigns, @source, @original_exception =11 base_path, assigns.dup,source, original_exception12 @file_path = file_path9 def initialize(template, assigns, original_exception) 10 @base_path = template.base_path_for_exception 11 @assigns, @source, @original_exception = assigns.dup, template.source, original_exception 12 @file_path = template.filename 13 13 @backtrace = compute_backtrace 14 14 end 15 15 -
a/actionpack/lib/action_view/template_handler.rb
old new 30 30 # Called by CacheHelper#cache 31 31 def cache_fragment(block, name = {}, options = nil) 32 32 end 33 34 # This method reads a template file.35 def read_template_file(template_path, extension)36 File.read(template_path)37 end38 33 end 39 34 end -
a/actionpack/lib/action_view/template_handlers/compilable.rb
old new 26 26 end 27 27 28 28 # Compile and evaluate the template's code 29 def compile_template(template, file_name, local_assigns) 30 return unless compile_template?(template, file_name, local_assigns) 31 32 template ||= read_template_file(file_name, nil) 33 34 render_symbol = assign_method_name(template, file_name) 35 render_source = create_template_source(template, render_symbol, local_assigns.keys) 29 def compile_template(template) 30 return unless compile_template?(template) 31 32 render_symbol = assign_method_name(template) 33 render_source = create_template_source(template, render_symbol) 36 34 line_offset = self.template_args[render_symbol].size + self.line_offset 37 35 38 36 begin 39 file_name = 'compiled-template' if file_name.blank?37 file_name = template.filename || 'compiled-template' 40 38 ActionView::Base::CompiledTemplates.module_eval(render_source, file_name, -line_offset) 41 39 rescue Exception => e # errors from template code 42 40 if @view.logger … … 45 43 @view.logger.debug "Backtrace: #{e.backtrace.join("\n")}" 46 44 end 47 45 48 raise ActionView::TemplateError.new(@view.finder.extract_base_path_from(file_name) || 49 @view.finder.view_paths.first, file_name || template, @view.assigns, template, e) 46 raise ActionView::TemplateError.new(template, @view.assigns, e) 50 47 end 51 48 52 49 self.compile_time[render_symbol] = Time.now … … 59 56 # The template will be compiled if the inline template or file has not been compiled yet, 60 57 # if local_assigns has a new key, which isn't supported by the compiled code yet, 61 58 # or if the file has changed on disk and checking file mods hasn't been disabled. 62 def compile_template?(template , file_name, local_assigns)63 method_key = file_name || template59 def compile_template?(template) 60 method_key = template.method_key 64 61 render_symbol = @view.method_names[method_key] 65 62 66 63 compile_time = self.compile_time[render_symbol] 67 if compile_time && supports_local_assigns?(render_symbol, local_assigns)68 if file_name && !@view.cache_template_loading69 template_changed_since?( file_name, compile_time)64 if compile_time && supports_local_assigns?(render_symbol, template.locals) 65 if template.filename && !@view.cache_template_loading 66 template_changed_since?(template.filename, compile_time) 70 67 end 71 68 else 72 69 true 73 70 end 74 71 end 75 72 76 def assign_method_name(template, file_name) 77 method_key = file_name || template 78 @view.method_names[method_key] ||= compiled_method_name(template, file_name) 73 def assign_method_name(template) 74 @view.method_names[template.method_key] ||= compiled_method_name(template) 79 75 end 80 76 81 def compiled_method_name(template , file_name)82 ['_run', self.class.to_s.demodulize.underscore, compiled_method_name_file_path_segment( file_name)].compact.join('_').to_sym77 def compiled_method_name(template) 78 ['_run', self.class.to_s.demodulize.underscore, compiled_method_name_file_path_segment(template.filename)].compact.join('_').to_sym 83 79 end 84 80 85 81 def compiled_method_name_file_path_segment(file_name) … … 94 90 end 95 91 96 92 # Method to create the source code for a given template. 97 def create_template_source(template, render_symbol , locals)98 body = compile(template )93 def create_template_source(template, render_symbol) 94 body = compile(template.source) 99 95 100 96 self.template_args[render_symbol] ||= {} 101 locals_keys = self.template_args[render_symbol].keys | locals97 locals_keys = self.template_args[render_symbol].keys | template.locals.keys 102 98 self.template_args[render_symbol] = locals_keys.inject({}) { |h, k| h[k] = true; h } 103 99 104 100 locals_code = "" -
a/actionpack/test/controller/custom_handler_test.rb
old new 20 20 end 21 21 22 22 def test_custom_render 23 result = @view.render_template( "foo", "hello <%= one %>", nil, :one => "two" ) 23 template = ActionView::Template.new(@view, "hello <%= one %>", false, { :one => "two" }, true, "foo") 24 25 result = @view.render_template(template) 24 26 assert_equal( 25 27 [ "hello <%= one %>", { :one => "two" }, @view ], 26 28 result ) 27 29 end 28 30 29 31 def test_custom_render2 30 result = @view.render_template( "foo2", "hello <%= one %>", nil, :one => "two" ) 32 template = ActionView::Template.new(@view, "hello <%= one %>", false, { :one => "two" }, true, "foo2") 33 result = @view.render_template(template) 31 34 assert_equal( 32 35 [ "hello <%= one %>", { :one => "two" }, @view ], 33 36 result ) … … 35 38 36 39 def test_unhandled_extension 37 40 # uses the ERb handler by default if the extension isn't recognized 38 result = @view.render_template( "bar", "hello <%= one %>", nil, :one => "two" ) 41 template = ActionView::Template.new(@view, "hello <%= one %>", false, { :one => "two" }, true, "bar") 42 result = @view.render_template(template) 39 43 assert_equal "hello two", result 40 44 end 41 45 end -
a/actionpack/test/controller/render_test.rb
old new 140 140 :locals => { :local_name => name } 141 141 end 142 142 143 def accessing_local_assigns_in_inline_template_with_string_keys144 name = params[:local_name]145 ActionView::Base.local_assigns_support_string_keys = true146 render :inline => "<%= 'Goodbye, ' + local_name %>",147 :locals => { "local_name" => name }148 ActionView::Base.local_assigns_support_string_keys = false149 end150 151 143 def formatted_html_erb 152 144 end 153 145 … … 386 378 get :accessing_local_assigns_in_inline_template, :local_name => "Local David" 387 379 assert_equal "Goodbye, Local David", @response.body 388 380 end 389 390 def test_accessing_local_assigns_in_inline_template_with_string_keys 391 get :accessing_local_assigns_in_inline_template_with_string_keys, :local_name => "Local David" 392 assert_equal "Goodbye, Local David", @response.body 393 end 394 381 395 382 def test_render_200_should_set_etag 396 383 get :render_hello_world_from_variable 397 384 assert_equal etag_for("hello david"), @response.headers['ETag'] -
a/actionpack/test/template/compiled_templates_test.rb
old new 86 86 v = ActionView::Base.new 87 87 v.base_path = '.' 88 88 v.cache_template_loading = false 89 89 90 ta = ActionView::Template.new(v, @a, false, {}) 91 tb = ActionView::Template.new(v, @b, false, {}) 92 ts = ActionView::Template.new(v, @s, false, {}) 93 90 94 @handler_class = ActionView::Base.handler_class_for_extension(:rhtml) 91 95 @handler = @handler_class.new(v) 92 96 … … 99 103 assert @handler.send(:template_changed_since?, @b, t) 100 104 assert @handler.send(:template_changed_since?, @s, t) unless windows 101 105 102 assert @handler.send(:compile_template?, nil, @a, {})103 assert @handler.send(:compile_template?, nil, @b, {})104 assert @handler.send(:compile_template?, nil, @s, {}) unless windows106 assert @handler.send(:compile_template?, ta) 107 assert @handler.send(:compile_template?, tb) 108 assert @handler.send(:compile_template?, ts) unless windows 105 109 106 110 # All templates are rendered at t+2 107 111 Time.expects(:now).times(windows ? 2 : 3).returns(t + 2.seconds) 108 v.send(:compile_and_render_template, @handler, '', @a)109 v.send(:compile_and_render_template, @handler, '', @b)110 v.send(:compile_and_render_template, @handler, '', @s) unless windows112 v.send(:compile_and_render_template, @handler, ta) 113 v.send(:compile_and_render_template, @handler, tb) 114 v.send(:compile_and_render_template, @handler, ts) unless windows 111 115 a_n = v.method_names[@a] 112 116 b_n = v.method_names[@b] 113 117 s_n = v.method_names[@s] unless windows … … 122 126 assert !@handler.send(:template_changed_since?, @a, @handler.compile_time[a_n]) 123 127 assert !@handler.send(:template_changed_since?, @b, @handler.compile_time[b_n]) 124 128 assert !@handler.send(:template_changed_since?, @s, @handler.compile_time[s_n]) unless windows 125 assert !@handler.send(:compile_template?, nil, @a, {})126 assert !@handler.send(:compile_template?, nil, @b, {})127 assert !@handler.send(:compile_template?, nil, @s, {}) unless windows128 v.send(:compile_and_render_template, @handler, '', @a)129 v.send(:compile_and_render_template, @handler, '', @b)130 v.send(:compile_and_render_template, @handler, '', @s) unless windows129 assert !@handler.send(:compile_template?, ta) 130 assert !@handler.send(:compile_template?, tb) 131 assert !@handler.send(:compile_template?, ts) unless windows 132 v.send(:compile_and_render_template, @handler, ta) 133 v.send(:compile_and_render_template, @handler, tb) 134 v.send(:compile_and_render_template, @handler, ts) unless windows 131 135 # none of the files have changed since last compile 132 136 assert @handler.compile_time[a_n] < t + 3.seconds 133 137 assert @handler.compile_time[b_n] < t + 3.seconds … … 144 148 assert !@handler.send(:template_changed_since?, @a, @handler.compile_time[a_n]) 145 149 assert !@handler.send(:template_changed_since?, @b, @handler.compile_time[b_n]) 146 150 assert @handler.send(:template_changed_since?, @s, @handler.compile_time[s_n]) unless windows 147 assert !@handler.send(:compile_template?, nil, @a, {})148 assert !@handler.send(:compile_template?, nil, @b, {})149 assert @handler.send(:compile_template?, nil, @s, {}) unless windows151 assert !@handler.send(:compile_template?, ta) 152 assert !@handler.send(:compile_template?, tb) 153 assert @handler.send(:compile_template?, ts) unless windows 150 154 151 155 # Only the symlink template gets rendered at t+3 152 156 Time.stubs(:now).returns(t + 3.seconds) unless windows 153 v.send(:compile_and_render_template, @handler, '', @a)154 v.send(:compile_and_render_template, @handler, '', @b)155 v.send(:compile_and_render_template, @handler, '', @s) unless windows157 v.send(:compile_and_render_template, @handler, ta) 158 v.send(:compile_and_render_template, @handler, tb) 159 v.send(:compile_and_render_template, @handler, ts) unless windows 156 160 # the symlink has changed since last compile 157 161 assert @handler.compile_time[a_n] < t + 3.seconds 158 162 assert @handler.compile_time[b_n] < t + 3.seconds … … 170 174 assert !@handler.send(:template_changed_since?, @a, @handler.compile_time[a_n]) 171 175 assert @handler.send(:template_changed_since?, @b, @handler.compile_time[b_n]) 172 176 assert @handler.send(:template_changed_since?, @s, @handler.compile_time[s_n]) unless windows 173 assert !@handler.send(:compile_template?, nil, @a, {})174 assert @handler.send(:compile_template?, nil, @b, {})175 assert @handler.send(:compile_template?, nil, @s, {}) unless windows177 assert !@handler.send(:compile_template?, ta) 178 assert @handler.send(:compile_template?, tb) 179 assert @handler.send(:compile_template?, ts) unless windows 176 180 177 181 Time.expects(:now).times(windows ? 1 : 2).returns(t + 5.seconds) 178 v.send(:compile_and_render_template, @handler, '', @a)179 v.send(:compile_and_render_template, @handler, '', @b)180 v.send(:compile_and_render_template, @handler, '', @s) unless windows182 v.send(:compile_and_render_template, @handler, ta) 183 v.send(:compile_and_render_template, @handler, tb) 184 v.send(:compile_and_render_template, @handler, ts) unless windows 181 185 # the file at the end of the symlink has changed since last compile 182 186 # both the symlink and the file at the end of it should be recompiled 183 187 assert @handler.compile_time[a_n] < t + 5.seconds