Skip to content

Commit

Permalink
Banner for different syntax error types
Browse files Browse the repository at this point in the history
SyntaxSearch works for other missing keywords other than `end` that would otherwise trigger an `unexpected end` error. This commit adds more explicit banners for these cases.

#18
  • Loading branch information
schneems committed Dec 10, 2020
1 parent e4cc8c0 commit b4698e3
Show file tree
Hide file tree
Showing 7 changed files with 209 additions and 29 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## HEAD (unreleased)

- Error banner now indicates when missing a `|` or `}` in addition to `end` (https://github.com/zombocom/syntax_search/pull/29)
- Trailing slashes are now handled (joined) before the code search (https://github.com/zombocom/syntax_search/pull/28)

## 0.2.0
Expand Down
4 changes: 2 additions & 2 deletions lib/syntax_search.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def self.call(source: , filename: , terminal: false, record_dir: nil, timeout: T
filename: filename,
terminal: terminal,
code_lines: search.code_lines,
invalid_type: invalid_type(source),
invalid_obj: invalid_type(source),
io: $stderr
).call
rescue Timeout::Error
Expand Down Expand Up @@ -134,7 +134,7 @@ def self.valid?(source)


def self.invalid_type(source)
WhoDisSyntaxError.new(source).call.error_symbol
WhoDisSyntaxError.new(source).call
end
end

Expand Down
66 changes: 44 additions & 22 deletions lib/syntax_search/display_invalid_blocks.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ module SyntaxErrorSearch
class DisplayInvalidBlocks
attr_reader :filename

def initialize(code_lines: ,blocks:, io: $stderr, filename: nil, terminal: false, invalid_type: :unmatched_end)
def initialize(code_lines: ,blocks:, io: $stderr, filename: nil, terminal: false, invalid_obj: WhoDisSyntaxError::Null.new)
@terminal = terminal
@filename = filename
@io = io
Expand All @@ -18,7 +18,7 @@ def initialize(code_lines: ,blocks:, io: $stderr, filename: nil, terminal: false
@invalid_lines = @blocks.map(&:lines).flatten
@code_lines = code_lines

@invalid_type = invalid_type
@invalid_obj = invalid_obj
end

def call
Expand All @@ -36,34 +36,56 @@ def call
end

private def found_invalid_blocks
case @invalid_type
when :missing_end
@io.puts <<~EOM
@io.puts
@io.puts banner
@io.puts
@io.puts("file: #{filename}") if filename
@io.puts <<~EOM
simplified:
#{indent(code_block)}
EOM
end

def banner
case @invalid_obj.error_symbol
when :missing_end
<<~EOM
SyntaxSearch: Missing `end` detected
This code has a missing `end`. Ensure that all
syntax keywords (`def`, `do`, etc.) have a matching `end`.
EOM
when :unmatched_end
@io.puts <<~EOM
SyntaxSearch: Unmatched `end` detected
This code has an unmatched `end`. Ensure that all `end` lines
in your code have a matching syntax keyword (`def`, `do`, etc.)
and that you don't have any extra `end` lines.
EOM
when :unmatched_syntax
case @invalid_obj.unmatched_symbol
when :end
<<~EOM
SyntaxSearch: Unmatched `end` detected
This code has an unmatched `end`. Ensure that all `end` lines
in your code have a matching syntax keyword (`def`, `do`, etc.)
and that you don't have any extra `end` lines.
EOM
when :|
<<~EOM
SyntaxSearch: Unmatched `|` character detected
Example:
`do |x` should be `do |x|`
EOM
when :"}"
<<~EOM
SyntaxSearch: Unmatched `}` character detected
This code has an unmatched `}`. Ensure that opening curl braces are
closed: `{ }`.
EOM
else
"SyntaxSearch: Unmatched #{@invalid_obj.unmatched_symbol}` detected"
end
end

@io.puts("file: #{filename}") if filename
@io.puts <<~EOM
simplified:
#{indent(code_block)}
EOM
end

def indent(string, with: " ")
Expand Down
39 changes: 35 additions & 4 deletions lib/syntax_search/who_dis_syntax_error.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,30 @@ module SyntaxErrorSearch
# puts WhoDisSyntaxError.new("def foo;").call.error_symbol
# # => :missing_end
class WhoDisSyntaxError < Ripper
attr_reader :error, :run_once, :error_symbol
class Null
def error_symbol; :missing_end; end
def unmatched_symbol; :end ; end
end
attr_reader :error, :run_once

# Return options:
# - :missing_end
# - :unmatched_syntax
# - :unknown
def error_symbol
call
@error_symbol
end

# Return options:
# - :end
# - :|
# - :}
# - :unknown
def unmatched_symbol
call
@unmatched_symbol
end

def call
@run_once ||= begin
Expand All @@ -20,12 +43,20 @@ def call

def on_parse_error(msg)
@error = msg
@unmatched_symbol = :unknown

if @error.match?(/unexpected end-of-input/)
@error_symbol = :missing_end
elsif @error.match?(/unexpected `end'/) || @error.match?(/expecting end-of-input/)
@error_symbol = :unmatched_end
elsif @error.match?(/expecting end-of-input/)
@error_symbol = :unmatched_syntax
@unmatched_symbol = :end
elsif @error.match?(/unexpected `end'/) || @error.match?(/unexpected end,/) || @error.match?(/unexpected keyword_end/)
@error_symbol = :unmatched_syntax

match = @error.match(/expecting '(?<unmatched_symbol>.*)'/)
@unmatched_symbol = match[:unmatched_symbol].to_sym if match
else
@error_symbol = :nope
@error_symbol = :unknown
end
end
end
Expand Down
38 changes: 38 additions & 0 deletions spec/unit/code_search_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,44 @@

module SyntaxErrorSearch
RSpec.describe CodeSearch do
it "handles mismatched |" do
source = <<~EOM
class Blerg
Foo.call do |a
end # one
puts lol
class Foo
end # two
end # three
EOM
search = CodeSearch.new(source)
search.call

expect(search.invalid_blocks.join).to eq(<<~EOM.indent(2))
Foo.call do |a
end # one
EOM
end

it "handles mismatched }" do
source = <<~EOM
class Blerg
Foo.call do {
puts lol
class Foo
end # two
end # three
EOM
search = CodeSearch.new(source)
search.call

expect(search.invalid_blocks.join).to eq(<<~EOM.indent(2))
Foo.call do {
EOM
end

it "handles no spaces between blocks" do
search = CodeSearch.new(<<~'EOM')
require "rails_helper"
Expand Down
63 changes: 63 additions & 0 deletions spec/unit/display_invalid_blocks_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,69 @@

module SyntaxErrorSearch
RSpec.describe DisplayInvalidBlocks do
it "Unmatched | banner" do
source = <<~EOM
Foo.call do |
end
EOM
code_lines = code_line_array(source)

display = DisplayInvalidBlocks.new(
code_lines: code_lines,
blocks: CodeBlock.new(lines: code_lines),
invalid_obj: WhoDisSyntaxError.new(source),
)
expect(display.banner).to include("Unmatched `|` character detected")
end

it "Unmatched } banner" do
source = <<~EOM
class Cat
lol = {
end
EOM
code_lines = code_line_array(source)

display = DisplayInvalidBlocks.new(
code_lines: code_lines,
blocks: CodeBlock.new(lines: code_lines),
invalid_obj: WhoDisSyntaxError.new(source),
)
expect(display.banner).to include("Unmatched `}` character detected")
end

it "Unmatched end banner" do
source = <<~EOM
class Cat
end
end
EOM
code_lines = code_line_array(source)

display = DisplayInvalidBlocks.new(
code_lines: code_lines,
blocks: CodeBlock.new(lines: code_lines),
invalid_obj: WhoDisSyntaxError.new(source),
)
expect(display.banner).to include("SyntaxSearch: Unmatched `end` detected")
end

it "missing end banner" do
source = <<~EOM
class Cat
def meow
end
EOM
code_lines = code_line_array(source)

display = DisplayInvalidBlocks.new(
code_lines: code_lines,
blocks: CodeBlock.new(lines: code_lines),
invalid_obj: WhoDisSyntaxError.new(source),
)
expect(display.banner).to include("SyntaxSearch: Missing `end` detected")
end

it "captures surrounding context on same indent" do
syntax_string = <<~EOM
class Blerg
Expand Down
27 changes: 26 additions & 1 deletion spec/unit/who_dis_syntax_error_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,32 @@ module SyntaxErrorSearch

expect(
WhoDisSyntaxError.new("def foo; end; end").call.error_symbol
).to eq(:unmatched_end)
).to eq(:unmatched_syntax)

expect(
WhoDisSyntaxError.new("def foo; end; end").call.unmatched_symbol
).to eq(:end)
end

it "" do
source = <<~EOM
class Blerg
Foo.call do |a
end # one
puts lol
class Foo
end # two
end # three
EOM

expect(
SyntaxErrorSearch.invalid_type(source).error_symbol
).to eq(:unmatched_syntax)

expect(
SyntaxErrorSearch.invalid_type(source).unmatched_symbol
).to eq(:|)
end
end
end

0 comments on commit b4698e3

Please sign in to comment.