1
0
Fork 0
mirror of https://github.com/haml/haml.git synced 2022-11-09 12:33:31 -05:00

Move compiler into its own class

This commit is contained in:
Norman Clarke 2012-06-04 13:26:37 -03:00
parent cf6a83798a
commit eb9a366730
6 changed files with 64 additions and 56 deletions

View file

@ -1,10 +1,51 @@
require 'cgi'
module Haml
module Compiler
class Compiler
include Haml::Util
private
attr_accessor :options
def initialize(options)
@options = options
@output_tabs = 0
@to_merge = []
@precompiled = ''
end
def compile(node)
parent = instance_variable_defined?('@node') ? @node : nil
@node = node
if node.children.empty?
send(:"compile_#{node.type}")
else
send(:"compile_#{node.type}") {node.children.each {|c| compile c}}
end
ensure
@node = parent
end
if RUBY_VERSION < "1.9"
# The source code that is evaluated to produce the Haml document.
#
# In Ruby 1.9, this is automatically converted to the correct encoding
# (see {file:REFERENCE.md#encodings the `:encoding` option}).
#
# @return [String]
def precompiled
@precompiled
end
else
def precompiled
encoding = Encoding.find(@options[:encoding])
return @precompiled.force_encoding(encoding) if encoding == Encoding::BINARY
return @precompiled.encode(encoding)
end
end
def precompiled_with_return_value
precompiled + ";" + precompiled_method_return_value
end
# Returns the precompiled string with the preamble and postamble
def precompiled_with_ambles(local_names)
@ -23,6 +64,8 @@ END
preamble + locals_code(local_names) + precompiled + postamble
end
private
# Returns the string used as the return value of the precompiled method.
# This method exists so it can be monkeypatched to return modified values.
def precompiled_method_return_value
@ -260,7 +303,7 @@ END
# does not output the result.
def push_silent(text, can_suppress = false)
flush_merged_text
return if can_suppress && options[:suppress_eval]
return if can_suppress && @options.suppress_eval?
@precompiled << "#{resolve_newlines}#{text}\n"
@output_line += text.count("\n") + 1
end
@ -321,7 +364,7 @@ END
# If `opts[:preserve_script]` is true, Haml::Helpers#find_and_flatten is run on
# the result before it is added to `@buffer`
def push_script(text, opts = {})
return if options[:suppress_eval]
return if @options.suppress_eval?
args = %w[preserve_script in_tag preserve_tag escape_html nuke_inner_whitespace]
args.map! {|name| opts[name.to_sym]}
@ -479,17 +522,5 @@ END
raise SyntaxError.new("[HAML BUG] Undefined entry in Haml::Compiler@to_merge.")
end
end
def compile(node)
parent = instance_variable_defined?('@node') ? @node : nil
@node = node
if node.children.empty?
send(:"compile_#{node.type}")
else
send(:"compile_#{node.type}") {node.children.each {|c| compile c}}
end
ensure
@node = parent
end
end
end

View file

@ -17,7 +17,7 @@ module Haml
# output = haml_engine.render
# puts output
class Engine
include Compiler
include Haml::Util
# The Haml::Options instance.
# See {file:REFERENCE.md#options the Haml options documentation}.
@ -32,23 +32,8 @@ module Haml
# @return [String]
attr_accessor :indentation
if RUBY_VERSION < "1.9"
# The source code that is evaluated to produce the Haml document.
#
# In Ruby 1.9, this is automatically converted to the correct encoding
# (see {file:REFERENCE.md#encodings the `:encoding` option}).
#
# @return [String]
def precompiled
@precompiled
end
else
def precompiled
encoding = Encoding.find(@options[:encoding])
return @precompiled.force_encoding(encoding) if encoding == Encoding::BINARY
return @precompiled.encode(encoding)
end
end
attr_accessor :compiler
attr_accessor :parser
# Precompiles the Haml template.
@ -58,7 +43,6 @@ module Haml
# see {file:REFERENCE.md#options the Haml options documentation}
# @raise [Haml::Error] if there's a Haml syntax error in the template
def initialize(template, options = {})
@index = nil # explicitily initialize to avoid warnings
@options = Options.new(options)
@template = check_haml_encoding(template) do |msg, line|
@ -67,20 +51,10 @@ module Haml
initialize_encoding options[:encoding]
@index = 0
@parser = Parser.new(@template, @options)
@compiler = Compiler.new(@options)
@parser = Parser.new(@template, @options)
@output_tabs = 0
@to_merge = []
@precompiled = ''
compile(@parser.parse)
rescue Haml::Error => e
if @index || e.line
e.backtrace.unshift "#{@options[:filename]}:#{(e.line ? e.line + 1 : @index) + @options[:line] - 1}"
end
raise
@compiler.compile(@parser.parse)
end
# Processes the template and returns the result as a string.
@ -143,8 +117,7 @@ module Haml
@haml_buffer = buffer
end
eval(precompiled + ";" + precompiled_method_return_value,
scope, @options[:filename], @options[:line])
eval(@compiler.precompiled_with_return_value, scope, @options[:filename], @options[:line])
ensure
# Get rid of the current buffer
scope_object.instance_eval do
@ -186,7 +159,7 @@ module Haml
end
eval("Proc.new { |*_haml_locals| _haml_locals = _haml_locals[0] || {};" +
precompiled_with_ambles(local_names) + "}\n", scope, @options[:filename], @options[:line])
compiler.precompiled_with_ambles(local_names) + "}\n", scope, @options[:filename], @options[:line])
end
# Defines a method on `object` with the given name
@ -230,7 +203,7 @@ module Haml
def def_method(object, name, *local_names)
method = object.is_a?(Module) ? :module_eval : :instance_eval
object.send(method, "def #{name}(_haml_locals = {}); #{precompiled_with_ambles(local_names)}; end",
object.send(method, "def #{name}(_haml_locals = {}); #{compiler.precompiled_with_ambles(local_names)}; end",
@options[:filename], @options[:line])
end

View file

@ -80,6 +80,7 @@ module Haml
@template = (template.rstrip).split(/\r\n|\r|\n/) + [:eod, :eod]
@options = options
@flat = false
@index = 0
@template_index = 0
@template_tabs = 0
end
@ -120,6 +121,9 @@ module Haml
# Close all the open tags
close until @parent.type == :root
@root
rescue Haml::Error => e
e.backtrace.unshift "#{@options[:filename]}:#{(e.line ? e.line + 1 : @index) + @options[:line] - 1}"
raise
end

View file

@ -5,7 +5,7 @@ require 'haml/helpers/action_view_extensions'
require 'haml/helpers/xss_mods'
module Haml
module Compiler
class Compiler
def precompiled_method_return_value_with_haml_xss
"::Haml::Util.html_safe(#{precompiled_method_return_value_without_haml_xss})"
end

View file

@ -18,7 +18,7 @@ module Haml
options = Haml::Template.options.dup
options[:mime_type] = template.mime_type if template.respond_to? :mime_type
options[:filename] = template.identifier
Haml::Engine.new(template.source, options).send(:precompiled_with_ambles, [])
Haml::Engine.new(template.source, options).compiler.precompiled_with_ambles([])
end
# In Rails 3.1+, #call takes the place of #compile

View file

@ -41,9 +41,9 @@ class FiltersTest < MiniTest::Unit::TestCase
test "should pass options to Tilt filters that precompile" do
haml = ":erb\n <%= 'foo' %>"
refute_match('TEST_VAR', Haml::Engine.new(haml).precompiled)
refute_match('TEST_VAR', Haml::Engine.new(haml).compiler.precompiled)
Haml::Filters::Erb.options = {:outvar => 'TEST_VAR'}
assert_match('TEST_VAR', Haml::Engine.new(haml).precompiled)
assert_match('TEST_VAR', Haml::Engine.new(haml).compiler.precompiled)
end
test "should pass options to Tilt filters that don't precompile" do