Show XML parsing errors when using IO as input.

Previously this wouldn't display anything due to the IO object being exhausted.
To fix this the input has to be wound back to the start, which means re-reading
it. Sadly I can't think of a way around this that doesn't require buffering
lines while parsing them (which massively increases memory usage).
This commit is contained in:
Yorick Peterse 2014-09-03 22:52:59 +02:00
parent d67f43508d
commit dc5874f5aa
2 changed files with 39 additions and 21 deletions

View File

@ -228,31 +228,35 @@ end
# @raise [Racc::ParseError] # @raise [Racc::ParseError]
# #
def on_error(type, value, stack) def on_error(type, value, stack)
name = token_to_str(type) name = token_to_str(type)
index = @line - 1 index = @line - 1
lines = @data.each_line.to_a index_range = (index - 5)..(index + 5)
code = '' code = ''
# For IO we sadly have to re-read the input :<
if @data.respond_to?(:rewind)
@data.rewind
end
# Show up to 5 lines before and after the offending line (if they exist). # Show up to 5 lines before and after the offending line (if they exist).
(-5..5).each do |offset| @data.each_line.with_index do |line, line_index|
line = lines[index + offset] next unless index_range.cover?(line_index)
number = @line + offset
if line and number > 0 number = line_index + 1
if offset == 0
prefix = '=> '
else
prefix = ' '
end
line = line.strip if line_index == index
prefix = '=> '
if line.length > 80 else
line = line[0..79] + ' (more)' prefix = ' '
end
code << "#{prefix}#{number}: #{line}\n"
end end
line = line.strip
if line.length > 80
line = line[0..79] + ' (more)'
end
code << "#{prefix}#{number}: #{line}\n"
end end
raise Racc::ParseError, <<-EOF.strip raise Racc::ParseError, <<-EOF.strip

View File

@ -16,7 +16,7 @@ describe Oga::XML::Parser do
expect { parse(@invalid_xml) }.to raise_error(Racc::ParseError) expect { parse(@invalid_xml) }.to raise_error(Racc::ParseError)
end end
example 'display a more meaningful error message' do example 'include the offending input when using String as input' do
# Racc basically reports errors at the last moment instead of where they # Racc basically reports errors at the last moment instead of where they
# *actually* occur. # *actually* occur.
partial = <<-EOF.strip partial = <<-EOF.strip
@ -29,5 +29,19 @@ describe Oga::XML::Parser do
parse_error(@invalid_xml).should =~ /#{partial}/ parse_error(@invalid_xml).should =~ /#{partial}/
end end
example 'include the offending input when using IO as input' do
# Racc basically reports errors at the last moment instead of where they
# *actually* occur.
partial = <<-EOF.strip
1. <person>
2. <name>Alice</name>
3. <age>25
4. <nationality>Dutch</nationality>
=> 5. </person>
EOF
parse_error(StringIO.new(@invalid_xml)).should =~ /#{partial}/
end
end end
end end