what_weve_got_here_is_an_error_to_communicate 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +1 -0
- data/Readme.md +9 -7
- data/experiments/formatting/other_resources +7 -0
- data/lib/error_to_communicate/at_exit.rb +15 -9
- data/lib/error_to_communicate/config.rb +55 -22
- data/lib/error_to_communicate/exception_info.rb +86 -31
- data/lib/error_to_communicate/format_terminal.rb +146 -0
- data/lib/error_to_communicate/heuristic/exception.rb +22 -0
- data/lib/error_to_communicate/heuristic/load_error.rb +57 -0
- data/lib/error_to_communicate/heuristic/no_method_error.rb +35 -0
- data/lib/error_to_communicate/heuristic/syntax_error.rb +55 -0
- data/lib/error_to_communicate/heuristic/wrong_number_of_arguments.rb +73 -0
- data/lib/error_to_communicate/heuristic.rb +54 -0
- data/lib/error_to_communicate/project.rb +50 -0
- data/lib/error_to_communicate/rspec_formatter.rb +8 -9
- data/lib/error_to_communicate/theme.rb +137 -0
- data/lib/error_to_communicate/version.rb +2 -2
- data/lib/error_to_communicate.rb +4 -2
- data/spec/acceptance/exception_spec.rb +2 -4
- data/spec/acceptance/load_error_spec.rb +23 -0
- data/spec/acceptance/name_error_spec.rb +46 -0
- data/spec/acceptance/no_methood_error_spec.rb +6 -8
- data/spec/acceptance/runtime_error_spec.rb +27 -0
- data/spec/acceptance/short_and_long_require_spec.rb +29 -0
- data/spec/acceptance/spec_helper.rb +4 -3
- data/spec/acceptance/syntax_error_spec.rb +32 -0
- data/spec/acceptance/{argument_error_spec.rb → wrong_number_of_arguments_spec.rb} +1 -1
- data/spec/config_spec.rb +120 -0
- data/spec/heuristic/exception_spec.rb +17 -0
- data/spec/heuristic/load_error_spec.rb +195 -0
- data/spec/heuristic/no_method_error_spec.rb +25 -0
- data/spec/heuristic/spec_helper.rb +33 -0
- data/spec/heuristic/wrong_number_of_arguments_spec.rb +115 -0
- data/spec/heuristic_spec.rb +76 -0
- data/spec/parsing_exception_info_spec.rb +212 -0
- data/spec/rspec_formatter_spec.rb +3 -1
- data/spec/spec_helper.rb +28 -1
- data/what_weve_got_here_is_an_error_to_communicate.gemspec +2 -2
- metadata +29 -19
- data/lib/error_to_communicate/format/terminal_helpers.rb +0 -97
- data/lib/error_to_communicate/format.rb +0 -132
- data/lib/error_to_communicate/parse/backtrace.rb +0 -34
- data/lib/error_to_communicate/parse/exception.rb +0 -21
- data/lib/error_to_communicate/parse/no_method_error.rb +0 -27
- data/lib/error_to_communicate/parse/registry.rb +0 -30
- data/lib/error_to_communicate/parse/wrong_number_of_arguments.rb +0 -35
- data/spec/parse/backtrace_spec.rb +0 -101
- data/spec/parse/exception_spec.rb +0 -14
- data/spec/parse/no_method_error_spec.rb +0 -23
- data/spec/parse/registered_parsers_spec.rb +0 -68
- data/spec/parse/spec_helper.rb +0 -23
- data/spec/parse/wrong_number_of_arguments_spec.rb +0 -77
@@ -1,27 +0,0 @@
|
|
1
|
-
require 'error_to_communicate/exception_info'
|
2
|
-
require 'error_to_communicate/parse/backtrace'
|
3
|
-
|
4
|
-
module WhatWeveGotHereIsAnErrorToCommunicate
|
5
|
-
module Parse
|
6
|
-
module NoMethodError
|
7
|
-
def self.parse?(exception)
|
8
|
-
exception.kind_of? ::NoMethodError
|
9
|
-
end
|
10
|
-
|
11
|
-
def self.parse(exception)
|
12
|
-
ExceptionInfo::NoMethodError.new(
|
13
|
-
exception: exception,
|
14
|
-
classname: exception.class.to_s,
|
15
|
-
explanation: exception.message[/^[^\(]*/].strip,
|
16
|
-
backtrace: Backtrace.parse(exception),
|
17
|
-
undefined_method_name: extract_method_name(exception.message),
|
18
|
-
)
|
19
|
-
end
|
20
|
-
|
21
|
-
def self.extract_method_name(message)
|
22
|
-
words = message.split(/\s+/)
|
23
|
-
words[2][1...-1]
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
module WhatWeveGotHereIsAnErrorToCommunicate
|
2
|
-
module Parse
|
3
|
-
class Registry
|
4
|
-
def initialize(options)
|
5
|
-
@dont_parse = options.fetch :dont_parse
|
6
|
-
@parsers = options.fetch :parsers
|
7
|
-
end
|
8
|
-
|
9
|
-
def <<(parser)
|
10
|
-
@parsers << parser
|
11
|
-
self
|
12
|
-
end
|
13
|
-
|
14
|
-
def parser_for(exception)
|
15
|
-
return nil if @dont_parse.call exception
|
16
|
-
@parsers.find { |parser| parser.parse? exception }
|
17
|
-
end
|
18
|
-
|
19
|
-
def parse?(exception)
|
20
|
-
!!parser_for(exception)
|
21
|
-
end
|
22
|
-
|
23
|
-
def parse(exception)
|
24
|
-
parser = @parsers.find { |parser| parser.parse? exception }
|
25
|
-
return parser.parse exception if parser
|
26
|
-
raise ::ArgumentError.new, "No parser found for #{exception.inspect}"
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
@@ -1,35 +0,0 @@
|
|
1
|
-
require 'error_to_communicate/exception_info'
|
2
|
-
require 'error_to_communicate/parse/backtrace'
|
3
|
-
|
4
|
-
module WhatWeveGotHereIsAnErrorToCommunicate
|
5
|
-
module Parse
|
6
|
-
module WrongNumberOfArguments
|
7
|
-
def self.parse?(exception)
|
8
|
-
exception.respond_to?(:message) && extract_from(exception)
|
9
|
-
end
|
10
|
-
|
11
|
-
def self.parse(exception)
|
12
|
-
num_received, num_expected = extract_from(exception)
|
13
|
-
ExceptionInfo::WrongNumberOfArguments.new(
|
14
|
-
exception: exception,
|
15
|
-
classname: exception.class.to_s,
|
16
|
-
explanation: 'Wrong number of arguments',
|
17
|
-
backtrace: Backtrace.parse(exception),
|
18
|
-
num_expected: num_expected,
|
19
|
-
num_received: num_received,
|
20
|
-
)
|
21
|
-
end
|
22
|
-
|
23
|
-
private
|
24
|
-
|
25
|
-
def self.extract_from(exception)
|
26
|
-
case exception.message
|
27
|
-
when /^wrong number of arguments.*?\((\d+) for (\d+)\)$/ # MRI / JRuby
|
28
|
-
num_received, num_expected = $1.to_i, $2.to_i
|
29
|
-
when /^method '.*?': given (\d+).*? expected (\d+)$/ # RBX
|
30
|
-
num_received, num_expected = $1.to_i, $2.to_i
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
@@ -1,101 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'error_to_communicate/parse/backtrace'
|
3
|
-
|
4
|
-
RSpec.describe 'parsing an ArgumentError', parse: true do
|
5
|
-
let :exception do
|
6
|
-
FakeException.new backtrace: [
|
7
|
-
"file.rb:111:in `method1'",
|
8
|
-
"file.rb:222:in `method2'",
|
9
|
-
"file.rb:333:in `method3'"
|
10
|
-
]
|
11
|
-
end
|
12
|
-
|
13
|
-
def parse(exception)
|
14
|
-
WhatWeveGotHereIsAnErrorToCommunicate::Parse::Backtrace.parse(exception)
|
15
|
-
end
|
16
|
-
|
17
|
-
it 'records the linenum, and label of each backtrace location' do
|
18
|
-
locations = parse exception
|
19
|
-
expect(locations.map &:linenum).to eq [111, 222, 333]
|
20
|
-
expect(locations.map &:label).to eq %w[method1 method2 method3]
|
21
|
-
end
|
22
|
-
|
23
|
-
specify 'the predecessor is the parsed location from the previous index, or nil for the first' do
|
24
|
-
l1, l2, l3 = locations = parse(exception)
|
25
|
-
expect(locations.map &:pred).to eq [nil, l1, l2]
|
26
|
-
end
|
27
|
-
|
28
|
-
specify 'the successor is the parsed locations from the next index, or nil for the last' do
|
29
|
-
l1, l2, l3 = locations = parse(exception)
|
30
|
-
expect(locations.map &:succ).to eq [l2, l3, nil]
|
31
|
-
end
|
32
|
-
|
33
|
-
# it 'records the absolute filepath if it can find the file'
|
34
|
-
# it 'records the relative filepath if it can find the file'
|
35
|
-
# it 'records the relative filepath if it cannot fild the file'
|
36
|
-
|
37
|
-
def assert_parses_line(line, assertions)
|
38
|
-
parsed = WhatWeveGotHereIsAnErrorToCommunicate::Parse::Backtrace.parse_backtrace_line(line)
|
39
|
-
assertions.each do |method_name, expected|
|
40
|
-
actual = parsed.__send__ method_name
|
41
|
-
expect(actual).to eq expected
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
it 'records the path whether its absolute or relative' do
|
46
|
-
assert_parses_line "file.rb:111:in `method1'", path: "file.rb"
|
47
|
-
assert_parses_line "/file.rb:111:in `method1'", path: "/file.rb"
|
48
|
-
end
|
49
|
-
|
50
|
-
it 'does not get confused by numbers in directories, filenames, or method names' do
|
51
|
-
line = "/a1/b2/c3123/file123.rb:111:in `method1'"
|
52
|
-
assert_parses_line line, path: "/a1/b2/c3123/file123.rb"
|
53
|
-
assert_parses_line line, linenum: 111
|
54
|
-
assert_parses_line line, label: "method1"
|
55
|
-
end
|
56
|
-
|
57
|
-
context 'random ass colons in the middle of like files and directories and shit' do
|
58
|
-
# $ mkdir 'a:b'
|
59
|
-
# $ echo 'begin; define_method("a:b") { |arg| }; send "a:b"; rescue Exception; p $!.backtrace; end' > 'a:b/c:d.rb'
|
60
|
-
|
61
|
-
# $ chruby-exec 2.2 -- ruby -v
|
62
|
-
# > ruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-darwin13]
|
63
|
-
#
|
64
|
-
# $ chruby-exec 2.2 -- ruby 'a:b/c:d.rb'
|
65
|
-
# > ["a:b/c:d.rb:1:in `block in <main>'", "a:b/c:d.rb:1:in `<main>'"]
|
66
|
-
it 'does not get confused with MRI style results' do
|
67
|
-
line = "a:b/c:d.rb:1:in `block in <main>'"
|
68
|
-
assert_parses_line line, path: "a:b/c:d.rb"
|
69
|
-
assert_parses_line line, linenum: 1
|
70
|
-
assert_parses_line line, label: "block in <main>"
|
71
|
-
end
|
72
|
-
|
73
|
-
# $ chruby-exec rbx -- ruby -v
|
74
|
-
# > rubinius 2.5.0 (2.1.0 50777f41 2015-01-17 3.5.0 JI) [x86_64-darwin14.1.0]
|
75
|
-
#
|
76
|
-
# $ chruby-exec rbx -- ruby 'a:b/c:d.rb'
|
77
|
-
# > ["a:b/c:d.rb:1:in `__script__'",
|
78
|
-
# "kernel/delta/code_loader.rb:66:in `load_script'",
|
79
|
-
# "kernel/delta/code_loader.rb:152:in `load_script'",
|
80
|
-
# "kernel/loader.rb:645:in `script'",
|
81
|
-
# "kernel/loader.rb:799:in `main'"]
|
82
|
-
it 'does not get confused with RBX style results' do
|
83
|
-
line = "a:b/c:d.rb:1:in `__script__'"
|
84
|
-
assert_parses_line line, path: "a:b/c:d.rb"
|
85
|
-
assert_parses_line line, linenum: 1
|
86
|
-
assert_parses_line line, label: "__script__"
|
87
|
-
end
|
88
|
-
|
89
|
-
# $ chruby-exec jruby -- ruby -v
|
90
|
-
# > jruby 1.7.16 (1.9.3p392) 2014-09-25 575b395 on Java HotSpot(TM) 64-Bit Server VM 1.7.0_51-b13 +jit [darwin-x86_64]
|
91
|
-
#
|
92
|
-
# $ chruby-exec jruby -- ruby 'a:b/c:d.rb'
|
93
|
-
# > ["a:b/c:d.rb:1:in `(root)'"]
|
94
|
-
it 'does not get confused by Jruby style results' do
|
95
|
-
line = "a:b/c:d.rb:1:in `(root)'"
|
96
|
-
assert_parses_line line, path: "a:b/c:d.rb"
|
97
|
-
assert_parses_line line, linenum: 1
|
98
|
-
assert_parses_line line, label: "(root)"
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
require 'parse/spec_helper'
|
2
|
-
require 'error_to_communicate/parse/exception'
|
3
|
-
|
4
|
-
RSpec.describe 'parsing an Exception', parse: true do
|
5
|
-
def parse(exception)
|
6
|
-
WhatWeveGotHereIsAnErrorToCommunicate::Parse::Exception.parse(exception)
|
7
|
-
end
|
8
|
-
|
9
|
-
it_behaves_like 'an exception parser', sample_message: 'literally anything'
|
10
|
-
|
11
|
-
# Going to wait on implementing these as they may not be correct,
|
12
|
-
# e.g. anyone can raise an argument error for any reason.
|
13
|
-
it 'extracts the name of the method that was called'
|
14
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
require 'parse/spec_helper'
|
2
|
-
require 'error_to_communicate/parse/no_method_error'
|
3
|
-
|
4
|
-
RSpec.describe 'parsing a NoMethodError', parse: true do
|
5
|
-
def error_class
|
6
|
-
WhatWeveGotHereIsAnErrorToCommunicate::Parse::NoMethodError
|
7
|
-
end
|
8
|
-
|
9
|
-
def parse(exception)
|
10
|
-
error_class.parse(exception)
|
11
|
-
end
|
12
|
-
|
13
|
-
it_behaves_like 'an exception parser', sample_message: "undefined method `<' for nil:NilClass"
|
14
|
-
|
15
|
-
def extracts_method_name!(expected, message)
|
16
|
-
actual = error_class.extract_method_name(message)
|
17
|
-
expect(actual).to eq expected
|
18
|
-
end
|
19
|
-
|
20
|
-
it 'extracts the name of the method that was called' do
|
21
|
-
extracts_method_name! '<', "undefined method `<' for nil:NilClass"
|
22
|
-
end
|
23
|
-
end
|
@@ -1,68 +0,0 @@
|
|
1
|
-
require 'error_to_communicate/config'
|
2
|
-
|
3
|
-
RSpec.describe 'registered parsers', parse: true do
|
4
|
-
p = WhatWeveGotHereIsAnErrorToCommunicate::Parse
|
5
|
-
|
6
|
-
def capture
|
7
|
-
yield
|
8
|
-
raise 'NO EXCEPTION WAS RAISED!'
|
9
|
-
rescue Exception
|
10
|
-
return $!
|
11
|
-
end
|
12
|
-
|
13
|
-
describe 'selected parsers' do
|
14
|
-
def parser_for(exception)
|
15
|
-
WhatWeveGotHereIsAnErrorToCommunicate::Config
|
16
|
-
.new.registry.parser_for(exception)
|
17
|
-
end
|
18
|
-
|
19
|
-
it 'doesn\'t parse nil' do
|
20
|
-
expect(parser_for nil).to eq nil
|
21
|
-
end
|
22
|
-
|
23
|
-
it 'doesn\'t parse a SystemExit' do
|
24
|
-
err = capture { exit }
|
25
|
-
expect(parser_for err).to eq nil
|
26
|
-
|
27
|
-
err = capture { exit 1 }
|
28
|
-
expect(parser_for err).to eq nil
|
29
|
-
end
|
30
|
-
|
31
|
-
it 'parses wrong number of arguments' do
|
32
|
-
err = capture { lambda { }.call :arg }
|
33
|
-
expect(parser_for err).to eq p::WrongNumberOfArguments
|
34
|
-
end
|
35
|
-
|
36
|
-
it 'parses NoMethodErrors' do
|
37
|
-
err = capture { sdfsdfsdf() }
|
38
|
-
expect(parser_for err).to eq p::NoMethodError
|
39
|
-
end
|
40
|
-
|
41
|
-
it 'lets ArgumentErrors that are not wrong number of arguments fall through', t:true do
|
42
|
-
err = capture { raise ArgumentError, "zomg" }
|
43
|
-
expect(parser_for err).to eq p::Exception
|
44
|
-
end
|
45
|
-
|
46
|
-
it 'parses Exception' do
|
47
|
-
err = capture { raise Exception, "wat" }
|
48
|
-
expect(parser_for err).to eq p::Exception
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
describe 'config.parse' do
|
53
|
-
def parse(exception)
|
54
|
-
WhatWeveGotHereIsAnErrorToCommunicate::Config
|
55
|
-
.new.parse(exception)
|
56
|
-
end
|
57
|
-
|
58
|
-
it 'parses the exception if anything is willing to do it' do
|
59
|
-
exception = capture { sdfsdfsdf() }
|
60
|
-
exception_info = parse exception
|
61
|
-
expect(exception_info.exception).to equal exception
|
62
|
-
end
|
63
|
-
|
64
|
-
it 'raises an ArgumentError if there are no parsers for this exception' do
|
65
|
-
expect { parse "not an error" }.to raise_error ArgumentError, /"not an error"/
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
data/spec/parse/spec_helper.rb
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
RSpec.shared_examples 'an exception parser' do |attributes|
|
4
|
-
let(:message) { attributes.fetch :sample_message }
|
5
|
-
let(:explanation) { attributes.fetch :sample_explanation, message }
|
6
|
-
|
7
|
-
let :exception do
|
8
|
-
FakeException.new message: message,
|
9
|
-
backtrace: ["/Users/someone/a/b/c.rb:123:in `some_method_name'"]
|
10
|
-
end
|
11
|
-
|
12
|
-
it 'records the exception, class name, and explanation comes from the message' do
|
13
|
-
info = parse exception
|
14
|
-
expect(info.exception ).to equal exception
|
15
|
-
expect(info.classname ).to eq 'FakeException'
|
16
|
-
expect(info.explanation).to eq explanation
|
17
|
-
end
|
18
|
-
|
19
|
-
it 'records the backtrace locations' do
|
20
|
-
info = parse exception
|
21
|
-
expect(info.backtrace.map &:linenum).to eq [123]
|
22
|
-
end
|
23
|
-
end
|
@@ -1,77 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'parse/spec_helper'
|
3
|
-
require 'error_to_communicate/parse/wrong_number_of_arguments'
|
4
|
-
|
5
|
-
RSpec.describe 'parsing wrong number of arguments', parse: true do
|
6
|
-
def parse(exception)
|
7
|
-
WhatWeveGotHereIsAnErrorToCommunicate::Parse::WrongNumberOfArguments.parse(exception)
|
8
|
-
end
|
9
|
-
|
10
|
-
it_behaves_like 'an exception parser',
|
11
|
-
sample_message: "wrong number of arguments (1 for 0) (ArgumentError)",
|
12
|
-
sample_explanation: "Wrong number of arguments"
|
13
|
-
|
14
|
-
describe 'parse?' do
|
15
|
-
def will_parse?(exception)
|
16
|
-
WhatWeveGotHereIsAnErrorToCommunicate::Parse::WrongNumberOfArguments.parse?(exception)
|
17
|
-
end
|
18
|
-
|
19
|
-
def will_parse!(exception)
|
20
|
-
expect(will_parse? exception).to be_truthy
|
21
|
-
end
|
22
|
-
|
23
|
-
def wont_parse!(exception)
|
24
|
-
expect(will_parse? exception).to be_falsy
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'is true when given an MRI style wrong number of arguments message' do
|
28
|
-
will_parse! ArgumentError.new "wrong number of arguments (1 for 0)"
|
29
|
-
end
|
30
|
-
|
31
|
-
it 'is true when given an RBX style wrong number of arguments message' do
|
32
|
-
will_parse! ArgumentError.new "method 'a': given 1, expected 0"
|
33
|
-
end
|
34
|
-
|
35
|
-
it 'is true when given an JRuby style wrong number of arguments message' do
|
36
|
-
will_parse! ArgumentError.new "wrong number of arguments calling `a` (1 for 0)"
|
37
|
-
end
|
38
|
-
|
39
|
-
it 'is true when given an MRI style wrong number of arguments message' do
|
40
|
-
will_parse! ArgumentError.new "wrong number of arguments (1 for 0)"
|
41
|
-
end
|
42
|
-
|
43
|
-
it 'is false for ArgumentErrors that are not "wrong number of arguments"' do
|
44
|
-
wont_parse! ArgumentError.new "Some other kind of ArgumentError"
|
45
|
-
end
|
46
|
-
|
47
|
-
it 'is false when the message is contained within some other message (not overeager)' do
|
48
|
-
wont_parse! RSpec::Expectations::ExpectationNotMetError.new(<<-MESSAGE)
|
49
|
-
expected: "wrong number of arguments (1 for 0) (ArgumentError)"
|
50
|
-
got: "Wrong number of arguments"
|
51
|
-
|
52
|
-
(compared using ==)
|
53
|
-
MESSAGE
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
describe 'parse' do
|
58
|
-
let(:mri_message) { "wrong number of arguments (1 for 0)" }
|
59
|
-
let(:mri_parsed) { parse FakeException.new(message: mri_message) }
|
60
|
-
|
61
|
-
let(:rbx_message) { "method 'a': given 1, expected 0" }
|
62
|
-
let(:rbx_parsed) { parse FakeException.new(message: rbx_message) }
|
63
|
-
|
64
|
-
let(:jruby_message) { "wrong number of arguments calling `a` (1 for 0)" }
|
65
|
-
let(:jruby_parsed) { parse FakeException.new(message: "wrong number of arguments calling `a` (1 for 0)") }
|
66
|
-
|
67
|
-
it 'extracts the number of arguments that were passed' do
|
68
|
-
expect(rbx_parsed.num_expected).to eq 0
|
69
|
-
expect(mri_parsed.num_expected).to eq 0
|
70
|
-
end
|
71
|
-
|
72
|
-
it 'extracts the number of arguments that were received' do
|
73
|
-
expect(rbx_parsed.num_received).to eq 1
|
74
|
-
expect(mri_parsed.num_received).to eq 1
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|