From e6de95889dd361359bcd885c9f38087f14f57628 Mon Sep 17 00:00:00 2001 From: Michael Koziarski Date: Fri, 11 Jan 2008 04:45:06 +0000 Subject: [PATCH] * Pass around handler instances, not their classes [Koz] * Move compilation, rendering and 'compilable?' checks into the Handlers [Koz] * Remove delegate_* methods as the handler is now an instance [Koz] git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@8624 5ecf4fe2-1ee6-0310-87b1-e25e094e27de --- actionpack/lib/action_view/base.rb | 24 +- .../lib/action_view/template_handler.rb | 12 + .../action_view/template_handlers/builder.rb | 4 + .../lib/action_view/template_handlers/erb.rb | 4 + .../lib/action_view/template_handlers/rjs.rb | 4 + .../test/controller/custom_handler_test.rb | 2 +- actionpack/test/controller/layout_test.rb | 3 +- .../test/template/compiled_templates_test.rb | 217 +++++++++--------- 8 files changed, 142 insertions(+), 128 deletions(-) diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index 6fde9ccf73..34572e442d 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -252,7 +252,7 @@ def self.register_default_template_handler(extension, klass) @@default_template_handlers = klass end - def self.handler_for_extension(extension) + def self.handler_class_for_extension(extension) (extension && @@template_handlers[extension.to_sym]) || @@default_template_handlers end @@ -361,13 +361,13 @@ def render(options = {}, old_local_assigns = {}, &block) #:nodoc: # Renders the +template+ which is given as a string as either erb or builder depending on template_extension. # The hash in local_assigns is made available as local variables. def render_template(template_extension, template, file_path = nil, local_assigns = {}) #:nodoc: - handler = self.class.handler_for_extension(template_extension) + handler = self.class.handler_class_for_extension(template_extension).new(self) - if template_handler_is_compilable?(handler) + if handler.compilable? compile_and_render_template(handler, template, file_path, local_assigns) else template ||= read_template_file(file_path, template_extension) # Make sure that a lazyily-read template is loaded. - delegate_render(handler, template, local_assigns) + handler.render(template, local_assigns) end end @@ -513,18 +513,6 @@ def evaluate_assigns end end - def delegate_render(handler, template, local_assigns) - handler.new(self).render(template, local_assigns) - end - - def delegate_compile(handler, template) - handler.new(self).compile(template) - end - - def template_handler_is_compilable?(handler) - handler.new(self).respond_to?(:compile) - end - # Assigns instance variables from the controller to the view. def assign_variables_from_controller @assigns.each { |key, value| instance_variable_set("@#{key}", value) } @@ -565,7 +553,7 @@ def template_changed_since?(file_name, compile_time) # Method to create the source code for a given template. def create_template_source(handler, template, render_symbol, locals) - body = delegate_compile(handler, template) + body = handler.compile(template) @@template_args[render_symbol] ||= {} locals_keys = @@template_args[render_symbol].keys | locals @@ -585,7 +573,7 @@ def assign_method_name(handler, template, file_name) end def compiled_method_name(handler, template, file_name) - ['_run', handler.to_s.demodulize.underscore, compiled_method_name_file_path_segment(file_name)].compact.join('_').to_sym + ['_run', handler.class.to_s.demodulize.underscore, compiled_method_name_file_path_segment(file_name)].compact.join('_').to_sym end def compiled_method_name_file_path_segment(file_name) diff --git a/actionpack/lib/action_view/template_handler.rb b/actionpack/lib/action_view/template_handler.rb index 8ce31ade49..b2c6ff3e36 100644 --- a/actionpack/lib/action_view/template_handler.rb +++ b/actionpack/lib/action_view/template_handler.rb @@ -4,6 +4,10 @@ def self.line_offset 0 end + def self.compilable? + false + end + def initialize(view) @view = view end @@ -14,6 +18,14 @@ def render(template, local_assigns) def compile(template) end + def compilable? + self.class.compilable? + end + + def line_offset + self.class.line_offset + end + # Called by CacheHelper#cache def cache_fragment(block, name = {}, options = nil) end diff --git a/actionpack/lib/action_view/template_handlers/builder.rb b/actionpack/lib/action_view/template_handlers/builder.rb index 88044917dd..098c90f5c7 100644 --- a/actionpack/lib/action_view/template_handlers/builder.rb +++ b/actionpack/lib/action_view/template_handlers/builder.rb @@ -7,6 +7,10 @@ def self.line_offset 2 end + def self.compilable? + true + end + def compile(template) content_type_handler = (@view.send!(:controller).respond_to?(:response) ? "controller.response" : "controller") "#{content_type_handler}.content_type ||= Mime::XML\n" + diff --git a/actionpack/lib/action_view/template_handlers/erb.rb b/actionpack/lib/action_view/template_handlers/erb.rb index 26cca586ba..ffc1ab0e97 100644 --- a/actionpack/lib/action_view/template_handlers/erb.rb +++ b/actionpack/lib/action_view/template_handlers/erb.rb @@ -26,6 +26,10 @@ def compile(template) ::ERB.new(template, nil, @view.erb_trim_mode).src end + def self.compilable? + true + end + def cache_fragment(block, name = {}, options = nil) #:nodoc: @view.fragment_for(block, name, options) do eval(ActionView::Base.erb_variable, block.binding) diff --git a/actionpack/lib/action_view/template_handlers/rjs.rb b/actionpack/lib/action_view/template_handlers/rjs.rb index bd51cc4d39..e4b3d0c2a6 100644 --- a/actionpack/lib/action_view/template_handlers/rjs.rb +++ b/actionpack/lib/action_view/template_handlers/rjs.rb @@ -10,6 +10,10 @@ def compile(template) "update_page do |page|\n#{template}\nend" end + def self.compilable? + true + end + def cache_fragment(block, name = {}, options = nil) #:nodoc: @view.fragment_for(block, name, options) do begin diff --git a/actionpack/test/controller/custom_handler_test.rb b/actionpack/test/controller/custom_handler_test.rb index 672ffeeaf8..f3f2625daa 100644 --- a/actionpack/test/controller/custom_handler_test.rb +++ b/actionpack/test/controller/custom_handler_test.rb @@ -1,6 +1,6 @@ require 'abstract_unit' -class CustomHandler +class CustomHandler < ActionView::TemplateHandler def initialize( view ) @view = view end diff --git a/actionpack/test/controller/layout_test.rb b/actionpack/test/controller/layout_test.rb index 1a2134847e..11ad4a20af 100644 --- a/actionpack/test/controller/layout_test.rb +++ b/actionpack/test/controller/layout_test.rb @@ -31,7 +31,7 @@ class ControllerNameSpace::NestedController < LayoutTest class MultipleExtensions < LayoutTest end -class MabView +class MabView < ActionView::TemplateHandler def initialize(view) end @@ -67,6 +67,7 @@ def test_third_party_template_library_auto_discovers_layout get :hello assert_equal 'layouts/third_party_template_library', @controller.active_layout assert_equal 'layouts/third_party_template_library', @response.layout + assert_response :success assert_equal 'Mab', @response.body end diff --git a/actionpack/test/template/compiled_templates_test.rb b/actionpack/test/template/compiled_templates_test.rb index 7c8d931b33..4998eb198c 100644 --- a/actionpack/test/template/compiled_templates_test.rb +++ b/actionpack/test/template/compiled_templates_test.rb @@ -73,115 +73,116 @@ def test_mtime end uses_mocha 'test_compile_time' do - def test_compile_time - t = Time.now - - File.open(@a, "w"){|f| f.puts @a} - File.open(@b, "w"){|f| f.puts @b} - # windows doesn't support symlinks (even under cygwin) - windows = (RUBY_PLATFORM =~ /win32/) - `ln -s #{@a} #{@s}` unless windows - - v = ActionView::Base.new - v.base_path = '.' - v.cache_template_loading = false - - # All templates were created at t+1 - File::Stat.any_instance.expects(:mtime).times(windows ? 2 : 3).returns(t + 1.second) - - # private methods template_changed_since? and compile_template? - # should report true for all since they have not been compiled - assert v.send(:template_changed_since?, @a, t) - assert v.send(:template_changed_since?, @b, t) - assert v.send(:template_changed_since?, @s, t) unless windows - - assert v.send(:compile_template?, nil, @a, {}) - assert v.send(:compile_template?, nil, @b, {}) - assert v.send(:compile_template?, nil, @s, {}) unless windows - - @handler = ActionView::Base.handler_for_extension(:rhtml) - - # All templates are rendered at t+2 - Time.expects(:now).times(windows ? 2 : 3).returns(t + 2.seconds) - v.send(:compile_and_render_template, @handler, '', @a) - v.send(:compile_and_render_template, @handler, '', @b) - v.send(:compile_and_render_template, @handler, '', @s) unless windows - a_n = v.method_names[@a] - b_n = v.method_names[@b] - s_n = v.method_names[@s] unless windows - # all of the files have changed since last compile - assert v.compile_time[a_n] > t - assert v.compile_time[b_n] > t - assert v.compile_time[s_n] > t unless windows - - # private methods template_changed_since? and compile_template? - # should report false for all since none have changed since compile - File::Stat.any_instance.expects(:mtime).times(windows ? 6 : 12).returns(t + 1.second) - assert !v.send(:template_changed_since?, @a, v.compile_time[a_n]) - assert !v.send(:template_changed_since?, @b, v.compile_time[b_n]) - assert !v.send(:template_changed_since?, @s, v.compile_time[s_n]) unless windows - assert !v.send(:compile_template?, nil, @a, {}) - assert !v.send(:compile_template?, nil, @b, {}) - assert !v.send(:compile_template?, nil, @s, {}) unless windows - v.send(:compile_and_render_template, @handler, '', @a) - v.send(:compile_and_render_template, @handler, '', @b) - v.send(:compile_and_render_template, @handler, '', @s) unless windows - # none of the files have changed since last compile - assert v.compile_time[a_n] < t + 3.seconds - assert v.compile_time[b_n] < t + 3.seconds - assert v.compile_time[s_n] < t + 3.seconds unless windows - - `rm #{@s}; ln -s #{@b} #{@s}` unless windows - # private methods template_changed_since? and compile_template? - # should report true for symlink since it has changed since compile + + def test_compile_time + t = Time.now + + File.open(@a, "w"){|f| f.puts @a} + File.open(@b, "w"){|f| f.puts @b} + # windows doesn't support symlinks (even under cygwin) + windows = (RUBY_PLATFORM =~ /win32/) + `ln -s #{@a} #{@s}` unless windows + + v = ActionView::Base.new + v.base_path = '.' + v.cache_template_loading = false + + # All templates were created at t+1 + File::Stat.any_instance.expects(:mtime).times(windows ? 2 : 3).returns(t + 1.second) + + # private methods template_changed_since? and compile_template? + # should report true for all since they have not been compiled + assert v.send(:template_changed_since?, @a, t) + assert v.send(:template_changed_since?, @b, t) + assert v.send(:template_changed_since?, @s, t) unless windows + + assert v.send(:compile_template?, nil, @a, {}) + assert v.send(:compile_template?, nil, @b, {}) + assert v.send(:compile_template?, nil, @s, {}) unless windows + + @handler_class = ActionView::Base.handler_class_for_extension(:rhtml) + @handler = @handler_class.new(v) + # All templates are rendered at t+2 + Time.expects(:now).times(windows ? 2 : 3).returns(t + 2.seconds) + v.send(:compile_and_render_template, @handler, '', @a) + v.send(:compile_and_render_template, @handler, '', @b) + v.send(:compile_and_render_template, @handler, '', @s) unless windows + a_n = v.method_names[@a] + b_n = v.method_names[@b] + s_n = v.method_names[@s] unless windows + # all of the files have changed since last compile + assert v.compile_time[a_n] > t + assert v.compile_time[b_n] > t + assert v.compile_time[s_n] > t unless windows + + # private methods template_changed_since? and compile_template? + # should report false for all since none have changed since compile + File::Stat.any_instance.expects(:mtime).times(windows ? 6 : 12).returns(t + 1.second) + assert !v.send(:template_changed_since?, @a, v.compile_time[a_n]) + assert !v.send(:template_changed_since?, @b, v.compile_time[b_n]) + assert !v.send(:template_changed_since?, @s, v.compile_time[s_n]) unless windows + assert !v.send(:compile_template?, nil, @a, {}) + assert !v.send(:compile_template?, nil, @b, {}) + assert !v.send(:compile_template?, nil, @s, {}) unless windows + v.send(:compile_and_render_template, @handler, '', @a) + v.send(:compile_and_render_template, @handler, '', @b) + v.send(:compile_and_render_template, @handler, '', @s) unless windows + # none of the files have changed since last compile + assert v.compile_time[a_n] < t + 3.seconds + assert v.compile_time[b_n] < t + 3.seconds + assert v.compile_time[s_n] < t + 3.seconds unless windows + + `rm #{@s}; ln -s #{@b} #{@s}` unless windows + # private methods template_changed_since? and compile_template? + # should report true for symlink since it has changed since compile - # t + 3.seconds is for the symlink - File::Stat.any_instance.expects(:mtime).times(windows ? 6 : 9).returns( - *(windows ? [ t + 1.second, t + 1.second ] : - [ t + 1.second, t + 1.second, t + 3.second ]) * 3) - assert !v.send(:template_changed_since?, @a, v.compile_time[a_n]) - assert !v.send(:template_changed_since?, @b, v.compile_time[b_n]) - assert v.send(:template_changed_since?, @s, v.compile_time[s_n]) unless windows - assert !v.send(:compile_template?, nil, @a, {}) - assert !v.send(:compile_template?, nil, @b, {}) - assert v.send(:compile_template?, nil, @s, {}) unless windows - - # Only the symlink template gets rendered at t+3 - Time.stubs(:now).returns(t + 3.seconds) unless windows - v.send(:compile_and_render_template, @handler, '', @a) - v.send(:compile_and_render_template, @handler, '', @b) - v.send(:compile_and_render_template, @handler, '', @s) unless windows - # the symlink has changed since last compile - assert v.compile_time[a_n] < t + 3.seconds - assert v.compile_time[b_n] < t + 3.seconds - assert_equal v.compile_time[s_n], t + 3.seconds unless windows - - FileUtils.touch @b - # private methods template_changed_since? and compile_template? - # should report true for symlink and file at end of symlink - # since it has changed since last compile - # - # t+4 is for @b and also for the file that @s points to, which is @b - File::Stat.any_instance.expects(:mtime).times(windows ? 6 : 12).returns( - *(windows ? [ t + 1.second, t + 4.seconds ] : - [ t + 1.second, t + 4.seconds, t + 3.second, t + 4.seconds ]) * 3) - assert !v.send(:template_changed_since?, @a, v.compile_time[a_n]) - assert v.send(:template_changed_since?, @b, v.compile_time[b_n]) - assert v.send(:template_changed_since?, @s, v.compile_time[s_n]) unless windows - assert !v.send(:compile_template?, nil, @a, {}) - assert v.send(:compile_template?, nil, @b, {}) - assert v.send(:compile_template?, nil, @s, {}) unless windows - - Time.expects(:now).times(windows ? 1 : 2).returns(t + 5.seconds) - v.send(:compile_and_render_template, @handler, '', @a) - v.send(:compile_and_render_template, @handler, '', @b) - v.send(:compile_and_render_template, @handler, '', @s) unless windows - # the file at the end of the symlink has changed since last compile - # both the symlink and the file at the end of it should be recompiled - assert v.compile_time[a_n] < t + 5.seconds - assert_equal v.compile_time[b_n], t + 5.seconds - assert_equal v.compile_time[s_n], t + 5.seconds unless windows - end + # t + 3.seconds is for the symlink + File::Stat.any_instance.expects(:mtime).times(windows ? 6 : 9).returns( + *(windows ? [ t + 1.second, t + 1.second ] : + [ t + 1.second, t + 1.second, t + 3.second ]) * 3) + assert !v.send(:template_changed_since?, @a, v.compile_time[a_n]) + assert !v.send(:template_changed_since?, @b, v.compile_time[b_n]) + assert v.send(:template_changed_since?, @s, v.compile_time[s_n]) unless windows + assert !v.send(:compile_template?, nil, @a, {}) + assert !v.send(:compile_template?, nil, @b, {}) + assert v.send(:compile_template?, nil, @s, {}) unless windows + + # Only the symlink template gets rendered at t+3 + Time.stubs(:now).returns(t + 3.seconds) unless windows + v.send(:compile_and_render_template, @handler, '', @a) + v.send(:compile_and_render_template, @handler, '', @b) + v.send(:compile_and_render_template, @handler, '', @s) unless windows + # the symlink has changed since last compile + assert v.compile_time[a_n] < t + 3.seconds + assert v.compile_time[b_n] < t + 3.seconds + assert_equal v.compile_time[s_n], t + 3.seconds unless windows + + FileUtils.touch @b + # private methods template_changed_since? and compile_template? + # should report true for symlink and file at end of symlink + # since it has changed since last compile + # + # t+4 is for @b and also for the file that @s points to, which is @b + File::Stat.any_instance.expects(:mtime).times(windows ? 6 : 12).returns( + *(windows ? [ t + 1.second, t + 4.seconds ] : + [ t + 1.second, t + 4.seconds, t + 3.second, t + 4.seconds ]) * 3) + assert !v.send(:template_changed_since?, @a, v.compile_time[a_n]) + assert v.send(:template_changed_since?, @b, v.compile_time[b_n]) + assert v.send(:template_changed_since?, @s, v.compile_time[s_n]) unless windows + assert !v.send(:compile_template?, nil, @a, {}) + assert v.send(:compile_template?, nil, @b, {}) + assert v.send(:compile_template?, nil, @s, {}) unless windows + + Time.expects(:now).times(windows ? 1 : 2).returns(t + 5.seconds) + v.send(:compile_and_render_template, @handler, '', @a) + v.send(:compile_and_render_template, @handler, '', @b) + v.send(:compile_and_render_template, @handler, '', @s) unless windows + # the file at the end of the symlink has changed since last compile + # both the symlink and the file at the end of it should be recompiled + assert v.compile_time[a_n] < t + 5.seconds + assert_equal v.compile_time[b_n], t + 5.seconds + assert_equal v.compile_time[s_n], t + 5.seconds unless windows + end end end -- GitLab