From 3736c8b7e97b9eca91a92c3f27e92e5c63d823fa Mon Sep 17 00:00:00 2001 From: nex3 Date: Mon, 7 May 2007 08:17:16 +0000 Subject: [PATCH] Super speed boost! Like, I'm talking ZOOM! The patch was written by Tom Bagby and modified by myself to make it a bit leaner. The basic idea is that instead of caching the compiled template as a string of Ruby code, we cache it as a compiled method. This means that caching doesn't have to be done Template-side, which also means the :precompiled option now doesn't do anything. I don't think anyone used it anyway, though, so we're all good. git-svn-id: svn://hamptoncatlin.com/haml/trunk@504 7063305b-7217-0410-af8c-cdc13e5119b9 --- lib/haml.rb | 4 ---- lib/haml/engine.rb | 48 +++++++++++++++++++++++++++++++++------- lib/haml/template.rb | 27 +--------------------- test/haml/engine_test.rb | 17 -------------- 4 files changed, 41 insertions(+), 55 deletions(-) diff --git a/lib/haml.rb b/lib/haml.rb index 13d09e16..f2d1db26 100644 --- a/lib/haml.rb +++ b/lib/haml.rb @@ -635,10 +635,6 @@ $LOAD_PATH << dir unless $LOAD_PATH.include?(dir) # evaluated. If this is true, said scripts are # rendered as empty strings. Defaults to false. # -# [:precompiled] A string containing a precompiled Haml template. -# If this is passed, template is ignored -# and no precompilation is done. -# # [:attr_wrapper] The character that should wrap element attributes. # This defaults to ' (an apostrophe). Characters # of this type within the attributes will be escaped diff --git a/lib/haml/engine.rb b/lib/haml/engine.rb index e00536c7..b8b40938 100644 --- a/lib/haml/engine.rb +++ b/lib/haml/engine.rb @@ -151,8 +151,6 @@ END end @options[:filters].rec_merge! options[:filters] if options[:filters] - @precompiled = @options[:precompiled] - @template = template.strip #String @to_close_stack = [] @output_tabs = 0 @@ -166,7 +164,7 @@ END begin # Only do the first round of pre-compiling if we really need to. # They might be passing in the precompiled string. - do_precompile if @precompiled.nil? && (@precompiled = String.new) + do_precompile unless @@method_names[@template] rescue Haml::Error => e e.add_backtrace_entry(@index, @options[:filename]) raise e @@ -185,6 +183,12 @@ END # Compile the @precompiled buffer compile &block + if @buffer.buffer.empty? + if @options[:filename] + raise @template.inspect + end + end + # Return the result string @buffer.buffer end @@ -192,11 +196,13 @@ END alias_method :to_html, :render private - + #Precompile each line def do_precompile + @precompiled = '' + method_name = assign_method_name(@template, options[:filename]) push_silent <<-END - def _haml_render + def #{method_name} @haml_is_haml = true _hamlout = @haml_stack[-1] _erbout = _hamlout.buffer @@ -368,6 +374,22 @@ END def is_multiline?(line) # ' '[0] == 32 line && line.length > 1 && line[-1] == MULTILINE_CHAR_VALUE && line[-2] == 32 end + + # Method for generating compiled method names basically ripped out of ActiveView::Base + # If Haml is to be used as a standalone module without rails and still use the precompiled + # methods technique, it will end up duplicating this stuff. I can't decide whether + # checking compile times to decide whether to recompile a template belongs in here or + # out in template.rb + @@method_names = {} + @@render_method_count = 0 + def assign_method_name(template, file_name) + @@render_method_count += 1 + @@method_names[template] = "_render_haml_#{@@render_method_count}".intern + end + + module CompiledTemplates + # holds compiled template code + end # Takes @precompiled, a string buffer of Ruby code, and # evaluates it in the context of @scope_object, after preparing @@ -385,11 +407,21 @@ END attr :haml_lineno # :nodoc: end end + @scope_object.class.instance_eval do + include CompiledTemplates + end begin - # Evaluate the buffer in the context of the scope object - @scope_object.instance_eval @precompiled - @scope_object._haml_render &block + if false#options[:filename] + method_name = @@method_names[options[:filename]] + else + method_name = @@method_names[@template] + end + + unless @scope_object.respond_to?(method_name) + CompiledTemplates.module_eval @precompiled + end + @scope_object.send(method_name, &block) rescue Exception => e class << e include Haml::Error diff --git a/lib/haml/template.rb b/lib/haml/template.rb index b1cf482b..6ad7d653 100644 --- a/lib/haml/template.rb +++ b/lib/haml/template.rb @@ -40,7 +40,6 @@ module Haml # to render its templates. def initialize(view) @view = view - @@precompiled_templates ||= {} end # Renders the file at the location template, @@ -60,13 +59,7 @@ module Haml engine = Haml::Engine.new(template, options) else options[:filename] ||= template - if @precompiled = get_precompiled(template) - options[:precompiled] ||= @precompiled - engine = Haml::Engine.new("", options) - else - engine = Haml::Engine.new(File.read(template), options) - set_precompiled(template, engine.precompiled) - end + engine = Haml::Engine.new(File.read(template), options) end yield_proc = @view.instance_eval do @@ -76,24 +69,6 @@ module Haml engine.to_html(@view) { |*args| yield_proc.call(*args) } end - - private - - # Gets the cached, precompiled version of the template at location filename - # as a string. - def get_precompiled(filename) - # Do we have it on file? Is it new enough? - if (precompiled, precompiled_on = @@precompiled_templates[filename]) && - (precompiled_on == File.mtime(filename).to_i) - precompiled - end - end - - # Sets the cached, precompiled version of the template at location filename - # to precompiled. - def set_precompiled(filename, precompiled) - @@precompiled_templates[filename] = [precompiled, File.mtime(filename).to_i] - end end end diff --git a/test/haml/engine_test.rb b/test/haml/engine_test.rb index 33bb0182..5b6d2078 100644 --- a/test/haml/engine_test.rb +++ b/test/haml/engine_test.rb @@ -80,23 +80,6 @@ class EngineTest < Test::Unit::TestCase def test_locals assert_equal("

Paragraph!

\n", render("%p= text", :locals => { :text => "Paragraph!" })) end - - def test_precompiled - precompiled = <<-END - def _haml_render - _hamlout = @haml_stack[-1] - _erbout = _hamlout.buffer - - _hamlout.open_tag("p", 0, nil, true, "", nil, nil, false) - @haml_lineno = 1 - haml_temp = "Haml Rocks Socks" - haml_temp = _hamlout.push_script(haml_temp, 1, false) - _hamlout.close_tag("p", 0) - end - END - - assert_equal("

Haml Rocks Socks

\n", render("%h1 I shall not be rendered", :precompiled => precompiled)) - end def test_comps assert_equal(-1, "foo" <=> nil)