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

No more line number mungeing - @precompiled line numbers now sync up with template line numbers.

git-svn-id: svn://hamptoncatlin.com/haml/trunk@680 7063305b-7217-0410-af8c-cdc13e5119b9
This commit is contained in:
nex3 2007-11-26 03:26:16 +00:00
parent 890521383d
commit 34619eb403
5 changed files with 51 additions and 151 deletions

View file

@ -40,7 +40,8 @@ module Haml
'preserve' => Haml::Filters::Preserve,
'redcloth' => Haml::Filters::RedCloth,
'textile' => Haml::Filters::Textile,
'markdown' => Haml::Filters::Markdown }
'markdown' => Haml::Filters::Markdown },
:filename => '(haml)'
}
@options.rec_merge! options
@ -68,9 +69,9 @@ END
@flat_spaces = -1
precompile
rescue Haml::Error => e
e.add_backtrace_entry(@index, @options[:filename])
raise e
rescue Haml::Error
$!.backtrace.unshift "#{@options[:filename]}:#{@index}"
raise
end
# Processes the template and returns the result as a string.
@ -129,11 +130,7 @@ END
@haml_is_haml = true
end
begin
eval(@precompiled, scope, '(haml-eval)')
rescue Exception => e
raise Engine.add_exception_info(e, @precompiled, @options[:filename])
end
eval(@precompiled, scope, @options[:filename], 0)
# Get rid of the current buffer
scope_object.instance_eval do
@ -174,12 +171,8 @@ END
scope = scope_object.instance_eval{binding}
end
begin
eval("Proc.new { |*_haml_locals| _haml_locals = _haml_locals[0] || {};" +
precompiled_with_ambles(local_names) + "}\n", scope, '(haml-eval)')
rescue Exception => e
raise Haml::Engine.add_exception_info(e, @precompiled, @options[:filename])
end
eval("Proc.new { |*_haml_locals| _haml_locals = _haml_locals[0] || {};" +
precompiled_with_ambles(local_names) + "}\n", scope, @options[:filename], 0)
end
# Defines a method on +object+
@ -220,11 +213,8 @@ END
def def_method(object, name, *local_names)
method = object.is_a?(Module) ? :module_eval : :instance_eval
begin
object.send(method, "def #{name}(_haml_locals = {}); #{precompiled_with_ambles(local_names)}; end", '(haml-eval)')
rescue Exception => e
raise Haml::Engine.add_exception_info(e, @precompiled, @options[:filename])
end
object.send(method, "def #{name}(_haml_locals = {}); #{precompiled_with_ambles(local_names)}; end",
@options[:filename], 0)
end
private
@ -235,21 +225,6 @@ END
eval(set_locals, scope)
end
def self.add_exception_info(e, precompiled, filename)
metaclass = class << e; self; end
metaclass.send(:include, Haml::Error)
eval_line = e.backtrace[0].scan(/:([0-9]*)/)[0][0].to_i
line_marker = precompiled.split("\n")[0...eval_line].grep(/#haml_lineno: [0-9]+/)[-1]
e.add_backtrace_entry(line_marker ? line_marker.scan(/[0-9]+/)[0].to_i : -1, filename)
# Format Ruby compiler errors nicely
message = e.message.scan(/compile error\n\(haml-eval\):[0-9]*: (.*)/)[0]
metaclass.send(:define_method, :message) { "compile error: #{message}" } if message
return e
end
# Returns a hash of options that Haml::Buffer cares about.
# This should remain loadable form #inspect.
def options_for_buffer

View file

@ -1,43 +1,13 @@
module Haml
# The abstract type of exception raised by Haml code.
# Haml::SyntaxError includes this module,
# as do all exceptions raised by Ruby code within Haml.
#
# Haml::Error encapsulates information about the exception,
# such as the line of the Haml template it was raised on
# and the Haml file that was being parsed (if applicable).
# It also provides a handy way to rescue only exceptions raised
# because of a faulty template.
module Error
# The line of the Haml template on which the exception was thrown.
attr_reader :haml_line
# The name of the file that was being parsed when the exception was raised.
# This will be nil unless Haml is being used as an ActionView plugin.
attr_reader :haml_filename
# Adds a properly formatted entry to the exception's backtrace.
# +lineno+ should be the line on which the error occurred.
# +filename+ should be the file in which the error occurred,
# if applicable (defaults to "(haml)").
def add_backtrace_entry(lineno, filename = nil) # :nodoc:
@haml_line = lineno
@haml_filename = filename
self.backtrace ||= []
self.backtrace.unshift "#{filename || '(haml)'}:#{lineno}"
end
end
class Error < StandardError; end
# SyntaxError is the type of exception raised when Haml encounters an
# ill-formatted document.
# It's not particularly interesting, except in that it includes Haml::Error.
class SyntaxError < StandardError
include Haml::Error
end
class SyntaxError < Haml::Error; end
# HamlError is the type of exception raised when Haml encounters an error
# not of a syntactical nature, such as an undefined Filter.
class HamlError < StandardError
include Haml::Error
end
class HamlError < Haml::Error; end
end

View file

@ -98,12 +98,8 @@ extend Haml::Helpers
@haml_is_haml = true
_hamlout = @haml_stack[-1]
_erbout = _hamlout.buffer
begin
END
postamble = <<END.gsub("\n", ";")
rescue Exception => e
raise Haml::Engine.add_exception_info(e, #{@precompiled.inspect}, #{@options[:filename].inspect})
end
@haml_is_haml = false
_hamlout.buffer
END
@ -132,10 +128,15 @@ END
if line.text.empty?
process_indent(old_line) unless !flat? || old_line.text.empty?
next unless flat?
unless flat?
newline
next
end
push_flat(old_line)
old_line.text, old_line.unstripped, old_line.spaces = '', '', 0
newline
next
end
@ -143,6 +144,7 @@ END
if old_line.text.nil? || suppress_render
old_line = line
newline
next
end
@ -151,6 +153,7 @@ END
if flat?
push_flat(old_line)
old_line = line
newline
next
end
@ -166,6 +169,7 @@ END
raise SyntaxError.new("Illegal Indentation: Indenting more than once per line is illegal.")
end
old_line = line
newline
end
# Close all the open tags
@ -186,8 +190,8 @@ END
# This method doesn't return anything; it simply processes the line and
# adds the appropriate code to <tt>@precompiled</tt>.
def process_line(text, index, block_opened)
@index = index + 1
@block_opened = block_opened
@index = index + 1
case text[0]
when DIV_CLASS, DIV_ID: render_div(text)
@ -200,9 +204,9 @@ END
when SILENT_SCRIPT
return start_haml_comment if text[1] == SILENT_COMMENT
mbk = mid_block_keyword?(text)
push_silent(text[1..-1], !mbk, true)
if (@block_opened && !mbk) || text[1..-1].split(' ', 2)[0] == "case"
push_silent(text[1..-1], true)
newline true
if (@block_opened && !mid_block_keyword?(text)) || text[1..-1].split(' ', 2)[0] == "case"
push_and_tabulate([:script])
end
when FILTER: start_filtered(text[1..-1].downcase)
@ -257,12 +261,10 @@ END
# Evaluates <tt>text</tt> in the context of the scope object, but
# does not output the result.
def push_silent(text, add_index = false, can_suppress = false)
def push_silent(text, can_suppress = false)
flush_merged_text
return if can_suppress && options[:suppress_eval]
@precompiled << "#haml_lineno: #{@index}\n" if add_index
@precompiled << "#{text}\n"
@precompiled << "#{text};"
end
# Adds <tt>text</tt> to <tt>@buffer</tt> with appropriate tabulation
@ -282,7 +284,7 @@ END
@precompiled << "_hamlout.push_text(#{@merged_text.dump}"
@precompiled << ", #{@tab_change}" if @tab_change != 0 || @try_one_liner
@precompiled << ")\n"
@precompiled << ");"
@merged_text = ''
@tab_change = 0
@try_one_liner = false
@ -311,8 +313,9 @@ END
flush_merged_text
return if options[:suppress_eval]
push_silent("haml_temp = #{text}", true)
out = "haml_temp = _hamlout.push_script(haml_temp, #{flattened.inspect}, #{close_tag.inspect})\n"
push_silent "haml_temp = #{text}"
newline true
out = "haml_temp = _hamlout.push_script(haml_temp, #{flattened.inspect}, #{close_tag.inspect});"
if @block_opened
push_and_tabulate([:loud, out])
else
@ -359,7 +362,7 @@ END
# Closes a Ruby block.
def close_block
push_silent "end", false, true
push_silent "end", true
@template_tabs -= 1
end
@ -373,7 +376,7 @@ END
# Closes a loud Ruby block.
def close_loud(command)
push_silent 'end', false, true
push_silent 'end', true
@precompiled << command
@template_tabs -= 1
end
@ -384,7 +387,7 @@ END
filtered = filter.new(@filter_buffer).render
if filter == Haml::Filters::Preserve
push_silent("_hamlout.buffer << #{filtered.dump} << \"\\n\"\n")
push_silent("_hamlout.buffer << #{filtered.dump} << \"\\n\";")
else
push_text(filtered.rstrip.gsub("\n", "\n#{' ' * @output_tabs}"))
end
@ -520,7 +523,7 @@ END
else
flush_merged_text
content = value.empty? || parse ? 'nil' : value.dump
push_silent "_hamlout.open_tag(#{tag_name.inspect}, #{atomic.inspect}, #{(!value.empty?).inspect}, #{attributes.inspect}, #{object_ref}, #{content}, #{attributes_hash[1...-1]})", true
push_silent "_hamlout.open_tag(#{tag_name.inspect}, #{atomic.inspect}, #{(!value.empty?).inspect}, #{attributes.inspect}, #{object_ref}, #{content}, #{attributes_hash[1...-1]})"
end
return if atomic
@ -641,7 +644,6 @@ END
spaces = line.index(/[^ ]/)
if line[spaces] == ?\t
return nil if line.strip.empty?
raise SyntaxError.new("Illegal Indentation: Only two space characters are allowed as tabulation.")
end
[spaces, spaces/2]
@ -657,5 +659,11 @@ END
def flat?
@flat_spaces != -1
end
def newline(skip_next = false)
return @skip_next_newline = false if @skip_next_newline
@skip_next_newline = true if skip_next
@precompiled << "\n"
end
end
end

View file

@ -187,82 +187,29 @@ class EngineTest < Test::Unit::TestCase
render("a\nb\n!!!\n c\nd")
rescue Haml::SyntaxError => e
assert_equal(e.message, "Illegal Nesting: Nesting within a header command is illegal.")
assert_equal(3, e.haml_line)
assert_equal(nil, e.haml_filename)
assert_equal('(haml):3', e.backtrace[0])
assert_equal("(haml):3", e.backtrace[0])
rescue Exception => e
assert(false, '"a\nb\n!!!\n c\nd" doesn\'t produce a Haml::SyntaxError')
else
assert(false, '"a\nb\n!!!\n c\nd" doesn\'t produce an exception')
end
def test_exception_type
render("%p hi\n= undefined\n= 12")
def test_exception
render("%p\n hi\n %a= undefined\n= 12")
rescue Exception => e
assert(e.is_a?(Haml::Error))
assert_equal(2, e.haml_line)
assert_equal(nil, e.haml_filename)
assert_equal('(haml):2', e.backtrace[0])
else
# Test failed... should have raised an exception
assert(false)
end
def test_def_method_exception_type
o = Object.new
Haml::Engine.new("%p hi\n= undefined\n= 12").def_method(o, :render)
o.render
rescue Exception => e
assert(e.is_a?(Haml::Error))
assert_equal(2, e.haml_line)
assert_equal(nil, e.haml_filename)
assert_equal('(haml):2', e.backtrace[0])
else
# Test failed... should have raised an exception
assert(false)
end
def test_render_proc_exception_type
Haml::Engine.new("%p hi\n= undefined\n= 12").render_proc.call
rescue Exception => e
assert(e.is_a?(Haml::Error))
assert_equal(2, e.haml_line)
assert_equal(nil, e.haml_filename)
assert_equal('(haml):2', e.backtrace[0])
assert_match("(haml):3", e.backtrace[0])
else
# Test failed... should have raised an exception
assert(false)
end
def test_compile_error
render("a\nb\n- fee do\nc")
render("a\nb\n- fee)\nc")
rescue Exception => e
assert_match(/^compile error: syntax error/, e.message)
assert_equal(3, e.haml_line)
assert_match(/^compile error\n\(haml\):3: syntax error/i, e.message)
else
assert(false,
'"a\nb\n- fee do\nc" doesn\'t produce an exception!')
end
def test_def_method_compile_error
o = Object.new
Haml::Engine.new("a\nb\n- fee do\nc").def_method(o, :render)
rescue Exception => e
assert_match(/^compile error: syntax error/, e.message)
assert_equal(3, e.haml_line)
else
assert(false,
'"a\nb\n- fee do\nc" doesn\'t produce an exception!')
end
def test_render_proc_compile_error
Haml::Engine.new("a\nb\n- fee do\nc").render_proc
rescue Exception => e
assert_match(/^compile error: syntax error/, e.message)
assert_equal(3, e.haml_line)
else
assert(false,
'"a\nb\n- fee do\nc" doesn\'t produce an exception!')
'"a\nb\n- fee)\nc" doesn\'t produce an exception!')
end
def test_unbalanced_brackets

View file

@ -145,7 +145,7 @@ class TemplateTest < Test::Unit::TestCase
render("- raise 'oops!'")
rescue Exception => e
assert_equal("oops!", e.message)
assert_equal("(haml):1", e.backtrace[0])
assert_match(/^\(haml\):1/, e.backtrace[0])
else
assert false
end
@ -165,7 +165,7 @@ END
begin
render(template.chomp)
rescue Exception => e
assert_equal("(haml):5", e.backtrace[0])
assert_match(/^\(haml\):5/, e.backtrace[0])
else
assert false
end