Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
42 changes: 38 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,23 @@ 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'/) || # Ruby 2.7 & 3.0
@error.match?(/unexpected end,/) || # Ruby 2.6
@error.match?(/unexpected keyword_end/) # Ruby 2.5

@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