diff --git a/init.rb b/init.rb index e90f5632..32424fa7 100644 --- a/init.rb +++ b/init.rb @@ -1,4 +1,3 @@ -require 'haml/engine' -require 'haml/helpers' +require 'haml/template' ActionView::Base.register_template_handler('haml', Haml::Template) \ No newline at end of file diff --git a/lib/haml/engine.rb b/lib/haml/engine.rb index f8033aa9..0356a03e 100644 --- a/lib/haml/engine.rb +++ b/lib/haml/engine.rb @@ -13,6 +13,9 @@ module Haml # puts output class Engine include Haml::Helpers + + # Allow access to the precompiled template + attr_reader :precompiled # Keeps track of the ASCII values of the characters that begin a # specially-interpreted line. @@ -60,30 +63,19 @@ module Haml @template = template #String @buffer = Haml::Buffer.new - @precompiled = String.new + @to_close_stack = [] @tabulation = 0 - @scope_object = Object.new if @scope_object.nil? + + # 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) end # Processes the template and returns the resulting (X)HTML code as # a string. - def to_html - # Process each line of the template - @template.each_with_index do |line, index| - count, line = count_soft_tabs(line) - suppress_render = handle_multiline(count, line, index) - - if !suppress_render && count && line - count, line = process_line(count, line, index) - end - end - - # Make sure an ending multiline gets closed - handle_multiline(0, nil, 0) - - # Close all the open tags - @to_close_stack.length.times { close } + def to_html(scope = Object.new) + @scope = scope # Compile the @precompiled buffer compile @@ -92,8 +84,26 @@ module Haml @buffer.buffer end - private - + private + + #Precompile each line + def do_precompile + @template.each_with_index do |line, index| + count, line = count_soft_tabs(line) + suppress_render = handle_multiline(count, line, index) + + if !suppress_render && count && line + count, line = process_line(count, line, index) + end + end + + # Make sure an ending multiline gets closed + handle_multiline(0, nil, 0) + + # Close all the open tags + @to_close_stack.length.times { close } + end + # Processes a single line of HAML. count does *not* represent the # line number; rather, it represents the tabulation count (the number of # spaces before the line divided by two). diff --git a/lib/haml/template.rb b/lib/haml/template.rb index 0f8d4536..2d873c8f 100644 --- a/lib/haml/template.rb +++ b/lib/haml/template.rb @@ -4,13 +4,15 @@ require 'action_view' module Haml class Template + def initialize(view) @view = view + @@precompiled_templates ||= {} end - def render(template, local_assigns={}) + def render(template_file_name, local_assigns={}) assigns = @view.assigns.dup - + # Do content for layout on its own to keep things working in partials if content_for_layout = @view.instance_variable_get("@content_for_layout") assigns['content_for_layout'] = content_for_layout @@ -24,23 +26,50 @@ module Haml end # Set all the local assigns local_assigns.each do |key,val| - class << self; self; end.send(:define_method, key) { val } + class << self; self; end.send(:define_method, key) &:val end end - - Haml::Engine.new(template, :scope_object => @view).to_html + + if @precompiled = get_precompiled(template_file_name) + engine = Haml::Engine.new("", :precompiled => @precompiled) + else + engine = Haml::Engine.new(File.read(template_file_name)) + set_precompiled(template_file_name, engine.precompiled) + end + + engine.to_html(@view) + + end + + 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 + + def set_precompiled(filename, precompiled) + @@precompiled_templates[filename] = [precompiled, File.mtime(filename).to_i] end end end -module ActionView - class Base - attr :haml_filename, true - - alias haml_old_render_file render_file - def render_file(template_path, use_full_path = true, local_assigns = {}) - @haml_filename = File.basename(template_path) - haml_old_render_file(template_path, use_full_path, local_assigns) +class ActionView::Base + attr :haml_filename, true + + alias_method :haml_old_render_file, :render_file + def render_file(template_path, use_full_path = true, local_assigns = {}) + @haml_filename = File.basename(template_path) + haml_old_render_file(template_path, use_full_path, local_assigns) + end + + alias_method :read_template_file_old, :read_template_file + def read_template_file(template_path, extension) + if extension =~ /haml/i + template_path + else + read_template_file_old(template_path, extension) end end end