dead_end 2.0.2 → 3.0.0
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/CHANGELOG.md +10 -0
- data/Gemfile.lock +1 -1
- data/README.md +89 -21
- data/exe/dead_end +3 -77
- data/lib/dead_end/auto.rb +1 -21
- data/lib/dead_end/cli.rb +118 -0
- data/lib/dead_end/code_block.rb +18 -2
- data/lib/dead_end/code_frontier.rb +29 -3
- data/lib/dead_end/code_search.rb +6 -5
- data/lib/dead_end/display_invalid_blocks.rb +37 -46
- data/lib/dead_end/explain_syntax.rb +103 -0
- data/lib/dead_end/left_right_lex_count.rb +157 -0
- data/lib/dead_end/ripper_errors.rb +30 -0
- data/lib/dead_end/version.rb +1 -1
- data/lib/dead_end.rb +145 -1
- metadata +6 -6
- data/lib/dead_end/banner.rb +0 -58
- data/lib/dead_end/fyi.rb +0 -8
- data/lib/dead_end/internals.rb +0 -157
- data/lib/dead_end/who_dis_syntax_error.rb +0 -83
@@ -0,0 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "left_right_lex_count"
|
4
|
+
|
5
|
+
module DeadEnd
|
6
|
+
# Explains syntax errors based on their source
|
7
|
+
#
|
8
|
+
# example:
|
9
|
+
#
|
10
|
+
# source = "def foo; puts 'lol'" # Note missing end
|
11
|
+
# explain ExplainSyntax.new(
|
12
|
+
# code_lines: CodeLine.from_source(source)
|
13
|
+
# ).call
|
14
|
+
# explain.errors.first
|
15
|
+
# # => "Unmatched keyword, missing `end' ?"
|
16
|
+
#
|
17
|
+
# When the error cannot be determined by lexical counting
|
18
|
+
# then ripper is run against the input and the raw ripper
|
19
|
+
# errors returned.
|
20
|
+
#
|
21
|
+
# Example:
|
22
|
+
#
|
23
|
+
# source = "1 * " # Note missing a second number
|
24
|
+
# explain ExplainSyntax.new(
|
25
|
+
# code_lines: CodeLine.from_source(source)
|
26
|
+
# ).call
|
27
|
+
# explain.errors.first
|
28
|
+
# # => "syntax error, unexpected end-of-input"
|
29
|
+
class ExplainSyntax
|
30
|
+
INVERSE = {
|
31
|
+
"{" => "}",
|
32
|
+
"}" => "{",
|
33
|
+
"[" => "]",
|
34
|
+
"]" => "[",
|
35
|
+
"(" => ")",
|
36
|
+
")" => "(",
|
37
|
+
"|" => "|"
|
38
|
+
}.freeze
|
39
|
+
|
40
|
+
def initialize(code_lines:)
|
41
|
+
@code_lines = code_lines
|
42
|
+
@left_right = LeftRightLexCount.new
|
43
|
+
@missing = nil
|
44
|
+
end
|
45
|
+
|
46
|
+
def call
|
47
|
+
@code_lines.each do |line|
|
48
|
+
line.lex.each do |lex|
|
49
|
+
@left_right.count_lex(lex)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
self
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns an array of missing elements
|
57
|
+
#
|
58
|
+
# For example this:
|
59
|
+
#
|
60
|
+
# ExplainSyntax.new(code_lines: lines).missing
|
61
|
+
# # => ["}"]
|
62
|
+
#
|
63
|
+
# Would indicate that the source is missing
|
64
|
+
# a `}` character in the source code
|
65
|
+
def missing
|
66
|
+
@missing ||= @left_right.missing
|
67
|
+
end
|
68
|
+
|
69
|
+
# Converts a missing string to
|
70
|
+
# an human understandable explanation.
|
71
|
+
#
|
72
|
+
# Example:
|
73
|
+
#
|
74
|
+
# explain.why("}")
|
75
|
+
# # => "Unmatched `{', missing `}' ?"
|
76
|
+
#
|
77
|
+
def why(miss)
|
78
|
+
case miss
|
79
|
+
when "keyword"
|
80
|
+
"Unmatched `end', missing keyword (`do', `def`, `if`, etc.) ?"
|
81
|
+
when "end"
|
82
|
+
"Unmatched keyword, missing `end' ?"
|
83
|
+
else
|
84
|
+
inverse = INVERSE.fetch(miss) {
|
85
|
+
raise "Unknown explain syntax char or key: #{miss.inspect}"
|
86
|
+
}
|
87
|
+
"Unmatched `#{inverse}', missing `#{miss}' ?"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# Returns an array of syntax error messages
|
92
|
+
#
|
93
|
+
# If no missing pairs are found it falls back
|
94
|
+
# on the original ripper error messages
|
95
|
+
def errors
|
96
|
+
if missing.empty?
|
97
|
+
return RipperErrors.new(@code_lines.map(&:original).join).call.errors
|
98
|
+
end
|
99
|
+
|
100
|
+
missing.map { |miss| why(miss) }
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DeadEnd
|
4
|
+
# Find mis-matched syntax based on lexical count
|
5
|
+
#
|
6
|
+
# Used for detecting missing pairs of elements
|
7
|
+
# each keyword needs an end, each '{' needs a '}'
|
8
|
+
# etc.
|
9
|
+
#
|
10
|
+
# Example:
|
11
|
+
#
|
12
|
+
# left_right = LeftRightLexCount.new
|
13
|
+
# left_right.count_kw
|
14
|
+
# left_right.missing.first
|
15
|
+
# # => "end"
|
16
|
+
#
|
17
|
+
# left_right = LeftRightLexCount.new
|
18
|
+
# source = "{ a: b, c: d" # Note missing '}'
|
19
|
+
# LexAll.new(source: source).each do |lex|
|
20
|
+
# left_right.count_lex(lex)
|
21
|
+
# end
|
22
|
+
# left_right.missing.first
|
23
|
+
# # => "}"
|
24
|
+
class LeftRightLexCount
|
25
|
+
def initialize
|
26
|
+
@kw_count = 0
|
27
|
+
@end_count = 0
|
28
|
+
|
29
|
+
@count_for_char = {
|
30
|
+
"{" => 0,
|
31
|
+
"}" => 0,
|
32
|
+
"[" => 0,
|
33
|
+
"]" => 0,
|
34
|
+
"(" => 0,
|
35
|
+
")" => 0,
|
36
|
+
"|" => 0
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
def count_kw
|
41
|
+
@kw_count += 1
|
42
|
+
end
|
43
|
+
|
44
|
+
def count_end
|
45
|
+
@end_count += 1
|
46
|
+
end
|
47
|
+
|
48
|
+
# Count source code characters
|
49
|
+
#
|
50
|
+
# Example:
|
51
|
+
#
|
52
|
+
# left_right = LeftRightLexCount.new
|
53
|
+
# left_right.count_lex(LexValue.new(1, :on_lbrace, "{", Ripper::EXPR_BEG))
|
54
|
+
# left_right.count_for_char("{")
|
55
|
+
# # => 1
|
56
|
+
# left_right.count_for_char("}")
|
57
|
+
# # => 0
|
58
|
+
def count_lex(lex)
|
59
|
+
case lex.type
|
60
|
+
when :on_tstring_content
|
61
|
+
# ^^^
|
62
|
+
# Means it's a string or a symbol `"{"` rather than being
|
63
|
+
# part of a data structure (like a hash) `{ a: b }`
|
64
|
+
when :on_embexpr_beg
|
65
|
+
# ^^^
|
66
|
+
# Embedded string expressions like `"#{foo} <-embed"`
|
67
|
+
# are parsed with chars:
|
68
|
+
#
|
69
|
+
# `#{` as :on_embexpr_beg
|
70
|
+
# `}` as :on_embexpr_end
|
71
|
+
#
|
72
|
+
# We cannot ignore both :on_emb_expr_beg and :on_embexpr_end
|
73
|
+
# because sometimes the lexer thinks something is an embed
|
74
|
+
# string end, when it is not like `lol = }` (no clue why).
|
75
|
+
#
|
76
|
+
# When we see `#{` count it as a `{` or we will
|
77
|
+
# have a mis-match count.
|
78
|
+
#
|
79
|
+
case lex.token
|
80
|
+
when "\#{"
|
81
|
+
@count_for_char["{"] += 1
|
82
|
+
end
|
83
|
+
else
|
84
|
+
@end_count += 1 if lex.is_end?
|
85
|
+
@kw_count += 1 if lex.is_kw?
|
86
|
+
@count_for_char[lex.token] += 1 if @count_for_char.key?(lex.token)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def count_for_char(char)
|
91
|
+
@count_for_char[char]
|
92
|
+
end
|
93
|
+
|
94
|
+
# Returns an array of missing syntax characters
|
95
|
+
# or `"end"` or `"keyword"`
|
96
|
+
#
|
97
|
+
# left_right.missing
|
98
|
+
# # => ["}"]
|
99
|
+
def missing
|
100
|
+
out = missing_pairs
|
101
|
+
out << missing_pipe
|
102
|
+
out << missing_keyword_end
|
103
|
+
out.compact!
|
104
|
+
out
|
105
|
+
end
|
106
|
+
|
107
|
+
PAIRS = {
|
108
|
+
"{" => "}",
|
109
|
+
"[" => "]",
|
110
|
+
"(" => ")"
|
111
|
+
}.freeze
|
112
|
+
|
113
|
+
# Opening characters like `{` need closing characters # like `}`.
|
114
|
+
#
|
115
|
+
# When a mis-match count is detected, suggest the
|
116
|
+
# missing member.
|
117
|
+
#
|
118
|
+
# For example if there are 3 `}` and only two `{`
|
119
|
+
# return `"{"`
|
120
|
+
private def missing_pairs
|
121
|
+
PAIRS.map do |(left, right)|
|
122
|
+
case @count_for_char[left] <=> @count_for_char[right]
|
123
|
+
when 1
|
124
|
+
right
|
125
|
+
when 0
|
126
|
+
nil
|
127
|
+
when -1
|
128
|
+
left
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# Keywords need ends and ends need keywords
|
134
|
+
#
|
135
|
+
# If we have more keywords, there's a missing `end`
|
136
|
+
# if we have more `end`-s, there's a missing keyword
|
137
|
+
private def missing_keyword_end
|
138
|
+
case @kw_count <=> @end_count
|
139
|
+
when 1
|
140
|
+
"end"
|
141
|
+
when 0
|
142
|
+
nil
|
143
|
+
when -1
|
144
|
+
"keyword"
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# Pipes come in pairs.
|
149
|
+
# If there's an odd number of pipes then we
|
150
|
+
# are missing one
|
151
|
+
private def missing_pipe
|
152
|
+
if @count_for_char["|"].odd?
|
153
|
+
"|"
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DeadEnd
|
4
|
+
# Capture parse errors from ripper
|
5
|
+
#
|
6
|
+
# Example:
|
7
|
+
#
|
8
|
+
# puts RipperErrors.new(" def foo").call.errors
|
9
|
+
# # => ["syntax error, unexpected end-of-input, expecting ';' or '\\n'"]
|
10
|
+
class RipperErrors < Ripper
|
11
|
+
attr_reader :errors
|
12
|
+
|
13
|
+
# Comes from ripper, called
|
14
|
+
# on every parse error, msg
|
15
|
+
# is a string
|
16
|
+
def on_parse_error(msg)
|
17
|
+
@errors ||= []
|
18
|
+
@errors << msg
|
19
|
+
end
|
20
|
+
|
21
|
+
def call
|
22
|
+
@run_once ||= begin
|
23
|
+
@errors = []
|
24
|
+
parse
|
25
|
+
true
|
26
|
+
end
|
27
|
+
self
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/dead_end/version.rb
CHANGED
data/lib/dead_end.rb
CHANGED
@@ -1,4 +1,148 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "dead_end/
|
3
|
+
require_relative "dead_end/version"
|
4
|
+
|
5
|
+
require "tmpdir"
|
6
|
+
require "stringio"
|
7
|
+
require "pathname"
|
8
|
+
require "ripper"
|
9
|
+
require "timeout"
|
10
|
+
|
11
|
+
module DeadEnd
|
12
|
+
# Used to indicate a default value that cannot
|
13
|
+
# be confused with another input
|
14
|
+
DEFAULT_VALUE = Object.new.freeze
|
15
|
+
|
16
|
+
class Error < StandardError; end
|
17
|
+
TIMEOUT_DEFAULT = ENV.fetch("DEAD_END_TIMEOUT", 1).to_i
|
18
|
+
|
19
|
+
def self.handle_error(e)
|
20
|
+
filename = e.message.split(":").first
|
21
|
+
$stderr.sync = true
|
22
|
+
|
23
|
+
call(
|
24
|
+
source: Pathname(filename).read,
|
25
|
+
filename: filename
|
26
|
+
)
|
27
|
+
|
28
|
+
raise e
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.call(source:, filename: DEFAULT_VALUE, terminal: DEFAULT_VALUE, record_dir: nil, timeout: TIMEOUT_DEFAULT, io: $stderr)
|
32
|
+
search = nil
|
33
|
+
filename = nil if filename == DEFAULT_VALUE
|
34
|
+
Timeout.timeout(timeout) do
|
35
|
+
record_dir ||= ENV["DEBUG"] ? "tmp" : nil
|
36
|
+
search = CodeSearch.new(source, record_dir: record_dir).call
|
37
|
+
end
|
38
|
+
|
39
|
+
blocks = search.invalid_blocks
|
40
|
+
DisplayInvalidBlocks.new(
|
41
|
+
io: io,
|
42
|
+
blocks: blocks,
|
43
|
+
filename: filename,
|
44
|
+
terminal: terminal,
|
45
|
+
code_lines: search.code_lines
|
46
|
+
).call
|
47
|
+
rescue Timeout::Error => e
|
48
|
+
io.puts "Search timed out DEAD_END_TIMEOUT=#{timeout}, run with DEBUG=1 for more info"
|
49
|
+
io.puts e.backtrace.first(3).join($/)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Used for counting spaces
|
53
|
+
module SpaceCount
|
54
|
+
def self.indent(string)
|
55
|
+
string.split(/\S/).first&.length || 0
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# This will tell you if the `code_lines` would be valid
|
60
|
+
# if you removed the `without_lines`. In short it's a
|
61
|
+
# way to detect if we've found the lines with syntax errors
|
62
|
+
# in our document yet.
|
63
|
+
#
|
64
|
+
# code_lines = [
|
65
|
+
# CodeLine.new(line: "def foo\n", index: 0)
|
66
|
+
# CodeLine.new(line: " def bar\n", index: 1)
|
67
|
+
# CodeLine.new(line: "end\n", index: 2)
|
68
|
+
# ]
|
69
|
+
#
|
70
|
+
# DeadEnd.valid_without?(
|
71
|
+
# without_lines: code_lines[1],
|
72
|
+
# code_lines: code_lines
|
73
|
+
# ) # => true
|
74
|
+
#
|
75
|
+
# DeadEnd.valid?(code_lines) # => false
|
76
|
+
def self.valid_without?(without_lines:, code_lines:)
|
77
|
+
lines = code_lines - Array(without_lines).flatten
|
78
|
+
|
79
|
+
if lines.empty?
|
80
|
+
true
|
81
|
+
else
|
82
|
+
valid?(lines)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.invalid?(source)
|
87
|
+
source = source.join if source.is_a?(Array)
|
88
|
+
source = source.to_s
|
89
|
+
|
90
|
+
Ripper.new(source).tap(&:parse).error?
|
91
|
+
end
|
92
|
+
|
93
|
+
# Returns truthy if a given input source is valid syntax
|
94
|
+
#
|
95
|
+
# DeadEnd.valid?(<<~EOM) # => true
|
96
|
+
# def foo
|
97
|
+
# end
|
98
|
+
# EOM
|
99
|
+
#
|
100
|
+
# DeadEnd.valid?(<<~EOM) # => false
|
101
|
+
# def foo
|
102
|
+
# def bar # Syntax error here
|
103
|
+
# end
|
104
|
+
# EOM
|
105
|
+
#
|
106
|
+
# You can also pass in an array of lines and they'll be
|
107
|
+
# joined before evaluating
|
108
|
+
#
|
109
|
+
# DeadEnd.valid?(
|
110
|
+
# [
|
111
|
+
# "def foo\n",
|
112
|
+
# "end\n"
|
113
|
+
# ]
|
114
|
+
# ) # => true
|
115
|
+
#
|
116
|
+
# DeadEnd.valid?(
|
117
|
+
# [
|
118
|
+
# "def foo\n",
|
119
|
+
# " def bar\n", # Syntax error here
|
120
|
+
# "end\n"
|
121
|
+
# ]
|
122
|
+
# ) # => false
|
123
|
+
#
|
124
|
+
# As an FYI the CodeLine class instances respond to `to_s`
|
125
|
+
# so passing a CodeLine in as an object or as an array
|
126
|
+
# will convert it to it's code representation.
|
127
|
+
def self.valid?(source)
|
128
|
+
!invalid?(source)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
require_relative "dead_end/code_line"
|
133
|
+
require_relative "dead_end/code_block"
|
134
|
+
require_relative "dead_end/code_search"
|
135
|
+
require_relative "dead_end/code_frontier"
|
136
|
+
require_relative "dead_end/clean_document"
|
137
|
+
|
138
|
+
require_relative "dead_end/lex_all"
|
139
|
+
require_relative "dead_end/block_expand"
|
140
|
+
require_relative "dead_end/around_block_scan"
|
141
|
+
require_relative "dead_end/ripper_errors"
|
142
|
+
require_relative "dead_end/display_invalid_blocks"
|
143
|
+
require_relative "dead_end/parse_blocks_from_indent_line"
|
144
|
+
|
145
|
+
require_relative "dead_end/explain_syntax"
|
146
|
+
|
4
147
|
require_relative "dead_end/auto"
|
148
|
+
require_relative "dead_end/cli"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dead_end
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- schneems
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-11-03 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: When you get an "unexpected end" in your syntax this gem helps you find
|
14
14
|
it
|
@@ -38,23 +38,23 @@ files:
|
|
38
38
|
- lib/dead_end.rb
|
39
39
|
- lib/dead_end/around_block_scan.rb
|
40
40
|
- lib/dead_end/auto.rb
|
41
|
-
- lib/dead_end/banner.rb
|
42
41
|
- lib/dead_end/block_expand.rb
|
43
42
|
- lib/dead_end/capture_code_context.rb
|
44
43
|
- lib/dead_end/clean_document.rb
|
44
|
+
- lib/dead_end/cli.rb
|
45
45
|
- lib/dead_end/code_block.rb
|
46
46
|
- lib/dead_end/code_frontier.rb
|
47
47
|
- lib/dead_end/code_line.rb
|
48
48
|
- lib/dead_end/code_search.rb
|
49
49
|
- lib/dead_end/display_code_with_line_numbers.rb
|
50
50
|
- lib/dead_end/display_invalid_blocks.rb
|
51
|
-
- lib/dead_end/
|
52
|
-
- lib/dead_end/
|
51
|
+
- lib/dead_end/explain_syntax.rb
|
52
|
+
- lib/dead_end/left_right_lex_count.rb
|
53
53
|
- lib/dead_end/lex_all.rb
|
54
54
|
- lib/dead_end/lex_value.rb
|
55
55
|
- lib/dead_end/parse_blocks_from_indent_line.rb
|
56
|
+
- lib/dead_end/ripper_errors.rb
|
56
57
|
- lib/dead_end/version.rb
|
57
|
-
- lib/dead_end/who_dis_syntax_error.rb
|
58
58
|
homepage: https://github.com/zombocom/dead_end.git
|
59
59
|
licenses:
|
60
60
|
- MIT
|
data/lib/dead_end/banner.rb
DELETED
@@ -1,58 +0,0 @@
|
|
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
|
data/lib/dead_end/fyi.rb
DELETED
@@ -1,8 +0,0 @@
|
|
1
|
-
require_relative "../dead_end/internals"
|
2
|
-
|
3
|
-
require_relative "auto"
|
4
|
-
|
5
|
-
DeadEnd.send(:remove_const, :SEARCH_SOURCE_ON_ERROR_DEFAULT)
|
6
|
-
DeadEnd::SEARCH_SOURCE_ON_ERROR_DEFAULT = false
|
7
|
-
|
8
|
-
warn "DEPRECATED: calling `require 'dead_end/fyi'` is deprecated, `require 'dead_end'` instead"
|