better_errors 0.1.0 → 0.2.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.
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Better Errors replaces the standard Rails error page with a much better and more useful error page. It is also usable outside of Rails in any Rack app as Rack middleware.
4
4
 
5
- ![image](http://i.imgur.com/urVDW.png)
5
+ ![image](http://i.imgur.com/zYOXF.png)
6
6
 
7
7
  ## Features
8
8
 
@@ -23,7 +23,7 @@ module BetterErrors
23
23
  end
24
24
 
25
25
  def source_unavailable
26
- "<p>Source unavailable</p>"
26
+ "<p class='unavailable'>Source unavailable</p>"
27
27
  end
28
28
 
29
29
  def coderay_scanner
@@ -50,6 +50,14 @@ module BetterErrors
50
50
  end
51
51
 
52
52
  private
53
+ def exception_message
54
+ if exception.is_a?(SyntaxError) && exception.message =~ /\A.*:\d*: (.*)$/
55
+ $1
56
+ else
57
+ exception.message
58
+ end
59
+ end
60
+
53
61
  def real_exception(exception)
54
62
  if exception.respond_to? :original_exception
55
63
  exception.original_exception
@@ -1,16 +1,18 @@
1
1
  module BetterErrors
2
2
  module REPL
3
3
  PROVIDERS = [
4
- { impl: "better_errors/repl/pry",
5
- const: :Pry },
6
4
  { impl: "better_errors/repl/basic",
7
5
  const: :Basic },
8
6
  ]
9
-
7
+
10
8
  def self.provider
11
9
  @provider ||= const_get detect[:const]
12
10
  end
13
11
 
12
+ def self.provider=(prov)
13
+ @provider = prov
14
+ end
15
+
14
16
  def self.detect
15
17
  PROVIDERS.find do |prov|
16
18
  test_provider prov
@@ -2,9 +2,9 @@ module BetterErrors
2
2
  class StackFrame
3
3
  def self.from_exception(exception)
4
4
  idx_offset = 0
5
- exception.backtrace.each_with_index.map { |frame, idx|
5
+ list = exception.backtrace.each_with_index.map do |frame, idx|
6
6
  frame_binding = exception.__better_errors_bindings_stack[idx - idx_offset]
7
- md = /\A(?<file>.*):(?<line>\d*):in `(?<name>.*)'\z/.match(frame)
7
+ md = /\A(?<file>.*):(?<line>\d*)(:in `(?<name>.*)')?\z/.match(frame)
8
8
 
9
9
  # prevent mismatching frames in the backtrace with the binding stack
10
10
  if frame_binding and frame_binding.eval("__FILE__") != md[:file]
@@ -13,7 +13,13 @@ module BetterErrors
13
13
  end
14
14
 
15
15
  StackFrame.new(md[:file], md[:line].to_i, md[:name], frame_binding)
16
- }.compact
16
+ end
17
+
18
+ if exception.is_a?(SyntaxError) && exception.to_s =~ /\A(.*):(\d*):/
19
+ list.unshift StackFrame.new($1, $2.to_i, "")
20
+ end
21
+
22
+ list
17
23
  end
18
24
 
19
25
  attr_reader :filename, :line, :name, :frame_binding
@@ -47,6 +53,14 @@ module BetterErrors
47
53
  end
48
54
  end
49
55
  end
56
+
57
+ def class_name
58
+ @class_name
59
+ end
60
+
61
+ def method_name
62
+ @method_name || @name
63
+ end
50
64
 
51
65
  def context
52
66
  if application?
@@ -93,12 +107,14 @@ module BetterErrors
93
107
  def set_pretty_method_name
94
108
  name =~ /\A(block (\([^)]+\) )?in )?/
95
109
  recv = frame_binding.eval("self")
96
- return unless method = frame_binding.eval("__method__")
97
- @name = if recv.is_a? Module
98
- "#{$1}#{recv}.#{method}"
99
- else
100
- "#{$1}#{recv.class}##{method}"
101
- end
110
+ return unless method_name = frame_binding.eval("__method__")
111
+ if recv.is_a? Module
112
+ @class_name = "#{$1}#{recv}"
113
+ @method_name = ".#{method_name}"
114
+ else
115
+ @class_name = "#{$1}#{recv.class}"
116
+ @method_name = "##{method_name}"
117
+ end
102
118
  end
103
119
 
104
120
  def starts_with?(haystack, needle)
@@ -3,262 +3,722 @@
3
3
  <head>
4
4
  <title><%= exception.class %> at <%= request_path %></title>
5
5
  <style>
6
+ /* Basic reset */
6
7
  * {
7
- margin:0;
8
- padding:0;
8
+ margin: 0;
9
+ padding: 0;
9
10
  }
11
+
12
+ table {
13
+ width: 100%;
14
+ border-collapse: collapse;
15
+ }
16
+
17
+ th, td {
18
+ vertical-align: top;
19
+ text-align: left;
20
+ }
21
+
22
+ textarea {
23
+ resize: none;
24
+ }
25
+
10
26
  body {
11
- font-family:Verdana, sans-serif;
12
- margin:0;
13
- font-size:13px;
14
- }
15
- header {
16
- padding:32px 32px;
17
- border-bottom:1px solid #e64c38;
18
- background-color: #ffe5e7;
19
- background-image: -webkit-gradient(linear, left top, left bottom, from(#ffe5e7), to(#ffb2b8)); /* Safari 4+, Chrome */
20
- background-image: -webkit-linear-gradient(top, #ffe5e7, #ffb2b8); /* Chrome 10+, Safari 5.1+, iOS 5+ */
21
- background-image: -moz-linear-gradient(top, #ffe5e7, #ffb2b8); /* Firefox 3.6-15 */
22
- background-image: -o-linear-gradient(top, #ffe5e7, #ffb2b8); /* Opera 11.10-12.00 */
23
- background-image: linear-gradient(to bottom, #ffe5e7, #ffb2b8); /* Firefox 16+, IE10, Opera 12.50+ */
24
- }
25
- h2 {
26
- font-weight:normal;
27
- margin:0;
28
- margin-bottom:16px;
29
- }
30
- h2 span {
31
- color:#666666;
32
- }
33
- header table {
34
- border-collapse:collapse;
35
- }
36
- header table th {
37
- text-align:right;
38
- font-weight:bold;
39
- padding-right:12px;
40
- }
41
- header table th, header table td {
42
- padding:4px 6px;
43
- }
44
- nav {
45
- display:block;
46
- padding:12px 12px;
47
- border-bottom:1px solid #000000;
48
- background-color: #444444;
49
- background-image: -webkit-gradient(linear, left top, left bottom, from(#444444), to(#222222)); /* Safari 4+, Chrome */
50
- background-image: -webkit-linear-gradient(top, #444444, #222222); /* Chrome 10+, Safari 5.1+, iOS 5+ */
51
- background-image: -moz-linear-gradient(top, #444444, #222222); /* Firefox 3.6-15 */
52
- background-image: -o-linear-gradient(top, #444444, #222222); /* Opera 11.10-12.00 */
53
- background-image: linear-gradient(to bottom, #444444, #222222); /* Firefox 16+, IE10, Opera 12.50+ */
54
- }
55
- nav a {
56
- color:#ffffff;
57
- text-decoration:none;
58
- padding:4px 16px;
59
- border-radius:16px;
60
- }
61
- nav a:hover {
62
- background-color: #666666;
63
- background-image: -webkit-gradient(linear, left top, left bottom, from(#666666), to(#444444)); /* Safari 4+, Chrome */
64
- background-image: -webkit-linear-gradient(top, #666666, #444444); /* Chrome 10+, Safari 5.1+, iOS 5+ */
65
- background-image: -moz-linear-gradient(top, #666666, #444444); /* Firefox 3.6-15 */
66
- background-image: -o-linear-gradient(top, #666666, #444444); /* Opera 11.10-12.00 */
67
- background-image: linear-gradient(to bottom, #666666, #444444); /* Firefox 16+, IE10, Opera 12.50+ */
68
- }
69
- nav a.selected {
70
- color:#000000;
71
- background-color: #efefef;
72
- background-image: -webkit-gradient(linear, left top, left bottom, from(#efefef), to(#cfcfcf)); /* Safari 4+, Chrome */
73
- background-image: -webkit-linear-gradient(top, #efefef, #cfcfcf); /* Chrome 10+, Safari 5.1+, iOS 5+ */
74
- background-image: -moz-linear-gradient(top, #efefef, #cfcfcf); /* Firefox 3.6-15 */
75
- background-image: -o-linear-gradient(top, #efefef, #cfcfcf); /* Opera 11.10-12.00 */
76
- background-image: linear-gradient(to bottom, #efefef, #cfcfcf); /* Firefox 16+, IE10, Opera 12.50+ */
77
- }
78
- .frames {
79
- width:50%;
80
- float:left;
81
- }
82
- .frames li {
83
- list-style:none;
84
- display:block;
85
- padding:12px;
86
- overflow:hidden;
87
- cursor:pointer;
88
- background-color: #f4f7ff;
89
- background-image: -webkit-gradient(linear, left top, left bottom, from(#f4f7ff), to(#e4ebfe)); /* Safari 4+, Chrome */
90
- background-image: -webkit-linear-gradient(top, #f4f7ff, #e4ebfe); /* Chrome 10+, Safari 5.1+, iOS 5+ */
91
- background-image: -moz-linear-gradient(top, #f4f7ff, #e4ebfe); /* Firefox 3.6-15 */
92
- background-image: -o-linear-gradient(top, #f4f7ff, #e4ebfe); /* Opera 11.10-12.00 */
93
- background-image: linear-gradient(to bottom, #f4f7ff, #e4ebfe); /* Firefox 16+, IE10, Opera 12.50+ */
94
- border-bottom:1px solid #cccccc;
95
- }
96
- .frames li:hover, .frames li.selected {
97
- background-color: #e4ebfe;
98
- background-image: -webkit-gradient(linear, left top, left bottom, from(#e4ebfe), to(#c2d3fe)); /* Safari 4+, Chrome */
99
- background-image: -webkit-linear-gradient(top, #e4ebfe, #c2d3fe); /* Chrome 10+, Safari 5.1+, iOS 5+ */
100
- background-image: -moz-linear-gradient(top, #e4ebfe, #c2d3fe); /* Firefox 3.6-15 */
101
- background-image: -o-linear-gradient(top, #e4ebfe, #c2d3fe); /* Opera 11.10-12.00 */
102
- background-image: linear-gradient(to bottom, #e4ebfe, #c2d3fe); /* Firefox 16+, IE10, Opera 12.50+ */
103
- }
104
- .frames .name, .frame_info h2.name {
105
- font-family:Monaco, Incosolata, Consolas, monospace;
106
- font-size:14px;
107
- margin-bottom:4px;
108
- word-wrap:break-word;
109
- }
110
- .location {
111
- color:#888888;
112
- }
113
- .location .filename, .location .line {
114
- color:#333333;
115
- }
116
- .frame_info {
117
- background-color:#efefef;
118
- border-bottom:1px solid #cccccc;
119
- float:left;
120
- width:50%;
121
- }
122
- .frame_info > * {
123
- margin:16px;
124
- }
125
- .frame_info h2 {
126
- font-family:Monaco, Incosolata, Consolas, monospace;
127
- }
128
- .frame_info .code {
129
- font-family:Monaco, Incosolata, Consolas, monospace;
130
- background-color:#ffffff;
131
- border:1px solid #cccccc;
132
- border-collapse:collapse;
133
- overflow:auto;
134
- }
135
- .frame_info .code pre:nth-child(2n+1) {
136
- background-color:#f9f9f9;
137
- }
138
- .frame_info .code pre:nth-child(2n) {
139
- background-color:#f3f3f3;
140
- }
141
- .frame_info .code pre.highlight {
142
- background-color:#ffeaaa;
143
- }
144
- .frame_info .code .line {
145
- text-align:right;
146
- padding-right:12px;
147
- padding-left:0px;
148
- }
149
- code {
150
- background-color:#f0f0f0;
151
- padding:2px 4px;
152
- border:1px solid #d0d0d0;
153
- }
154
- h3 {
155
- font-weight:normal;
156
- border-top:1px solid #cccccc;
157
- padding-top:16px;
158
- margin-bottom:16px;
159
- }
160
- .var_table {
161
- border-collapse:collapse;
162
- }
163
- .var_table td {
164
- padding:8px;
165
- }
166
- .var_table td.name {
167
- font-style:italic;
168
- }
169
- .var_table tr {
170
- border-bottom:1px solid #cccccc;
171
- }
172
- .repl .console {
173
- background-color:#ffffff;
174
- padding:2px 4px;
175
- border:1px solid #d0d0d0;
176
- margin-bottom:8px;
177
- font-family:monospace;
178
- }
179
- .repl pre {
180
- font-size:12px;
181
- white-space:pre-wrap;
182
- max-height:400px;
183
- overflow:auto;
184
- }
185
- .repl .prompt {
186
- font-size:12px;
187
- position:relative;
188
- }
189
- .repl input {
190
- font-size:12px;
191
- border:none;
192
- font-family:monospace;
193
- outline:none;
194
- padding:0px;
195
- position:absolute;
196
- left:20px;
197
- right:0px;
27
+ font-size: 10pt;
28
+ }
29
+
30
+ body, td, input, textarea {
31
+ font-family: helvetica neue, lucida grande, sans-serif;
32
+ line-height: 1.5;
33
+ color: #333;
34
+ text-shadow: 0 1px 0 rgba(255, 255, 255, 0.6);
35
+ }
36
+
37
+ html {
38
+ background: #f0f0f5;
39
+ }
40
+
41
+ /* ---------------------------------------------------------------------
42
+ * Basic layout
43
+ * --------------------------------------------------------------------- */
44
+
45
+ /* Small */
46
+ @media screen and (max-width: 1100px) {
47
+ html {
48
+ overflow-y: scroll;
49
+ }
50
+
51
+ body {
52
+ margin: 0 20px;
53
+ }
54
+
55
+ header.exception {
56
+ margin: 0 -20px;
57
+ }
58
+
59
+ nav.sidebar {
60
+ padding: 0;
61
+ margin: 20px 0;
62
+ }
63
+
64
+ ul.frames {
65
+ max-height: 200px;
66
+ overflow: auto;
67
+ }
68
+ }
69
+
70
+ /* Wide */
71
+ @media screen and (min-width: 1100px) {
72
+ header.exception {
73
+ position: fixed;
74
+ top: 0;
75
+ left: 0;
76
+ right: 0;
77
+ }
78
+
79
+ nav.sidebar,
80
+ .frame_info {
81
+ position: fixed;
82
+ top: 95px;
83
+ bottom: 0;
84
+
85
+ box-sizing: border-box;
86
+
87
+ overflow-y: auto;
88
+ overflow-x: hidden;
89
+ }
90
+
91
+ nav.sidebar {
92
+ width: 40%;
93
+ left: 20px;
94
+ top: 115px;
95
+ bottom: 20px;
96
+ }
97
+
98
+ .frame_info {
99
+ right: 0;
100
+ left: 40%;
101
+
102
+ padding: 20px;
103
+ padding-left: 10px;
104
+ margin-left: 30px;
105
+ }
106
+ }
107
+
108
+ nav.sidebar {
109
+ background: #d3d3da;
110
+ border-top: solid 3px #a33;
111
+ border-bottom: solid 3px #a33;
112
+ border-radius: 4px;
113
+ box-shadow: 0 0 6px rgba(0, 0, 0, 0.2), inset 0 0 0 1px rgba(0, 0, 0, 0.1);
114
+ }
115
+
116
+ /* ---------------------------------------------------------------------
117
+ * Header
118
+ * --------------------------------------------------------------------- */
119
+
120
+ header.exception {
121
+ padding: 18px 20px;
122
+
123
+ height: 59px;
124
+ min-height: 59px;
125
+
126
+ overflow: hidden;
127
+
128
+ background-color: #20202a;
129
+ color: #aaa;
130
+ text-shadow: 0 1px 0 rgba(0, 0, 0, 0.3);
131
+ font-weight: 200;
132
+ box-shadow: inset 0 -5px 3px -3px rgba(0, 0, 0, 0.05), inset 0 -1px 0 rgba(0, 0, 0, 0.05);
133
+
134
+ -webkit-text-smoothing: antialiased;
135
+ }
136
+
137
+ /* Heading */
138
+ header.exception h2 {
139
+ font-weight: 200;
140
+ font-size: 11pt;
141
+ }
142
+
143
+ header.exception h2,
144
+ header.exception p {
145
+ line-height: 1.4em;
146
+ height: 1.4em;
147
+ overflow: hidden;
148
+ white-space: pre;
149
+ text-overflow: ellipsis;
150
+ }
151
+
152
+ header.exception h2 strong {
153
+ font-weight: 700;
154
+ color: #d55;
155
+ }
156
+
157
+ header.exception p {
158
+ font-weight: 200;
159
+ font-size: 20pt;
160
+ color: white;
161
+ }
162
+
163
+ header.exception:hover {
164
+ height: auto;
165
+ z-index: 2;
166
+ }
167
+
168
+ header.exception:hover h2,
169
+ header.exception:hover p {
170
+ padding-right: 20px;
171
+ overflow-y: auto;
172
+ word-wrap: break-word;
173
+ height: auto;
174
+ max-height: 7em;
175
+ }
176
+
177
+ @media screen and (max-width: 1100px) {
178
+ header.exception {
179
+ height: auto;
180
+ }
181
+
182
+ header.exception h2,
183
+ header.exception p {
184
+ padding-right: 20px;
185
+ overflow-y: auto;
186
+ word-wrap: break-word;
187
+ height: auto;
188
+ max-height: 7em;
189
+ }
190
+ }
191
+
192
+ <%#
193
+ /* Light theme */
194
+ header.exception {
195
+ text-shadow: 0 1px 0 rgba(250, 250, 250, 0.6);
196
+ background: rgba(200,100,50,0.10);
197
+ color: #977;
198
+ }
199
+ header.exception h2 strong {
200
+ color: #533;
201
+ }
202
+ header.exception p {
203
+ color: #744;
204
+ }
205
+ %>
206
+
207
+ /* ---------------------------------------------------------------------
208
+ * Navigation
209
+ * --------------------------------------------------------------------- */
210
+
211
+ nav.tabs {
212
+ border-bottom: solid 1px #ddd;
213
+
214
+ background-color: #eee;
215
+ text-align: center;
216
+
217
+ padding: 6px;
218
+
219
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);
220
+ }
221
+
222
+ nav.tabs a {
223
+ display: inline-block;
224
+
225
+ height: 22px;
226
+ line-height: 22px;
227
+ padding: 0 10px;
228
+
229
+ text-decoration: none;
230
+ font-size: 8pt;
231
+ font-weight: bold;
232
+
233
+ color: #999;
234
+ text-shadow: 0 1px 0 rgba(255, 255, 255, 0.6);
235
+ }
236
+
237
+ nav.tabs a.selected {
238
+ color: white;
239
+ background: rgba(0, 0, 0, 0.5);
240
+ border-radius: 16px;
241
+ box-shadow: 1px 1px 0 rgba(255, 255, 255, 0.1);
242
+ text-shadow: 0 0 4px rgba(0, 0, 0, 0.4), 0 1px 0 rgba(0, 0, 0, 0.4);
243
+ }
244
+
245
+ /* ---------------------------------------------------------------------
246
+ * Sidebar
247
+ * --------------------------------------------------------------------- */
248
+
249
+ ul.frames {
250
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
251
+ }
252
+
253
+ /* Each item */
254
+ ul.frames li {
255
+ background-color: #f8f8f8;
256
+ background: -webkit-linear-gradient(top, #f8f8f8 80%, #f0f0f0);
257
+ background: -moz-linear-gradient(top, #f8f8f8 80%, #f0f0f0);
258
+ background: linear-gradient(top, #f8f8f8 80%, #f0f0f0);
259
+ box-shadow: inset 0 -1px 0 #e2e2e2;
260
+ padding: 7px 20px;
261
+
262
+ cursor: pointer;
263
+ overflow: hidden;
264
+ }
265
+
266
+ ul.frames .name,
267
+ ul.frames .location {
268
+ overflow: hidden;
269
+ height: 1.5em;
270
+
271
+ white-space: nowrap;
272
+ word-wrap: none;
273
+ text-overflow: ellipsis;
274
+ }
275
+
276
+ ul.frames .method {
277
+ color: #966;
278
+ }
279
+
280
+ ul.frames .location {
281
+ font-size: 0.85em;
282
+ font-weight: 400;
283
+ color: #999;
284
+ }
285
+
286
+ ul.frames .line {
287
+ font-weight: bold;
288
+ }
289
+
290
+ /* Selected frame */
291
+ ul.frames li.selected {
292
+ background: #38a;
293
+ box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.1), inset 0 2px 0 rgba(255, 255, 255, 0.01), inset 0 -1px 0 rgba(0, 0, 0, 0.1);
294
+ }
295
+
296
+ ul.frames li.selected .name,
297
+ ul.frames li.selected .method,
298
+ ul.frames li.selected .location {
299
+ color: white;
300
+ text-shadow: 0 1px 0 rgba(0, 0, 0, 0.2);
301
+ }
302
+
303
+ ul.frames li.selected .location {
304
+ opacity: 0.6;
305
+ }
306
+
307
+ /* Iconography */
308
+ ul.frames li {
309
+ padding-left: 60px;
310
+ position: relative;
311
+ }
312
+
313
+ ul.frames li .icon {
314
+ display: block;
315
+ width: 20px;
316
+ height: 20px;
317
+ line-height: 20px;
318
+ border-radius: 15px;
319
+
320
+ text-align: center;
321
+
322
+ background: white;
323
+ border: solid 2px #ccc;
324
+
325
+ font-size: 9pt;
326
+ font-weight: 200;
327
+ font-style: normal;
328
+
329
+ position: absolute;
330
+ top: 14px;
331
+ left: 20px;
332
+ }
333
+
334
+ ul.frames .icon.application {
335
+ background: #808090;
336
+ border-color: #555;
337
+ }
338
+
339
+ ul.frames .icon.application:before {
340
+ content: 'A';
341
+ color: white;
342
+ text-shadow: 0 0 3px rgba(0, 0, 0, 0.2);
343
+ }
344
+
345
+ /* Responsiveness -- flow to single-line mode */
346
+ @media screen and (max-width: 1100px) {
347
+ ul.frames li {
348
+ padding-top: 6px;
349
+ padding-bottom: 6px;
350
+ padding-left: 36px;
351
+ line-height: 1.3;
352
+ }
353
+
354
+ ul.frames li .icon {
355
+ width: 11px;
356
+ height: 11px;
357
+ line-height: 11px;
358
+
359
+ top: 7px;
360
+ left: 10px;
361
+ font-size: 5pt;
362
+ }
363
+
364
+ ul.frames .name,
365
+ ul.frames .location {
366
+ display: inline-block;
367
+ line-height: 1.3;
368
+ height: 1.3em;
369
+ }
370
+
371
+ ul.frames .name {
372
+ margin-right: 10px;
373
+ }
374
+ }
375
+
376
+ /* ---------------------------------------------------------------------
377
+ * Monospace
378
+ * --------------------------------------------------------------------- */
379
+
380
+ pre, code, .repl input, .repl .prompt span, textarea {
381
+ font-family: menlo, lucida console, monospace;
382
+ font-size: 8pt;
383
+ }
384
+
385
+ /* ---------------------------------------------------------------------
386
+ * Display area
387
+ * --------------------------------------------------------------------- */
388
+
389
+ .trace_info {
390
+ background: #fff;
391
+ padding: 6px;
392
+ border-radius: 3px;
393
+ margin-bottom: 2px;
394
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.03), 1px 1px 0 rgba(0, 0, 0, 0.05), -1px 1px 0 rgba(0, 0, 0, 0.05), 0 0 0 4px rgba(0, 0, 0, 0.04);
395
+ }
396
+
397
+ /* Titlebar */
398
+ .trace_info .title {
399
+ background: #f1f1f1;
400
+
401
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.3);
402
+ overflow: hidden;
403
+ padding: 6px 10px;
404
+
405
+ border: solid 1px #ccc;
406
+ border-bottom: 0;
407
+
408
+ border-top-left-radius: 2px;
409
+ border-top-right-radius: 2px;
410
+ }
411
+
412
+ .trace_info .title .name,
413
+ .trace_info .title .location {
414
+ font-size: 9pt;
415
+ line-height: 26px;
416
+ height: 26px;
417
+ overflow: hidden;
418
+ }
419
+
420
+ .trace_info .title .location {
421
+ float: left;
422
+ font-weight: bold;
423
+ font-size: 10pt;
424
+ }
425
+
426
+ .trace_info .title .name {
427
+ float: right;
428
+ font-weight: 200;
429
+ }
430
+
431
+ .code, .console, .unavailable {
432
+ background: #fff;
433
+ padding: 5px;
434
+
435
+ box-shadow: inset 3px 3px 3px rgba(0, 0, 0, 0.1), inset 0 0 0 1px rgba(0, 0, 0, 0.1);
436
+ }
437
+
438
+ .code {
439
+ margin-bottom: -1px;
440
+ }
441
+
442
+ .code {
443
+ padding: 10px 0;
444
+ overflow: auto;
445
+ }
446
+
447
+ /* Source unavailable */
448
+ p.unavailable {
449
+ padding: 20px 0 40px 0;
450
+ text-align: center;
451
+ color: #b99;
452
+ font-weight: bold;
453
+ }
454
+
455
+ p.unavailable:before {
456
+ content: '\00d7';
457
+ display: block;
458
+
459
+ color: #daa;
460
+
461
+ text-align: center;
462
+ font-size: 40pt;
463
+ font-weight: normal;
464
+ margin-bottom: -10px;
465
+ }
466
+
467
+ @-webkit-keyframes highlight {
468
+ 0% { background: rgba(220, 30, 30, 0.3); }
469
+ 100% { background: rgba(220, 30, 30, 0.1); }
470
+ }
471
+ @-moz-keyframes highlight {
472
+ 0% { background: rgba(220, 30, 30, 0.3); }
473
+ 100% { background: rgba(220, 30, 30, 0.1); }
474
+ }
475
+ @keyframes highlight {
476
+ 0% { background: rgba(220, 30, 30, 0.3); }
477
+ 100% { background: rgba(220, 30, 30, 0.1); }
478
+ }
479
+
480
+ .code .highlight {
481
+ background: rgba(220, 30, 30, 0.1);
482
+ -webkit-animation: highlight 400ms linear 1;
483
+ -moz-animation: highlight 400ms linear 1;
484
+ animation: highlight 400ms linear 1;
485
+ }
486
+
487
+ /* REPL shell */
488
+ .console {
489
+ padding: 0 1px 10px 1px;
490
+ border-bottom-left-radius: 2px;
491
+ border-bottom-right-radius: 2px;
492
+ }
493
+
494
+ .console pre {
495
+ padding: 10px 10px 0 10px;
496
+ max-height: 200px;
497
+ overflow-x: none;
498
+ overflow-y: auto;
499
+ margin-bottom: -3px;
500
+ word-wrap: break-word;
501
+ white-space: pre-wrap;
502
+ }
503
+
504
+ /* .prompt > span + input */
505
+ .console .prompt {
506
+ display: table;
507
+ width: 100%;
508
+ }
509
+
510
+ .console .prompt span,
511
+ .console .prompt input {
512
+ display: table-cell;
198
513
  }
514
+
515
+ .console .prompt span {
516
+ width: 1%;
517
+ padding-right: 5px;
518
+ padding-left: 10px;
519
+ }
520
+
521
+ .console .prompt input {
522
+ width: 99%;
523
+ }
524
+
525
+ /* Input box */
526
+ .console input,
527
+ .console input:focus {
528
+ outline: 0;
529
+ border: 0;
530
+ padding: 0;
531
+ background: transparent;
532
+ margin: 0;
533
+ }
534
+
535
+ /* Hint text */
536
+ .hint {
537
+ margin: 15px 0 20px 0;
538
+ font-size: 8pt;
539
+ color: #8080a0;
540
+ padding-left: 20px;
541
+ }
542
+
543
+ .hint:before {
544
+ content: '\25b2';
545
+ margin-right: 5px;
546
+ opacity: 0.5;
547
+ }
548
+
549
+ /* ---------------------------------------------------------------------
550
+ * Variable infos
551
+ * --------------------------------------------------------------------- */
552
+
553
+ .sub {
554
+ padding: 10px 0;
555
+ margin: 10px 0;
556
+ }
557
+
558
+ .sub:before {
559
+ content: '';
560
+ display: block;
561
+ width: 100%;
562
+ height: 4px;
563
+
564
+ border-radius: 2px;
565
+ background: rgba(0, 150, 200, 0.05);
566
+ box-shadow: 1px 1px 0 rgba(255, 255, 255, 0.7), inset 0 0 0 1px rgba(0, 0, 0, 0.04), inset 2px 2px 2px rgba(0, 0, 0, 0.07);
567
+ }
568
+
569
+ .sub h3 {
570
+ color: #39a;
571
+ font-size: 1.1em;
572
+ margin: 10px 0;
573
+ text-shadow: 0 1px 0 rgba(255, 255, 255, 0.6);
574
+
575
+ -webkit-font-smoothing: antialiased;
576
+ }
577
+
578
+ .sub .inset {
579
+ overflow-y: auto;
580
+ }
581
+
582
+ .sub table {
583
+ table-layout: fixed;
584
+ }
585
+
586
+ .sub table td {
587
+ border-top: dotted 1px #ddd;
588
+ padding: 7px 1px;
589
+ }
590
+
591
+ .sub table td.name {
592
+ width: 150px;
593
+
594
+ font-weight: bold;
595
+ font-size: 0.8em;
596
+ padding-right: 20px;
597
+ }
598
+
599
+ .sub table td pre {
600
+ max-height: 15em;
601
+ overflow-y: auto;
602
+ }
603
+
604
+ .sub table td pre {
605
+ width: 100%;
606
+
607
+ word-wrap: break-word;
608
+ white-space: normal;
609
+ }
610
+
611
+ /* ---------------------------------------------------------------------
612
+ * Scrollbar
613
+ * --------------------------------------------------------------------- */
614
+
615
+ nav.sidebar::-webkit-scrollbar,
616
+ .inset pre::-webkit-scrollbar,
617
+ .console pre::-webkit-scrollbar,
618
+ .code::-webkit-scrollbar {
619
+ width: 10px;
620
+ height: 10px;
621
+ }
622
+
623
+ .inset pre::-webkit-scrollbar-thumb,
624
+ .console pre::-webkit-scrollbar-thumb,
625
+ .code::-webkit-scrollbar-thumb {
626
+ background: #ccc;
627
+ border-radius: 5px;
628
+ }
629
+
630
+ nav.sidebar::-webkit-scrollbar-thumb {
631
+ background: rgba(0, 0, 0, 0.0);
632
+ border-radius: 5px;
633
+ }
634
+
635
+ nav.sidebar:hover::-webkit-scrollbar-thumb {
636
+ background-color: #999;
637
+ background: -webkit-linear-gradient(left, #aaa, #999);
638
+ }
639
+
640
+ .console pre:hover::-webkit-scrollbar-thumb,
641
+ .inset pre:hover::-webkit-scrollbar-thumb,
642
+ .code:hover::-webkit-scrollbar-thumb {
643
+ background: #888;
644
+ }
645
+
646
+
199
647
  </style>
200
648
  </head>
201
649
  <body>
202
- <header>
203
- <h2><%= exception.class %> <span>at <%= request_path %></span></h2>
204
- <table>
205
- <tr>
206
- <th>Message</th>
207
- <td><%= exception.message %></td>
208
- </tr>
209
- <% if backtrace_frames.any? %>
210
- <tr>
211
- <th>File</th>
212
- <td><%= backtrace_frames.first.filename %></td>
213
- </tr>
214
- <tr>
215
- <th>Line</th>
216
- <td><%= backtrace_frames.first.line %></td>
217
- </tr>
218
- <% end %>
219
- </table>
220
- </header>
221
- <nav>
222
- <a href="#" id="application_frames">Application Frames</a>
223
- <a href="#" id="all_frames">All Frames</a>
224
- </nav>
650
+ <div class='top'>
651
+ <header class="exception">
652
+ <h2><strong><%= exception.class %></strong> <span>at <%= request_path %></span></h2>
653
+ <p><%= exception_message %></p>
654
+ </header>
655
+ </div>
656
+
225
657
  <section class="backtrace">
226
- <ul class="frames">
227
- <% backtrace_frames.each_with_index do |frame, index| %>
228
- <li
229
- data-context="<%= frame.context %>"
230
- data-full-filename="<%= frame.filename %>"
231
- data-filename="<%= frame.pretty_path %>"
232
- data-line="<%= frame.line %>"
233
- data-name="<%= frame.name %>"
234
- data-index="<%= index %>"
235
- >
236
- <div class="name"><%= frame.name %></div>
237
- <div class="location"><span class="filename"><%= frame.pretty_path %></span>, line <span class="line"><%= frame.line %></span></div>
238
- </li>
239
- <% end %>
240
- </ul>
658
+ <nav class="sidebar">
659
+ <nav class="tabs">
660
+ <a href="#" id="application_frames">Application Frames</a>
661
+ <a href="#" id="all_frames">All Frames</a>
662
+ </nav>
663
+ <ul class="frames">
664
+ <% backtrace_frames.each_with_index do |frame, index| %>
665
+ <li
666
+ class="<%= frame.context %>"
667
+ style="display: none"
668
+ data-context="<%= frame.context %>"
669
+ data-full-filename="<%= frame.filename %>"
670
+ data-filename="<%= frame.pretty_path %>"
671
+ data-line="<%= frame.line %>"
672
+ data-name="<%= frame.name %>"
673
+ data-index="<%= index %>"
674
+ >
675
+ <span class='stroke'></span>
676
+ <i class="icon <%= frame.context %>"></i>
677
+ <div class="info">
678
+ <div class="name">
679
+ <strong><%= frame.class_name %></strong><span class='method'><%= frame.method_name %></span>
680
+ </div>
681
+ <div class="location">
682
+ <span class="filename"><%= frame.pretty_path %></span>, line <span class="line"><%= frame.line %></span>
683
+ </div>
684
+ </div>
685
+ </li>
686
+ <% end %>
687
+ </ul>
688
+ </nav>
689
+
241
690
  <% backtrace_frames.each_with_index do |frame, index| %>
242
691
  <div class="frame_info" id="frame_info_<%= index %>" style="display:none;">
243
- <h2 class="name"><%= frame.name %></h2>
244
- <div class="location"><span class="filename"><%= frame.pretty_path %></span>, line <span class="line"><%= frame.line %></span></div>
245
- <%== highlighted_code_block frame %>
692
+ <header class="trace_info">
693
+ <div class="title">
694
+ <h2 class="name"><%= frame.name %></h2>
695
+ <div class="location"><span class="filename"><%= frame.pretty_path %></span></div>
696
+ </div>
697
+
698
+ <%== highlighted_code_block frame %>
246
699
 
247
- <% if BetterErrors.binding_of_caller_available? %>
248
- <div class="repl">
249
- <h3>REPL</h3>
250
- <div class="console">
251
- <pre></pre>
252
- <div class="prompt"><span>&gt;&gt;</span> <input/></div>
700
+ <% if BetterErrors.binding_of_caller_available? && frame.frame_binding %>
701
+ <div class="repl">
702
+ <div class="console">
703
+ <pre></pre>
704
+ <div class="prompt"><span>&gt;&gt;</span> <input/></div>
705
+ </div>
253
706
  </div>
707
+ <% end %>
708
+ </header>
709
+
710
+ <% if BetterErrors.binding_of_caller_available? && frame.frame_binding %>
711
+ <div class="hint">
712
+ This a live shell. Type in here.
254
713
  </div>
255
714
 
256
715
  <div class="variable_info"></div>
257
- <% else %>
258
- <h3>Advanced features unavailable</h3>
259
- <p class="error">
260
- You must add <code>gem "binding_of_caller"</code> to your Gemfile to enable the REPL and local/instance variable inspection.
261
- </p>
716
+ <% end %>
717
+
718
+ <% unless BetterErrors.binding_of_caller_available? %>
719
+ <div class="hint">
720
+ <strong>Tip:</strong> add <code>gem "binding_of_caller"</code> to your Gemfile to enable the REPL and local/instance variable inspection.
721
+ </div>
262
722
  <% end %>
263
723
  </div>
264
724
  <% end %>
@@ -446,7 +906,11 @@
446
906
  })(i);
447
907
  }
448
908
 
449
- allFrames[0].click();
909
+ // Click the first application frame
910
+ (
911
+ document.querySelector(".frames li.application") ||
912
+ document.querySelector(".frames li")
913
+ ).click();
450
914
 
451
915
  var applicationFramesButton = document.getElementById("application_frames");
452
916
  var allFramesButton = document.getElementById("all_frames");
@@ -1,13 +1,21 @@
1
- <h3>Local Variables</h3>
2
- <table class="var_table">
3
- <% @frame.local_variables.each do |name, value| %>
4
- <tr><td class="name"><%= name %></td><td><pre><%= value.inspect %></pre></td></tr>
5
- <% end %>
6
- </table>
1
+ <div class="sub">
2
+ <h3>Local Variables</h3>
3
+ <div class='inset variables'>
4
+ <table class="var_table">
5
+ <% @frame.local_variables.each do |name, value| %>
6
+ <tr><td class="name"><%= name %></td><td><pre><%= value.inspect %></pre></td></tr>
7
+ <% end %>
8
+ </table>
9
+ </div>
10
+ </div>
7
11
 
8
- <h3>Instance Variables</h3>
9
- <table class="var_table">
10
- <% @frame.instance_variables.each do |name, value| %>
11
- <tr><td class="name"><%= name %></td><td><pre><%= value.inspect %></pre></td></tr>
12
- <% end %>
13
- </table>
12
+ <div class="sub">
13
+ <h3>Instance Variables</h3>
14
+ <div class="inset variables">
15
+ <table class="var_table">
16
+ <% @frame.instance_variables.each do |name, value| %>
17
+ <tr><td class="name"><%= name %></td><td><pre><%= value.inspect %></pre></td></tr>
18
+ <% end %>
19
+ </table>
20
+ </div>
21
+ </div>
@@ -1,3 +1,3 @@
1
1
  module BetterErrors
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/better_errors.rb CHANGED
@@ -22,12 +22,12 @@ rescue LoadError => e
22
22
  BetterErrors.binding_of_caller_available = false
23
23
  end
24
24
 
25
- if BetterErrors.binding_of_caller_available?
26
- require "better_errors/core_ext/exception"
27
- else
25
+ unless BetterErrors.binding_of_caller_available?
28
26
  warn "BetterErrors: binding_of_caller gem unavailable, cannot display local variables on error pages."
29
27
  warn "Add 'binding_of_caller' to your Gemfile to make this warning go away."
30
28
  warn ""
31
29
  end
32
30
 
31
+ require "better_errors/core_ext/exception"
32
+
33
33
  require "better_errors/rails" if defined? Rails::Railtie
@@ -57,5 +57,28 @@ module BetterErrors
57
57
  frame.gem_path.should == "(gem) whatever-1.2.3/lib/whatever.rb"
58
58
  end
59
59
  end
60
+
61
+ it "should special case SyntaxErrors" do
62
+ syntax_error = SyntaxError.new "my_file.rb:123: you wrote bad ruby!"
63
+ syntax_error.stub!(:backtrace).and_return([])
64
+ frames = StackFrame.from_exception(syntax_error)
65
+ frames.count.should == 1
66
+ frames.first.filename.should == "my_file.rb"
67
+ frames.first.line.should == 123
68
+ end
69
+
70
+ it "should not blow up if no method name is given" do
71
+ error = StandardError.new
72
+
73
+ error.stub!(:backtrace).and_return(["foo.rb:123"])
74
+ frames = StackFrame.from_exception(error)
75
+ frames.first.filename.should == "foo.rb"
76
+ frames.first.line.should == 123
77
+
78
+ error.stub!(:backtrace).and_return(["foo.rb:123: this is an error message"])
79
+ frames = StackFrame.from_exception(error)
80
+ frames.first.filename.should == "foo.rb"
81
+ frames.first.line.should == 123
82
+ end
60
83
  end
61
84
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: better_errors
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -127,3 +127,4 @@ test_files:
127
127
  - spec/better_errors/stack_frame_spec.rb
128
128
  - spec/better_errors/support/my_source.rb
129
129
  - spec/spec_helper.rb
130
+ has_rdoc: