what_weve_got_here_is_an_error_to_communicate 0.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 +7 -0
- data/.gitignore +11 -0
- data/.rspec +4 -0
- data/.travis.yml +7 -0
- data/Gemfile +2 -0
- data/Rakefile +6 -0
- data/Readme.md +34 -0
- data/acceptance +29 -0
- data/experiments/formatting/5_potential_structure_dsls.rb +88 -0
- data/experiments/formatting/half_thoughtout_dsl_for_toplevel_structure_of_argument_error.rb +43 -0
- data/experiments/formatting/haml_like_structure.rb +139 -0
- data/experiments/formatting/other_structures +156 -0
- data/lib/error_to_communicate.rb +3 -0
- data/lib/error_to_communicate/at_exit.rb +11 -0
- data/lib/error_to_communicate/config.rb +32 -0
- data/lib/error_to_communicate/exception_info.rb +41 -0
- data/lib/error_to_communicate/format.rb +132 -0
- data/lib/error_to_communicate/format/terminal_helpers.rb +97 -0
- data/lib/error_to_communicate/parse/backtrace.rb +34 -0
- data/lib/error_to_communicate/parse/exception.rb +21 -0
- data/lib/error_to_communicate/parse/no_method_error.rb +27 -0
- data/lib/error_to_communicate/parse/registry.rb +30 -0
- data/lib/error_to_communicate/parse/wrong_number_of_arguments.rb +35 -0
- data/lib/error_to_communicate/rspec_formatter.rb +46 -0
- data/lib/error_to_communicate/version.rb +3 -0
- data/lib/what_weve_got_here_is_an_error_to_communicate.rb +3 -0
- data/screenshot.png +0 -0
- data/spec/acceptance/argument_error_spec.rb +55 -0
- data/spec/acceptance/exception_spec.rb +29 -0
- data/spec/acceptance/no_error_spec.rb +44 -0
- data/spec/acceptance/no_methood_error_spec.rb +50 -0
- data/spec/acceptance/spec_helper.rb +41 -0
- data/spec/parse/backtrace_spec.rb +101 -0
- data/spec/parse/exception_spec.rb +14 -0
- data/spec/parse/no_method_error_spec.rb +23 -0
- data/spec/parse/registered_parsers_spec.rb +68 -0
- data/spec/parse/spec_helper.rb +23 -0
- data/spec/parse/wrong_number_of_arguments_spec.rb +77 -0
- data/spec/rspec_formatter_spec.rb +95 -0
- data/spec/spec_helper.rb +20 -0
- data/what_weve_got_here_is_an_error_to_communicate.gemspec +19 -0
- metadata +168 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6d8b74cd9d659e3218cc9ecad4a0fdbba80b6d07
|
4
|
+
data.tar.gz: eadb2da5ec5d00795c54b93bf8efd7e0304b017d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e060fb388519b4492109c8e31d1f723b6b3cdb939650b6a709348778cbf771f0cbd5f75ec7a866945d140308c58330c5436d464cd01254fea9c4272f4b87c126
|
7
|
+
data.tar.gz: 2df113222792975b9e4bdc07dbdb2190e1f4f67b1ef5b5daa6b13d2fbfaa675755abc92818e873c00e737efdacd84dd38f8790cb49ccac72d72ef23f12fefaa9
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
data/Readme.md
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
[](https://travis-ci.org/JoshCheek/what-we-ve-got-here-is-an-error-to-communicate)
|
2
|
+
|
3
|
+
What if error messages were compelling to read?
|
4
|
+
-----------------------------------------------
|
5
|
+
|
6
|
+
Blog explaining the code is [here](http://blog.turing.io/2015/01/18/what-we-ve-got-here-is-an-error-to-communicate/).
|
7
|
+
(or will be once it's merged).
|
8
|
+
|
9
|
+
A screenshot of the code rendering an `ArgumentError`.
|
10
|
+
|
11
|
+

|
12
|
+
|
13
|
+
This is a proof of concept
|
14
|
+
--------------------------
|
15
|
+
|
16
|
+
This isn't fit for real-world use.
|
17
|
+
If there is resonance in the community, I'll probably try to make it a real gem.
|
18
|
+
I'll have some time to do that during my next braeak in late march 2015.
|
19
|
+
|
20
|
+
Inspirations:
|
21
|
+
-------------
|
22
|
+
|
23
|
+
* I think initially this was inspired by Sarah Gray's talk at Software Craftsmanship North America:
|
24
|
+
[Visualizing Enumerable: Own Abstract Concepts Through Physicalization](https://vimeo.com/54860297)
|
25
|
+
* Got to thinking about it again with Kerri Miller, conversing at DCamp,
|
26
|
+
and then at Ruby Conf, she created [chatty_exceptions](https://github.com/kerrizor/chatty_exceptions)
|
27
|
+
which is in this same domain.
|
28
|
+
* Charlie Sommerville's [better_errors](https://rubygems.org/gems/better_errors)
|
29
|
+
gem gives you a nice interface like this for Rails.
|
30
|
+
|
31
|
+
License
|
32
|
+
--------
|
33
|
+
|
34
|
+
[<img src="http://www.wtfpl.net/wp-content/uploads/2012/12/wtfpl.svg" width="15" height="15" alt="WTFPL" /> Do what the fuck you want to.](http://www.wtfpl.net/)
|
data/acceptance
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
No error:
|
2
|
+
Given a file that doesn't error
|
3
|
+
No exception is printed
|
4
|
+
It exits with 0
|
5
|
+
|
6
|
+
Argument Error:
|
7
|
+
Given a file with three lines in the backtrace that explodes on the third
|
8
|
+
displaying the error:
|
9
|
+
It prints the exception class
|
10
|
+
It prints the message (reworded to be more obvious)
|
11
|
+
heuristic:
|
12
|
+
It displays the most recent line of code and the next 5
|
13
|
+
It displays the second most recent of the backtrace, and 5 lines of code before / after
|
14
|
+
backtrace:
|
15
|
+
It displays each line of the backtrace
|
16
|
+
It includes the code from that line
|
17
|
+
|
18
|
+
NoMethod Error:
|
19
|
+
Given a file with three lines in the backtrace that explodes on the third
|
20
|
+
displaying the error:
|
21
|
+
It prints the exception class
|
22
|
+
It prints the message (reworded to be more obvious) #<Object> has no method called #<method name>
|
23
|
+
heuristic:
|
24
|
+
It displays the line of the backtrace with the NoMethodError, and 5 lines of code before / after #This is where it blew up
|
25
|
+
It displays the second most recent of the backtrace, and 5 lines of code before / after #This is where the called started
|
26
|
+
backtrace:
|
27
|
+
It displays each line of the backtrace
|
28
|
+
It includes the code from that line
|
29
|
+
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# a bunch of different options for what the DSL could look like
|
2
|
+
|
3
|
+
def display_location(attributes)
|
4
|
+
formatter = attributes.fetch :formatter
|
5
|
+
location = attributes.fetch :location
|
6
|
+
path = Pathname.new location.path
|
7
|
+
line_index = location.linenum - 1
|
8
|
+
highlight = attributes.fetch :highlight, location.label # currently ignoring this, b/c we can't highlight into the middle of the syntax highlighted output
|
9
|
+
end_index = bound_num min: 0, num: line_index+attributes.fetch(:context).end
|
10
|
+
start_index = bound_num min: 0, num: line_index+attributes.fetch(:context).begin
|
11
|
+
annotation = attributes.fetch :annotation, ''
|
12
|
+
message_offset = line_index - start_index
|
13
|
+
emphasize_path = attributes.fetch(:emphasisis) == :path
|
14
|
+
raw_code = path.exist? && File.read(path).lines[start_index..end_index].join("")
|
15
|
+
|
16
|
+
# explicitly call begin to make the next call a node, call .end to leave
|
17
|
+
formatter
|
18
|
+
.begin.group(:path_with_code)
|
19
|
+
.begin.group(:path, emphasize_path&&:emphasize)
|
20
|
+
.text(:dir, path_to_dir(@cwd, path, '/'))
|
21
|
+
.text(:filename, path.basename)
|
22
|
+
.text(:separator, ":")
|
23
|
+
.text(:line_number, location.linenum)
|
24
|
+
.end
|
25
|
+
.begin.code(raw_code || "Can't find code")
|
26
|
+
.strip_indentation(true)
|
27
|
+
.language(:ruby)
|
28
|
+
.starting_linenum(start_index.next)
|
29
|
+
.if(raw_code).annotate(:error, annotate, line: message_offset)
|
30
|
+
.end
|
31
|
+
.end
|
32
|
+
|
33
|
+
# leaves get !, use .end to end a node
|
34
|
+
formatter
|
35
|
+
.group(:path_with_code)
|
36
|
+
.group(:path, emphasize_path&&:emphasize)
|
37
|
+
.text!(:dir, path_to_dir(@cwd, path, '/'))
|
38
|
+
.text!(:filename, path.basename)
|
39
|
+
.text!(:separator, ":")
|
40
|
+
.text!(:line_number, location.linenum)
|
41
|
+
.end
|
42
|
+
.code(raw_code || "Can't find code")
|
43
|
+
.strip_indentation!
|
44
|
+
.language!(:ruby)
|
45
|
+
.starting_linenum!(start_index.next)
|
46
|
+
.if(raw_code)
|
47
|
+
.annotate!(:error, annotate, line: message_offset)
|
48
|
+
.end
|
49
|
+
.end
|
50
|
+
.end
|
51
|
+
|
52
|
+
# nodes get !
|
53
|
+
formatter
|
54
|
+
.group!(:path_with_code)
|
55
|
+
.group!(:path, emphasize_path&&:emphasize)
|
56
|
+
.text(:dir, path_to_dir(@cwd, path, '/'))
|
57
|
+
.text(:filename, path.basename)
|
58
|
+
.text(:separator, ":")
|
59
|
+
.text(:line_number, location.linenum)
|
60
|
+
.end
|
61
|
+
.code!(raw_code || "Can't find code")
|
62
|
+
.strip_indentation
|
63
|
+
.language(:ruby)
|
64
|
+
.starting_linenum(start_index.next)
|
65
|
+
.if!(raw_code)
|
66
|
+
.annotate(:error, annotate, line: message_offset)
|
67
|
+
.end
|
68
|
+
.end
|
69
|
+
.end
|
70
|
+
|
71
|
+
# swapping self
|
72
|
+
formatter.eval prototype: self do
|
73
|
+
group :path_with_code do
|
74
|
+
group :path, emphasize_path&&:emphasize do
|
75
|
+
text :dir, path_to_dir(@cwd, path, '/')
|
76
|
+
text :filename, path.basename
|
77
|
+
text :separator, ":"
|
78
|
+
text :line_number, location.linenum
|
79
|
+
end
|
80
|
+
code raw_code||"Can't find code" do
|
81
|
+
language :ruby
|
82
|
+
strip_indentation
|
83
|
+
starting_linenum start_index.next
|
84
|
+
annotate :error, annotate, line: message_offset if raw_code
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
SemanticStructure
|
2
|
+
.dsl
|
3
|
+
.partition
|
4
|
+
.header
|
5
|
+
.title!(@info.classname)
|
6
|
+
.subtext(:error)
|
7
|
+
.text!(@info.explanation)
|
8
|
+
.deemphasize
|
9
|
+
.text!(:context, '(expected ')
|
10
|
+
.text!(:stands_out, @info.num_expected)
|
11
|
+
.text!(:context, ', sent ')
|
12
|
+
.text!(:stands_out, @info.num_received)
|
13
|
+
.text!(:context, ')')
|
14
|
+
.end
|
15
|
+
.end
|
16
|
+
.end
|
17
|
+
}
|
18
|
+
.partition { |heuristic|
|
19
|
+
heuristic = display_location formatter: heuristic,
|
20
|
+
annotation: "expected #{@info.num_expected}",
|
21
|
+
location: @info.backtrace[0],
|
22
|
+
highlight: @info.backtrace[0].label,
|
23
|
+
context: 0..5,
|
24
|
+
emphasisis: :code
|
25
|
+
|
26
|
+
heuristic = display_location formatter: heuristic
|
27
|
+
annotation: "SENT #{info.num_received}",
|
28
|
+
location: info.backtrace[1],
|
29
|
+
highlight: info.backtrace[0].label,
|
30
|
+
context: -5..5,
|
31
|
+
emphasisis: :code
|
32
|
+
heuristic
|
33
|
+
}
|
34
|
+
.partition { |fmt|
|
35
|
+
info.backtrace.reduce(fmt) do |formatter, location|
|
36
|
+
display_location formatter: formatter,
|
37
|
+
location: location,
|
38
|
+
highlight: location.succ.label,
|
39
|
+
context: 0..0,
|
40
|
+
emphasisis: :path
|
41
|
+
end
|
42
|
+
}
|
43
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
# hypothetical way to render http://blog.turing.io/images/article_images/error_to_communicate/proof_of_concept-e2d4c91d.png
|
2
|
+
# Seems like it would take a lot of work, though, and I'm not totally sure how to map it to HTML/CSS
|
3
|
+
|
4
|
+
# ===== KEY =====
|
5
|
+
defn: - a tree definition named "defn"
|
6
|
+
defn:< - a tree definition named "defn" with one child, a node named "defn"
|
7
|
+
node - a node named "node"
|
8
|
+
if a leaf, then its children may be provided as text
|
9
|
+
or zero or more of any kind of node
|
10
|
+
*node - zero or more nodes named "node"
|
11
|
+
$ref - node named "ref" whose children come from a structure definition named "ref"
|
12
|
+
?node - zero or one nodes named "node"
|
13
|
+
.class - a boolean attribute on the containing node (ie a css class)
|
14
|
+
node.class - node has the boolean attribute "attr"
|
15
|
+
|
16
|
+
# ===== TEMPLATE =====
|
17
|
+
main:
|
18
|
+
error_type
|
19
|
+
class
|
20
|
+
explanation
|
21
|
+
heuristic
|
22
|
+
backtrace
|
23
|
+
*$codeview
|
24
|
+
|
25
|
+
wrong_number_of_arguments:
|
26
|
+
$codeview
|
27
|
+
$codeview
|
28
|
+
|
29
|
+
codeview:
|
30
|
+
path
|
31
|
+
?.emphasize
|
32
|
+
dir
|
33
|
+
file
|
34
|
+
?line_num
|
35
|
+
code
|
36
|
+
*codeline
|
37
|
+
?.emphasize
|
38
|
+
?linenum
|
39
|
+
line
|
40
|
+
?annotation
|
41
|
+
|
42
|
+
message:<
|
43
|
+
details:<
|
44
|
+
standout:<
|
45
|
+
|
46
|
+
# ===== STYLE =====
|
47
|
+
|
48
|
+
error_type {
|
49
|
+
display: block;
|
50
|
+
border-top: 2px solid white;
|
51
|
+
border-bottom: 2px solid white;
|
52
|
+
}
|
53
|
+
error_type class {
|
54
|
+
color: #fff;
|
55
|
+
border-right: 1px solid white;
|
56
|
+
}
|
57
|
+
error_type explanation message { color: #F00 }
|
58
|
+
error_type explanation details { color: #A00 }
|
59
|
+
error_type explanation standout { color: #FFF }
|
60
|
+
|
61
|
+
path { display: block; }
|
62
|
+
path.emphasize { text-decoration: underline; }
|
63
|
+
path dir { color: #088; }
|
64
|
+
path file { color: #08C; }
|
65
|
+
path line_num { color: #04C; }
|
66
|
+
|
67
|
+
# should be grayed out if not emphasize
|
68
|
+
code { display: block; }
|
69
|
+
code codeline { display: block; }
|
70
|
+
code linenum { linenum: #04C; }
|
71
|
+
code line { }
|
72
|
+
code annotation {
|
73
|
+
background-color: #F00;
|
74
|
+
color: #FFF;
|
75
|
+
text-transform: uppercase;
|
76
|
+
}
|
77
|
+
|
78
|
+
|
79
|
+
# ===== DATA =====
|
80
|
+
bt0 = backtrace[0]
|
81
|
+
bt2 = backtrace[1]
|
82
|
+
main: {
|
83
|
+
error_type: {
|
84
|
+
class: 'ArgumentError',
|
85
|
+
explanation: [
|
86
|
+
{message: 'wrong number of arguments'},
|
87
|
+
{details: [
|
88
|
+
'(sent ',
|
89
|
+
{standout: 3},
|
90
|
+
' expected ',
|
91
|
+
{standout: 2},
|
92
|
+
')',
|
93
|
+
]}
|
94
|
+
]
|
95
|
+
},
|
96
|
+
heuristic: [
|
97
|
+
{codeview: {
|
98
|
+
path: {
|
99
|
+
dir: File.dirname(bt0.path),
|
100
|
+
file: File.basename(bt0.path),
|
101
|
+
linenum: bt0.linenum,
|
102
|
+
},
|
103
|
+
code: File.read(bt0.path)[bt0.linenum, 5].map.with_index(bt0.linenum) { |line, linenum|
|
104
|
+
{ emphasize: true,
|
105
|
+
linenum: linenum,
|
106
|
+
line: line,
|
107
|
+
annotation: ('Expected 2' if linenum == bt0.linenum),
|
108
|
+
}
|
109
|
+
},
|
110
|
+
}},
|
111
|
+
{codeview: {
|
112
|
+
path: {
|
113
|
+
dir: File.dirname(bt1.path),
|
114
|
+
file: File.basename(bt1.path),
|
115
|
+
linenum: bt1.linenum,
|
116
|
+
},
|
117
|
+
code: File.read(bt1.path)[bt1.linenum, 5].map.with_index(bt1.linenum) { |line, linenum|
|
118
|
+
{ emphasize: true,
|
119
|
+
linenum: linenum,
|
120
|
+
line: line,
|
121
|
+
annotation: ('Sent 3' if linenum == bt1.linenum)
|
122
|
+
}
|
123
|
+
},
|
124
|
+
}},
|
125
|
+
],
|
126
|
+
backtrace: backtrace.map { |location|
|
127
|
+
{ path: {
|
128
|
+
emphasize: true,
|
129
|
+
dir: File.dirname(location.path),
|
130
|
+
file: File.basename(location.path),
|
131
|
+
linenum: location.linenum,
|
132
|
+
},
|
133
|
+
code: {
|
134
|
+
linenum: location.linenum,
|
135
|
+
line: File.read(location.path).lines[location.linenum-1],
|
136
|
+
}
|
137
|
+
}
|
138
|
+
}
|
139
|
+
}
|
@@ -0,0 +1,156 @@
|
|
1
|
+
Hypothesis: Everything can be made from the following elements and styling
|
2
|
+
stack (vertical list)
|
3
|
+
flow (horizontal list)
|
4
|
+
grid (basically a table -- overlaid stacks and flows?)
|
5
|
+
text (an element containing only text)
|
6
|
+
|
7
|
+
Shoes:
|
8
|
+
(I'm omitting the methods that seem like they manipulate styles)
|
9
|
+
http://shoesrb.com/manual/Hello.html
|
10
|
+
layout
|
11
|
+
stack
|
12
|
+
flow
|
13
|
+
window
|
14
|
+
generic
|
15
|
+
image
|
16
|
+
video
|
17
|
+
background
|
18
|
+
banner
|
19
|
+
caption
|
20
|
+
code
|
21
|
+
dialog
|
22
|
+
inscription
|
23
|
+
form
|
24
|
+
list_box
|
25
|
+
button
|
26
|
+
check
|
27
|
+
edit_box
|
28
|
+
edit_line
|
29
|
+
radio
|
30
|
+
shapes
|
31
|
+
arc
|
32
|
+
arrow
|
33
|
+
cap
|
34
|
+
line
|
35
|
+
oval
|
36
|
+
rect
|
37
|
+
shape
|
38
|
+
star
|
39
|
+
text
|
40
|
+
para
|
41
|
+
strong
|
42
|
+
title
|
43
|
+
em
|
44
|
+
link
|
45
|
+
ins
|
46
|
+
span
|
47
|
+
sub
|
48
|
+
subtitle
|
49
|
+
sup
|
50
|
+
del
|
51
|
+
|
52
|
+
HTML:
|
53
|
+
http://www.w3.org/wiki/HTML/Elements
|
54
|
+
limited to just the ones I was already aware of, or seem useful
|
55
|
+
I've rearranged them a little bit
|
56
|
+
metadata
|
57
|
+
head
|
58
|
+
title
|
59
|
+
link
|
60
|
+
meta
|
61
|
+
sections
|
62
|
+
body
|
63
|
+
section
|
64
|
+
nav
|
65
|
+
article
|
66
|
+
aside
|
67
|
+
h1 - h6
|
68
|
+
header
|
69
|
+
footer
|
70
|
+
grouping
|
71
|
+
hr
|
72
|
+
pre
|
73
|
+
blockquote
|
74
|
+
ol/ul/dl/li/dt/dd
|
75
|
+
figure
|
76
|
+
figcaption
|
77
|
+
div
|
78
|
+
main
|
79
|
+
text
|
80
|
+
p
|
81
|
+
center
|
82
|
+
a
|
83
|
+
acronym
|
84
|
+
abbr
|
85
|
+
br
|
86
|
+
cite
|
87
|
+
code
|
88
|
+
em
|
89
|
+
mark
|
90
|
+
q
|
91
|
+
span
|
92
|
+
small
|
93
|
+
spacer
|
94
|
+
strike
|
95
|
+
strong
|
96
|
+
sub/sup
|
97
|
+
time
|
98
|
+
wbr <-- line break opportunity (who knew!)
|
99
|
+
ins
|
100
|
+
del
|
101
|
+
embedded content
|
102
|
+
img
|
103
|
+
iframe
|
104
|
+
embed
|
105
|
+
object
|
106
|
+
param
|
107
|
+
video
|
108
|
+
audio
|
109
|
+
source
|
110
|
+
track
|
111
|
+
canvas
|
112
|
+
map
|
113
|
+
area
|
114
|
+
math
|
115
|
+
svg
|
116
|
+
applet
|
117
|
+
frame
|
118
|
+
frameset
|
119
|
+
noframes
|
120
|
+
bgsound
|
121
|
+
noembed
|
122
|
+
plaintext
|
123
|
+
tables
|
124
|
+
table
|
125
|
+
caption
|
126
|
+
colgroup
|
127
|
+
col
|
128
|
+
tbody
|
129
|
+
thead
|
130
|
+
tfoot
|
131
|
+
tr
|
132
|
+
td
|
133
|
+
th
|
134
|
+
forms
|
135
|
+
form
|
136
|
+
fieldset
|
137
|
+
legend
|
138
|
+
label
|
139
|
+
input
|
140
|
+
button
|
141
|
+
select
|
142
|
+
datalist
|
143
|
+
optgroup
|
144
|
+
option
|
145
|
+
textarea
|
146
|
+
keygen
|
147
|
+
output
|
148
|
+
progress
|
149
|
+
meter
|
150
|
+
interactive
|
151
|
+
details
|
152
|
+
summary
|
153
|
+
command
|
154
|
+
menu
|
155
|
+
other
|
156
|
+
script
|