Skip to content

Commit 7801f67

Browse files
committed
Banner for different syntax error types
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
1 parent e4cc8c0 commit 7801f67

File tree

7 files changed

+212
-29
lines changed

7 files changed

+212
-29
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
## HEAD (unreleased)
22

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

56
## 0.2.0

lib/syntax_search.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def self.call(source: , filename: , terminal: false, record_dir: nil, timeout: T
4646
filename: filename,
4747
terminal: terminal,
4848
code_lines: search.code_lines,
49-
invalid_type: invalid_type(source),
49+
invalid_obj: invalid_type(source),
5050
io: $stderr
5151
).call
5252
rescue Timeout::Error
@@ -134,7 +134,7 @@ def self.valid?(source)
134134

135135

136136
def self.invalid_type(source)
137-
WhoDisSyntaxError.new(source).call.error_symbol
137+
WhoDisSyntaxError.new(source).call
138138
end
139139
end
140140

lib/syntax_search/display_invalid_blocks.rb

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ module SyntaxErrorSearch
88
class DisplayInvalidBlocks
99
attr_reader :filename
1010

11-
def initialize(code_lines: ,blocks:, io: $stderr, filename: nil, terminal: false, invalid_type: :unmatched_end)
11+
def initialize(code_lines: ,blocks:, io: $stderr, filename: nil, terminal: false, invalid_obj: WhoDisSyntaxError::Null.new)
1212
@terminal = terminal
1313
@filename = filename
1414
@io = io
@@ -18,7 +18,7 @@ def initialize(code_lines: ,blocks:, io: $stderr, filename: nil, terminal: false
1818
@invalid_lines = @blocks.map(&:lines).flatten
1919
@code_lines = code_lines
2020

21-
@invalid_type = invalid_type
21+
@invalid_obj = invalid_obj
2222
end
2323

2424
def call
@@ -36,34 +36,56 @@ def call
3636
end
3737

3838
private def found_invalid_blocks
39-
case @invalid_type
40-
when :missing_end
41-
@io.puts <<~EOM
39+
@io.puts
40+
@io.puts banner
41+
@io.puts
42+
@io.puts("file: #{filename}") if filename
43+
@io.puts <<~EOM
44+
simplified:
45+
46+
#{indent(code_block)}
47+
EOM
48+
end
4249

50+
def banner
51+
case @invalid_obj.error_symbol
52+
when :missing_end
53+
<<~EOM
4354
SyntaxSearch: Missing `end` detected
4455
4556
This code has a missing `end`. Ensure that all
4657
syntax keywords (`def`, `do`, etc.) have a matching `end`.
47-
48-
EOM
49-
when :unmatched_end
50-
@io.puts <<~EOM
51-
52-
SyntaxSearch: Unmatched `end` detected
53-
54-
This code has an unmatched `end`. Ensure that all `end` lines
55-
in your code have a matching syntax keyword (`def`, `do`, etc.)
56-
and that you don't have any extra `end` lines.
57-
5858
EOM
59+
when :unmatched_syntax
60+
case @invalid_obj.unmatched_symbol
61+
when :end
62+
<<~EOM
63+
SyntaxSearch: Unmatched `end` detected
64+
65+
This code has an unmatched `end`. Ensure that all `end` lines
66+
in your code have a matching syntax keyword (`def`, `do`, etc.)
67+
and that you don't have any extra `end` lines.
68+
EOM
69+
when :|
70+
<<~EOM
71+
SyntaxSearch: Unmatched `|` character detected
72+
73+
Example:
74+
75+
`do |x` should be `do |x|`
76+
EOM
77+
when :"}"
78+
<<~EOM
79+
SyntaxSearch: Unmatched `}` character detected
80+
81+
This code has an unmatched `}`. Ensure that opening curl braces are
82+
closed: `{ }`.
83+
EOM
84+
else
85+
"SyntaxSearch: Unmatched #{@invalid_obj.unmatched_symbol}` detected"
86+
end
5987
end
6088

61-
@io.puts("file: #{filename}") if filename
62-
@io.puts <<~EOM
63-
simplified:
64-
65-
#{indent(code_block)}
66-
EOM
6789
end
6890

6991
def indent(string, with: " ")

lib/syntax_search/who_dis_syntax_error.rb

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,30 @@ module SyntaxErrorSearch
88
# puts WhoDisSyntaxError.new("def foo;").call.error_symbol
99
# # => :missing_end
1010
class WhoDisSyntaxError < Ripper
11-
attr_reader :error, :run_once, :error_symbol
11+
class Null
12+
def error_symbol; :missing_end; end
13+
def unmatched_symbol; :end ; end
14+
end
15+
attr_reader :error, :run_once
16+
17+
# Return options:
18+
# - :missing_end
19+
# - :unmatched_syntax
20+
# - :unknown
21+
def error_symbol
22+
call
23+
@error_symbol
24+
end
25+
26+
# Return options:
27+
# - :end
28+
# - :|
29+
# - :}
30+
# - :unknown
31+
def unmatched_symbol
32+
call
33+
@unmatched_symbol
34+
end
1235

1336
def call
1437
@run_once ||= begin
@@ -20,12 +43,23 @@ def call
2043

2144
def on_parse_error(msg)
2245
@error = msg
46+
@unmatched_symbol = :unknown
47+
2348
if @error.match?(/unexpected end-of-input/)
2449
@error_symbol = :missing_end
25-
elsif @error.match?(/unexpected `end'/) || @error.match?(/expecting end-of-input/)
26-
@error_symbol = :unmatched_end
50+
elsif @error.match?(/expecting end-of-input/)
51+
@error_symbol = :unmatched_syntax
52+
@unmatched_symbol = :end
53+
elsif @error.match?(/unexpected `end'/) || # Ruby 2.7 & 3.0
54+
@error.match?(/unexpected end,/) || # Ruby 2.6
55+
@error.match?(/unexpected keyword_end/) # Ruby 2.5
56+
57+
@error_symbol = :unmatched_syntax
58+
59+
match = @error.match(/expecting '(?<unmatched_symbol>.*)'/)
60+
@unmatched_symbol = match[:unmatched_symbol].to_sym if match
2761
else
28-
@error_symbol = :nope
62+
@error_symbol = :unknown
2963
end
3064
end
3165
end

spec/unit/code_search_spec.rb

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,44 @@
44

55
module SyntaxErrorSearch
66
RSpec.describe CodeSearch do
7+
it "handles mismatched |" do
8+
source = <<~EOM
9+
class Blerg
10+
Foo.call do |a
11+
end # one
12+
13+
puts lol
14+
class Foo
15+
end # two
16+
end # three
17+
EOM
18+
search = CodeSearch.new(source)
19+
search.call
20+
21+
expect(search.invalid_blocks.join).to eq(<<~EOM.indent(2))
22+
Foo.call do |a
23+
end # one
24+
EOM
25+
end
26+
27+
it "handles mismatched }" do
28+
source = <<~EOM
29+
class Blerg
30+
Foo.call do {
31+
32+
puts lol
33+
class Foo
34+
end # two
35+
end # three
36+
EOM
37+
search = CodeSearch.new(source)
38+
search.call
39+
40+
expect(search.invalid_blocks.join).to eq(<<~EOM.indent(2))
41+
Foo.call do {
42+
EOM
43+
end
44+
745
it "handles no spaces between blocks" do
846
search = CodeSearch.new(<<~'EOM')
947
require "rails_helper"

spec/unit/display_invalid_blocks_spec.rb

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,69 @@
44

55
module SyntaxErrorSearch
66
RSpec.describe DisplayInvalidBlocks do
7+
it "Unmatched | banner" do
8+
source = <<~EOM
9+
Foo.call do |
10+
end
11+
EOM
12+
code_lines = code_line_array(source)
13+
14+
display = DisplayInvalidBlocks.new(
15+
code_lines: code_lines,
16+
blocks: CodeBlock.new(lines: code_lines),
17+
invalid_obj: WhoDisSyntaxError.new(source),
18+
)
19+
expect(display.banner).to include("Unmatched `|` character detected")
20+
end
21+
22+
it "Unmatched } banner" do
23+
source = <<~EOM
24+
class Cat
25+
lol = {
26+
end
27+
EOM
28+
code_lines = code_line_array(source)
29+
30+
display = DisplayInvalidBlocks.new(
31+
code_lines: code_lines,
32+
blocks: CodeBlock.new(lines: code_lines),
33+
invalid_obj: WhoDisSyntaxError.new(source),
34+
)
35+
expect(display.banner).to include("Unmatched `}` character detected")
36+
end
37+
38+
it "Unmatched end banner" do
39+
source = <<~EOM
40+
class Cat
41+
end
42+
end
43+
EOM
44+
code_lines = code_line_array(source)
45+
46+
display = DisplayInvalidBlocks.new(
47+
code_lines: code_lines,
48+
blocks: CodeBlock.new(lines: code_lines),
49+
invalid_obj: WhoDisSyntaxError.new(source),
50+
)
51+
expect(display.banner).to include("SyntaxSearch: Unmatched `end` detected")
52+
end
53+
54+
it "missing end banner" do
55+
source = <<~EOM
56+
class Cat
57+
def meow
58+
end
59+
EOM
60+
code_lines = code_line_array(source)
61+
62+
display = DisplayInvalidBlocks.new(
63+
code_lines: code_lines,
64+
blocks: CodeBlock.new(lines: code_lines),
65+
invalid_obj: WhoDisSyntaxError.new(source),
66+
)
67+
expect(display.banner).to include("SyntaxSearch: Missing `end` detected")
68+
end
69+
770
it "captures surrounding context on same indent" do
871
syntax_string = <<~EOM
972
class Blerg

spec/unit/who_dis_syntax_error_spec.rb

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,32 @@ module SyntaxErrorSearch
1111

1212
expect(
1313
WhoDisSyntaxError.new("def foo; end; end").call.error_symbol
14-
).to eq(:unmatched_end)
14+
).to eq(:unmatched_syntax)
15+
16+
expect(
17+
WhoDisSyntaxError.new("def foo; end; end").call.unmatched_symbol
18+
).to eq(:end)
19+
end
20+
21+
it "" do
22+
source = <<~EOM
23+
class Blerg
24+
Foo.call do |a
25+
end # one
26+
27+
puts lol
28+
class Foo
29+
end # two
30+
end # three
31+
EOM
32+
33+
expect(
34+
SyntaxErrorSearch.invalid_type(source).error_symbol
35+
).to eq(:unmatched_syntax)
36+
37+
expect(
38+
SyntaxErrorSearch.invalid_type(source).unmatched_symbol
39+
).to eq(:|)
1540
end
1641
end
1742
end

0 commit comments

Comments
 (0)