dead_end 1.1.6 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.circleci/config.yml +14 -0
- data/.standard.yml +1 -0
- data/CHANGELOG.md +24 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +29 -2
- data/README.md +1 -19
- data/Rakefile +1 -1
- data/dead_end.gemspec +12 -12
- data/exe/dead_end +12 -4
- data/lib/dead_end/around_block_scan.rb +16 -18
- data/lib/dead_end/auto.rb +3 -52
- data/lib/dead_end/banner.rb +58 -0
- data/lib/dead_end/block_expand.rb +6 -5
- data/lib/dead_end/capture_code_context.rb +167 -50
- data/lib/dead_end/clean_document.rb +313 -0
- data/lib/dead_end/code_block.rb +3 -3
- data/lib/dead_end/code_frontier.rb +28 -17
- data/lib/dead_end/code_line.rb +160 -77
- data/lib/dead_end/code_search.rb +37 -48
- data/lib/dead_end/display_code_with_line_numbers.rb +7 -8
- data/lib/dead_end/display_invalid_blocks.rb +18 -48
- data/lib/dead_end/fyi.rb +2 -1
- data/lib/dead_end/internals.rb +23 -27
- data/lib/dead_end/lex_all.rb +15 -31
- data/lib/dead_end/lex_value.rb +62 -0
- data/lib/dead_end/parse_blocks_from_indent_line.rb +3 -4
- data/lib/dead_end/version.rb +1 -1
- data/lib/dead_end/who_dis_syntax_error.rb +22 -8
- metadata +7 -6
- data/.travis.yml +0 -6
- data/lib/dead_end/heredoc_block_parse.rb +0 -30
- data/lib/dead_end/trailing_slash_join.rb +0 -53
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7d7d236a8a3634efc153e2a20f511072c2b10f97553595ddb3309b88f74dbbb8
|
4
|
+
data.tar.gz: 5cb84a34d16f9c7714791f01864cfb1b05095b8eb9587be5cfbc86aed1c31a20
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 41f2022c9faba2cd907b91f9dbd2200172af5ddaa6117f80c7dc7229665026e89d06284cfd43d439dfe879f541ee77b57cb09334c49d1f7732ba1ab484197852
|
7
|
+
data.tar.gz: 667597674b31cda70837d9e11c46ccf3f4d7374445f56d8fc1f1f4fda3bd4cad0fdf2c2517620224aea683be21b7142101787aac0cb40e7a296ac039be2af0d3
|
data/.circleci/config.yml
CHANGED
@@ -7,6 +7,11 @@ references:
|
|
7
7
|
name: Run test suite
|
8
8
|
command: bundle exec rspec spec/
|
9
9
|
|
10
|
+
lint: &lint
|
11
|
+
run:
|
12
|
+
name: Run linter, fix with `standardrb --fix` locally
|
13
|
+
command: bundle exec standardrb
|
14
|
+
|
10
15
|
jobs:
|
11
16
|
"ruby-2-5":
|
12
17
|
docker:
|
@@ -40,6 +45,14 @@ jobs:
|
|
40
45
|
- ruby/install-deps
|
41
46
|
- <<: *unit
|
42
47
|
|
48
|
+
"lint":
|
49
|
+
docker:
|
50
|
+
- image: circleci/ruby:3.0
|
51
|
+
steps:
|
52
|
+
- checkout
|
53
|
+
- ruby/install-deps
|
54
|
+
- <<: *lint
|
55
|
+
|
43
56
|
workflows:
|
44
57
|
version: 2
|
45
58
|
build:
|
@@ -48,3 +61,4 @@ workflows:
|
|
48
61
|
- "ruby-2-6"
|
49
62
|
- "ruby-2-7"
|
50
63
|
- "ruby-3-0"
|
64
|
+
- "lint"
|
data/.standard.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby_version: 2.5.9
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,29 @@
|
|
1
1
|
## HEAD (unreleased)
|
2
2
|
|
3
|
+
## 2.0.1
|
4
|
+
|
5
|
+
- Reintroduce Ruby 2.5 support (https://github.com/zombocom/dead_end/pull/90)
|
6
|
+
- Support naked braces/brackets/parens, invert labels on banner (https://github.com/zombocom/dead_end/pull/89)
|
7
|
+
- Handle mismatched end when using rescue without begin (https://github.com/zombocom/dead_end/pull/83)
|
8
|
+
- CLI returns non-zero exit code when syntax error is found (https://github.com/zombocom/dead_end/pull/86)
|
9
|
+
- Let -v respond with gem version instead of 'unknown' (https://github.com/zombocom/dead_end/pull/82)
|
10
|
+
|
11
|
+
## 2.0.0
|
12
|
+
|
13
|
+
- Support "endless" oneline method definitions for Ruby 3+ (https://github.com/zombocom/dead_end/pull/80)
|
14
|
+
- Reduce timeout to 1 second (https://github.com/zombocom/dead_end/pull/79)
|
15
|
+
- Logically consecutive lines (such as chained methods are now joined) (https://github.com/zombocom/dead_end/pull/78)
|
16
|
+
- Output improvement for cases where the only line is an single `end` (https://github.com/zombocom/dead_end/pull/78)
|
17
|
+
|
18
|
+
## 1.2.0
|
19
|
+
|
20
|
+
- Output improvements via less greedy unmatched kw capture https://github.com/zombocom/dead_end/pull/73
|
21
|
+
- Remove NoMethodError patching instead use https://github.com/ruby/error_highlight/ (https://github.com/zombocom/dead_end/pull/71)
|
22
|
+
|
23
|
+
## 1.1.7
|
24
|
+
|
25
|
+
- Fix sinatra support for `require_relative` (https://github.com/zombocom/dead_end/pull/63)
|
26
|
+
|
3
27
|
## 1.1.6
|
4
28
|
|
5
29
|
- Consider if syntax error caused an unexpected variable instead of end (https://github.com/zombocom/dead_end/pull/58)
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,13 +1,20 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
dead_end (
|
4
|
+
dead_end (2.0.1)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
|
+
ast (2.4.2)
|
9
10
|
diff-lcs (1.4.4)
|
11
|
+
parallel (1.21.0)
|
12
|
+
parser (3.0.2.0)
|
13
|
+
ast (~> 2.4.1)
|
14
|
+
rainbow (3.0.0)
|
10
15
|
rake (12.3.3)
|
16
|
+
regexp_parser (2.1.1)
|
17
|
+
rexml (3.2.5)
|
11
18
|
rspec (3.10.0)
|
12
19
|
rspec-core (~> 3.10.0)
|
13
20
|
rspec-expectations (~> 3.10.0)
|
@@ -21,7 +28,26 @@ GEM
|
|
21
28
|
diff-lcs (>= 1.2.0, < 2.0)
|
22
29
|
rspec-support (~> 3.10.0)
|
23
30
|
rspec-support (3.10.0)
|
31
|
+
rubocop (1.20.0)
|
32
|
+
parallel (~> 1.10)
|
33
|
+
parser (>= 3.0.0.0)
|
34
|
+
rainbow (>= 2.2.2, < 4.0)
|
35
|
+
regexp_parser (>= 1.8, < 3.0)
|
36
|
+
rexml
|
37
|
+
rubocop-ast (>= 1.9.1, < 2.0)
|
38
|
+
ruby-progressbar (~> 1.7)
|
39
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
40
|
+
rubocop-ast (1.12.0)
|
41
|
+
parser (>= 3.0.1.1)
|
42
|
+
rubocop-performance (1.11.5)
|
43
|
+
rubocop (>= 1.7.0, < 2.0)
|
44
|
+
rubocop-ast (>= 0.4.0)
|
45
|
+
ruby-progressbar (1.11.0)
|
24
46
|
stackprof (0.2.16)
|
47
|
+
standard (1.3.0)
|
48
|
+
rubocop (= 1.20.0)
|
49
|
+
rubocop-performance (= 1.11.5)
|
50
|
+
unicode-display_width (2.1.0)
|
25
51
|
|
26
52
|
PLATFORMS
|
27
53
|
ruby
|
@@ -31,6 +57,7 @@ DEPENDENCIES
|
|
31
57
|
rake (~> 12.0)
|
32
58
|
rspec (~> 3.0)
|
33
59
|
stackprof
|
60
|
+
standard
|
34
61
|
|
35
62
|
BUNDLED WITH
|
36
|
-
2.2.
|
63
|
+
2.2.29
|
data/README.md
CHANGED
@@ -81,27 +81,9 @@ end
|
|
81
81
|
|
82
82
|
As well as unmatched `|` and unmatched `}`. These errors can be time consuming to debug because Ruby often only tells you the last line in the file. The command `ruby -wc path/to/file.rb` can narrow it down a little bit, but this library does a better job.
|
83
83
|
|
84
|
-
## What other errors does it handle?
|
85
|
-
|
86
|
-
In addition to syntax errors, the NoMethodError is annotated to show the line where the error occured, and the surrounding context:
|
87
|
-
|
88
|
-
```
|
89
|
-
scratch.rb:7:in `call': undefined method `upcase' for nil:NilClass (NoMethodError)
|
90
|
-
|
91
|
-
|
92
|
-
1 class Pet
|
93
|
-
6 def call
|
94
|
-
❯ 7 puts "Come here #{@neam.upcase}"
|
95
|
-
8 end
|
96
|
-
9 end
|
97
|
-
```
|
98
|
-
|
99
84
|
## Sounds cool, but why isn't this baked into Ruby directly?
|
100
85
|
|
101
|
-
|
102
|
-
|
103
|
-
1. Get real world useage and feedback. If we gave you an awful suggestion, let us know! We try to handle lots of cases well, but maybe we could be better.
|
104
|
-
2. Prove out demand. If you like this idea, then vote for it by putting it in your Gemfile.
|
86
|
+
We are now talking about it https://bugs.ruby-lang.org/issues/18159#change-93682.
|
105
87
|
|
106
88
|
## Artificial Inteligence?
|
107
89
|
|
data/Rakefile
CHANGED
data/dead_end.gemspec
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
3
|
+
require_relative "lib/dead_end/version"
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
|
-
spec.name
|
7
|
-
spec.version
|
8
|
-
spec.authors
|
9
|
-
spec.email
|
6
|
+
spec.name = "dead_end"
|
7
|
+
spec.version = DeadEnd::VERSION
|
8
|
+
spec.authors = ["schneems"]
|
9
|
+
spec.email = ["richard.schneeman+foo@gmail.com"]
|
10
10
|
|
11
|
-
spec.summary
|
12
|
-
spec.description
|
13
|
-
spec.homepage
|
14
|
-
spec.license
|
11
|
+
spec.summary = "Find syntax errors in your source in a snap"
|
12
|
+
spec.description = 'When you get an "unexpected end" in your syntax this gem helps you find it'
|
13
|
+
spec.homepage = "https://github.com/zombocom/dead_end.git"
|
14
|
+
spec.license = "MIT"
|
15
15
|
spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
|
16
16
|
|
17
17
|
spec.metadata["homepage_uri"] = spec.homepage
|
@@ -19,10 +19,10 @@ Gem::Specification.new do |spec|
|
|
19
19
|
|
20
20
|
# Specify which files should be added to the gem when it is released.
|
21
21
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
22
|
-
spec.files
|
22
|
+
spec.files = Dir.chdir(File.expand_path("..", __FILE__)) do
|
23
23
|
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|assets)/}) }
|
24
24
|
end
|
25
|
-
spec.bindir
|
26
|
-
spec.executables
|
25
|
+
spec.bindir = "exe"
|
26
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
27
27
|
spec.require_paths = ["lib"]
|
28
28
|
end
|
data/exe/dead_end
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require
|
3
|
+
require "pathname"
|
4
4
|
require "optparse"
|
5
|
-
require_relative "../lib/dead_end
|
5
|
+
require_relative "../lib/dead_end"
|
6
6
|
|
7
7
|
options = {}
|
8
8
|
options[:terminal] = true
|
@@ -35,6 +35,8 @@ parser = OptionParser.new do |opts|
|
|
35
35
|
Options:
|
36
36
|
EOM
|
37
37
|
|
38
|
+
opts.version = DeadEnd::VERSION
|
39
|
+
|
38
40
|
opts.on("--help", "Help - displays this message") do |v|
|
39
41
|
puts opts
|
40
42
|
exit
|
@@ -60,11 +62,17 @@ end
|
|
60
62
|
file = Pathname(file)
|
61
63
|
options[:record_dir] = "tmp" if ENV["DEBUG"]
|
62
64
|
|
63
|
-
|
65
|
+
warn "Record dir: #{options[:record_dir]}" if options[:record_dir]
|
64
66
|
|
65
|
-
DeadEnd.call(
|
67
|
+
display = DeadEnd.call(
|
66
68
|
source: file.read,
|
67
69
|
filename: file.expand_path,
|
68
70
|
terminal: options[:terminal],
|
69
71
|
record_dir: options[:record_dir]
|
70
72
|
)
|
73
|
+
|
74
|
+
if display.document_ok?
|
75
|
+
exit(0)
|
76
|
+
else
|
77
|
+
exit(1)
|
78
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
3
|
module DeadEnd
|
4
4
|
# This class is useful for exploring contents before and after
|
5
5
|
# a block
|
@@ -9,10 +9,10 @@ module DeadEnd
|
|
9
9
|
#
|
10
10
|
# Example:
|
11
11
|
#
|
12
|
-
# def dog
|
13
|
-
# puts "bark"
|
14
|
-
# puts "bark"
|
15
|
-
# end
|
12
|
+
# def dog # 1
|
13
|
+
# puts "bark" # 2
|
14
|
+
# puts "bark" # 3
|
15
|
+
# end # 4
|
16
16
|
#
|
17
17
|
# scan = AroundBlockScan.new(
|
18
18
|
# code_lines: code_lines
|
@@ -22,13 +22,13 @@ module DeadEnd
|
|
22
22
|
# scan.scan_while { true }
|
23
23
|
#
|
24
24
|
# puts scan.before_index # => 0
|
25
|
-
# puts scan.after_index
|
25
|
+
# puts scan.after_index # => 3
|
26
26
|
#
|
27
27
|
# Contents can also be filtered using AroundBlockScan#skip
|
28
28
|
#
|
29
29
|
# To grab the next surrounding indentation use AroundBlockScan#scan_adjacent_indent
|
30
30
|
class AroundBlockScan
|
31
|
-
def initialize(code_lines
|
31
|
+
def initialize(code_lines:, block:)
|
32
32
|
@code_lines = code_lines
|
33
33
|
@orig_before_index = block.lines.first.index
|
34
34
|
@orig_after_index = block.lines.last.index
|
@@ -56,7 +56,7 @@ module DeadEnd
|
|
56
56
|
end_count = 0
|
57
57
|
@before_index = before_lines.reverse_each.take_while do |line|
|
58
58
|
next false if stop_next
|
59
|
-
next true if @skip_array.detect {|meth| line.send(meth) }
|
59
|
+
next true if @skip_array.detect { |meth| line.send(meth) }
|
60
60
|
|
61
61
|
kw_count += 1 if line.is_kw?
|
62
62
|
end_count += 1 if line.is_end?
|
@@ -65,14 +65,14 @@ module DeadEnd
|
|
65
65
|
end
|
66
66
|
|
67
67
|
block.call(line)
|
68
|
-
end.
|
68
|
+
end.last&.index
|
69
69
|
|
70
70
|
stop_next = false
|
71
71
|
kw_count = 0
|
72
72
|
end_count = 0
|
73
73
|
@after_index = after_lines.take_while do |line|
|
74
74
|
next false if stop_next
|
75
|
-
next true if @skip_array.detect {|meth| line.send(meth) }
|
75
|
+
next true if @skip_array.detect { |meth| line.send(meth) }
|
76
76
|
|
77
77
|
kw_count += 1 if line.is_kw?
|
78
78
|
end_count += 1 if line.is_end?
|
@@ -89,7 +89,7 @@ module DeadEnd
|
|
89
89
|
lines = []
|
90
90
|
kw_count = 0
|
91
91
|
end_count = 0
|
92
|
-
before_lines.
|
92
|
+
before_lines.reverse_each do |line|
|
93
93
|
next if line.empty?
|
94
94
|
break if line.indent < @orig_indent
|
95
95
|
next if line.indent != @orig_indent
|
@@ -109,8 +109,6 @@ module DeadEnd
|
|
109
109
|
kw_count = 0
|
110
110
|
end_count = 0
|
111
111
|
after_lines.each do |line|
|
112
|
-
# puts "line: #{line.number} #{line.original_line}, indent: #{line.indent}, #{line.empty?} #{line.indent == @orig_indent}"
|
113
|
-
|
114
112
|
next if line.empty?
|
115
113
|
break if line.indent < @orig_indent
|
116
114
|
next if line.indent != @orig_indent
|
@@ -124,14 +122,13 @@ module DeadEnd
|
|
124
122
|
|
125
123
|
lines << line
|
126
124
|
end
|
127
|
-
lines.select! {|line| !line.is_comment? }
|
128
125
|
|
129
126
|
lines
|
130
127
|
end
|
131
128
|
|
132
129
|
def on_falling_indent
|
133
130
|
last_indent = @orig_indent
|
134
|
-
before_lines.
|
131
|
+
before_lines.reverse_each do |line|
|
135
132
|
next if line.empty?
|
136
133
|
if line.indent < last_indent
|
137
134
|
yield line
|
@@ -150,7 +147,7 @@ module DeadEnd
|
|
150
147
|
end
|
151
148
|
|
152
149
|
def scan_neighbors
|
153
|
-
|
150
|
+
scan_while { |line| line.not_empty? && line.indent >= @orig_indent }
|
154
151
|
end
|
155
152
|
|
156
153
|
def next_up
|
@@ -167,13 +164,14 @@ module DeadEnd
|
|
167
164
|
before_after_indent << (next_down&.indent || 0)
|
168
165
|
|
169
166
|
indent = before_after_indent.min
|
170
|
-
|
167
|
+
scan_while { |line| line.not_empty? && line.indent >= indent }
|
171
168
|
|
172
169
|
self
|
173
170
|
end
|
174
171
|
|
175
172
|
def start_at_next_line
|
176
|
-
before_index
|
173
|
+
before_index
|
174
|
+
after_index
|
177
175
|
@before_index -= 1
|
178
176
|
@after_index += 1
|
179
177
|
self
|
data/lib/dead_end/auto.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
3
|
require_relative "../dead_end/internals"
|
4
4
|
|
5
5
|
# Monkey patch kernel to ensure that all `require` calls call the same
|
@@ -27,7 +27,7 @@ module Kernel
|
|
27
27
|
if Pathname.new(file).absolute?
|
28
28
|
dead_end_original_require file
|
29
29
|
else
|
30
|
-
dead_end_original_require File.expand_path("../#{file}", caller_locations(1, 1)[0].absolute_path)
|
30
|
+
dead_end_original_require File.expand_path("../#{file}", Kernel.caller_locations(1, 1)[0].absolute_path)
|
31
31
|
end
|
32
32
|
rescue SyntaxError => e
|
33
33
|
DeadEnd.handle_error(e)
|
@@ -40,6 +40,7 @@ end
|
|
40
40
|
# am I doing something different?
|
41
41
|
class Object
|
42
42
|
private
|
43
|
+
|
43
44
|
def load(path, wrap = false)
|
44
45
|
Kernel.load(path, wrap)
|
45
46
|
rescue SyntaxError => e
|
@@ -52,53 +53,3 @@ class Object
|
|
52
53
|
DeadEnd.handle_error(e)
|
53
54
|
end
|
54
55
|
end
|
55
|
-
|
56
|
-
module DeadEnd
|
57
|
-
IsProduction = -> {
|
58
|
-
ENV["RAILS_ENV"] == "production" || ENV["RACK_ENV"] == "production"
|
59
|
-
}
|
60
|
-
end
|
61
|
-
|
62
|
-
# Unlike a syntax error, a NoMethodError can occur hundreds or thousands of times and
|
63
|
-
# chew up CPU and other resources. Since this is primarilly a "development" optimization
|
64
|
-
# we can attempt to disable this behavior in a production context.
|
65
|
-
if !DeadEnd::IsProduction.call
|
66
|
-
class NoMethodError
|
67
|
-
alias :dead_end_original_to_s :to_s
|
68
|
-
|
69
|
-
def to_s
|
70
|
-
return super if DeadEnd::IsProduction.call
|
71
|
-
|
72
|
-
file, line, _ = backtrace[0].split(":")
|
73
|
-
return super if !File.exist?(file)
|
74
|
-
|
75
|
-
index = line.to_i - 1
|
76
|
-
source = File.read(file)
|
77
|
-
code_lines = DeadEnd::CodeLine.parse(source)
|
78
|
-
|
79
|
-
block = DeadEnd::CodeBlock.new(lines: code_lines[index])
|
80
|
-
lines = DeadEnd::CaptureCodeContext.new(
|
81
|
-
blocks: block,
|
82
|
-
code_lines: code_lines
|
83
|
-
).call
|
84
|
-
|
85
|
-
message = super.dup
|
86
|
-
message << $/
|
87
|
-
message << $/
|
88
|
-
|
89
|
-
message << DeadEnd::DisplayCodeWithLineNumbers.new(
|
90
|
-
lines: lines,
|
91
|
-
highlight_lines: block.lines,
|
92
|
-
terminal: self.class.to_tty?
|
93
|
-
).call
|
94
|
-
|
95
|
-
message << $/
|
96
|
-
message
|
97
|
-
rescue => e
|
98
|
-
puts "DeadEnd Internal error: #{e.dead_end_original_to_s}"
|
99
|
-
puts "DeadEnd Internal backtrace:"
|
100
|
-
puts backtrace.map {|l| " " + l }.join($/)
|
101
|
-
super
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DeadEnd
|
4
|
+
class Banner
|
5
|
+
attr_reader :invalid_obj
|
6
|
+
|
7
|
+
def initialize(invalid_obj:)
|
8
|
+
@invalid_obj = invalid_obj
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
case invalid_obj.error_symbol
|
13
|
+
when :missing_end
|
14
|
+
<<~EOM
|
15
|
+
DeadEnd: Missing `end` detected
|
16
|
+
|
17
|
+
This code has a missing `end`. Ensure that all
|
18
|
+
syntax keywords (`def`, `do`, etc.) have a matching `end`.
|
19
|
+
EOM
|
20
|
+
when :unmatched_syntax
|
21
|
+
case unmatched_symbol
|
22
|
+
when :end
|
23
|
+
<<~EOM
|
24
|
+
DeadEnd: Unmatched `end` detected
|
25
|
+
|
26
|
+
This code has an unmatched `end`. Ensure that all `end` lines
|
27
|
+
in your code have a matching syntax keyword (`def`, `do`, etc.)
|
28
|
+
and that you don't have any extra `end` lines.
|
29
|
+
EOM
|
30
|
+
when :|
|
31
|
+
<<~EOM
|
32
|
+
DeadEnd: Unmatched `|` character detected
|
33
|
+
|
34
|
+
Example:
|
35
|
+
|
36
|
+
`do |x` should be `do |x|`
|
37
|
+
EOM
|
38
|
+
when *WhoDisSyntaxError::CHARACTERS.keys
|
39
|
+
<<~EOM
|
40
|
+
DeadEnd: Unmatched `#{unmatched_symbol}` character detected
|
41
|
+
|
42
|
+
It appears a `#{missing_character}` might be missing.
|
43
|
+
EOM
|
44
|
+
else
|
45
|
+
"DeadEnd: Unmatched `#{unmatched_symbol}` detected"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private def unmatched_symbol
|
51
|
+
invalid_obj.unmatched_symbol
|
52
|
+
end
|
53
|
+
|
54
|
+
private def missing_character
|
55
|
+
WhoDisSyntaxError::CHARACTERS[unmatched_symbol]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module DeadEnd
|
3
4
|
# This class is responsible for taking a code block that exists
|
4
5
|
# at a far indentaion and then iteratively increasing the block
|
@@ -30,7 +31,7 @@ module DeadEnd
|
|
30
31
|
# end
|
31
32
|
#
|
32
33
|
class BlockExpand
|
33
|
-
def initialize(code_lines:
|
34
|
+
def initialize(code_lines:)
|
34
35
|
@code_lines = code_lines
|
35
36
|
end
|
36
37
|
|
@@ -43,7 +44,7 @@ module DeadEnd
|
|
43
44
|
end
|
44
45
|
|
45
46
|
def expand_indent(block)
|
46
|
-
|
47
|
+
AroundBlockScan.new(code_lines: @code_lines, block: block)
|
47
48
|
.skip(:hidden?)
|
48
49
|
.stop_after_kw
|
49
50
|
.scan_adjacent_indent
|
@@ -59,15 +60,15 @@ module DeadEnd
|
|
59
60
|
# Slurp up empties
|
60
61
|
if grab_empty
|
61
62
|
scan = AroundBlockScan.new(code_lines: @code_lines, block: scan.code_block)
|
62
|
-
.scan_while {|line| line.empty? || line.hidden? }
|
63
|
+
.scan_while { |line| line.empty? || line.hidden? }
|
63
64
|
end
|
64
65
|
|
65
66
|
new_block = scan.code_block
|
66
67
|
|
67
68
|
if block.lines == new_block.lines
|
68
|
-
|
69
|
+
nil
|
69
70
|
else
|
70
|
-
|
71
|
+
new_block
|
71
72
|
end
|
72
73
|
end
|
73
74
|
end
|