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
This commit is contained in:
nex3 2007-05-07 08:17:16 +00:00
parent 568051434c
commit 3736c8b7e9
4 changed files with 41 additions and 55 deletions

View File

@ -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.
#
# [<tt>:precompiled</tt>] A string containing a precompiled Haml template.
# If this is passed, <tt>template</tt> is ignored
# and no precompilation is done.
#
# [<tt>:attr_wrapper</tt>] The character that should wrap element attributes.
# This defaults to <tt>'</tt> (an apostrophe). Characters
# of this type within the attributes will be escaped

View File

@ -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 <tt>@precompiled</tt>, a string buffer of Ruby code, and
# evaluates it in the context of <tt>@scope_object</tt>, 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

View File

@ -40,7 +40,6 @@ module Haml
# to render its templates.
def initialize(view)
@view = view
@@precompiled_templates ||= {}
end
# Renders the file at the location <tt>template</tt>,
@ -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 <tt>filename</tt>
# 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 <tt>filename</tt>
# to <tt>precompiled</tt>.
def set_precompiled(filename, precompiled)
@@precompiled_templates[filename] = [precompiled, File.mtime(filename).to_i]
end
end
end

View File

@ -80,23 +80,6 @@ class EngineTest < Test::Unit::TestCase
def test_locals
assert_equal("<p>Paragraph!</p>\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("<p>Haml Rocks Socks</p>\n", render("%h1 I shall not be rendered", :precompiled => precompiled))
end
def test_comps
assert_equal(-1, "foo" <=> nil)