what_weve_got_here_is_an_error_to_communicate 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Build Status](https://travis-ci.org/JoshCheek/what-we-ve-got-here-is-an-error-to-communicate.svg?branch=master)](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
|
+
![screenshot](https://s3.amazonaws.com/josh.cheek/images/scratch/better-reuby-commandline-errors.png)
|
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
|