diff --git a/lib/power_assert/parser.rb b/lib/power_assert/parser.rb index 06bab95..1a982a5 100644 --- a/lib/power_assert/parser.rb +++ b/lib/power_assert/parser.rb @@ -8,9 +8,14 @@ class Parser def initialize(line, path, lineno, binding, assertion_method_name = nil, assertion_proc = nil) @line = line - @line_for_parsing = valid_syntax?(line) ? line : slice_expression(line) @path = path @lineno = lineno + begin + @rest_lines = open(path).each_line.drop(lineno + 1) + rescue StandardError + @rest_lines = [] + end + @line_for_parsing = valid_syntax? ? @line : slice_expression(line) @binding = binding @proc_local_variables = binding.eval('local_variables').map(&:to_s) @assertion_method_name = assertion_method_name @@ -32,16 +37,28 @@ def method_id_set private - def valid_syntax?(str) + def valid_syntax? return true unless defined?(RubyVM) begin verbose, $VERBOSE = $VERBOSE, nil - RubyVM::InstructionSequence.compile(str) - true - rescue SyntaxError - false + original_stderr = $stderr.clone + $stderr.reopen(File.new('/dev/null', 'w')) + while true do + begin + RubyVM::InstructionSequence.compile(@line) + return true + rescue SyntaxError + if @rest_lines.empty? + return false + else + next_line = @rest_lines.shift + @line = "#{@line}#{next_line}" + end + end + end ensure $VERBOSE = verbose + $stderr.reopen(original_stderr) end end diff --git a/test/fixtures/invalid_multiline_assertion.rb b/test/fixtures/invalid_multiline_assertion.rb new file mode 100644 index 0000000..0eb9013 --- /dev/null +++ b/test/fixtures/invalid_multiline_assertion.rb @@ -0,0 +1,2 @@ +a(0, + 1, diff --git a/test/fixtures/valid_multiline_assertion.rb b/test/fixtures/valid_multiline_assertion.rb new file mode 100644 index 0000000..52d51ed --- /dev/null +++ b/test/fixtures/valid_multiline_assertion.rb @@ -0,0 +1,2 @@ +a(0, + 1) diff --git a/test/parser_multiline_test.rb b/test/parser_multiline_test.rb new file mode 100644 index 0000000..ae9d5d1 --- /dev/null +++ b/test/parser_multiline_test.rb @@ -0,0 +1,30 @@ +class TestParserMultiline < Test::Unit::TestCase + def setup + ::PowerAssert.public_constant :Parser + end + + def teardown + ::PowerAssert.private_constant :Parser + end + + def test_valid + path = "#{File.dirname(__FILE__)}/fixtures/valid_multiline_assertion.rb" + lineno = 0 + line = open(path).each_line.first + assert parsed_as_valid_syntax?(line, path, lineno) + end + + def test_invalid + path = "#{File.dirname(__FILE__)}/fixtures/invalid_multiline_assertion.rb" + lineno = 0 + line = open(path).each_line.first + assert_false parsed_as_valid_syntax?(line, path, lineno) + end + + private + + def parsed_as_valid_syntax?(line, path, lineno) + parser = ::PowerAssert::Parser.new(line, path, lineno, TOPLEVEL_BINDING, nil, nil) + parser.send(:valid_syntax?) + end +end