better_errors 0.0.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of better_errors might be problematic. Click here for more details.

data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ *.gem
2
+ tmp
3
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source :rubygems
2
+
3
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Charlie Somerville
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,47 @@
1
+ # Better Errors
2
+
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.
4
+
5
+ ![image](http://i.imgur.com/1GepF.png)
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'better_errors'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install better_errors
20
+
21
+ ## Usage
22
+
23
+ If you're using Rails, there's nothing else you need to do.
24
+
25
+ If you're not using Rails, you need to insert `BetterErrors::Middleware` into your middleware stack, and optionally set `BetterErrors.application_root` if you'd like Better Errors to abbreviate filenames within your application.
26
+
27
+ Here's an example using Sinatra:
28
+
29
+ ```ruby
30
+ require "sinatra"
31
+ require "better_errors"
32
+
33
+ use BetterErrors::Middleware
34
+ BetterErrors.application_root = File.expand_path("..", __FILE__)
35
+
36
+ get "/" do
37
+ raise "oops"
38
+ end
39
+ ```
40
+
41
+ ## Contributing
42
+
43
+ 1. Fork it
44
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
45
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
46
+ 4. Push to the branch (`git push origin my-new-feature`)
47
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'better_errors/version'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "better_errors"
8
+ s.version = BetterErrors::VERSION
9
+ s.authors = ["Charlie Somerville"]
10
+ s.email = ["charlie@charliesomerville.com"]
11
+ s.description = %q{Better Errors gives Rails a better error page.}
12
+ s.summary = %q{Better Errors gives Rails a better error page}
13
+ s.homepage = "https://github.com/charliesome/better_errors"
14
+ s.license = "MIT"
15
+
16
+ s.files = `git ls-files`.split($/)
17
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
18
+ s.require_paths = ["lib"]
19
+
20
+ s.add_development_dependency "rake"
21
+
22
+ s.add_dependency "erubis"
23
+ s.add_dependency "coderay"
24
+ # optional dependency:
25
+ # s.add_dependency "binding_of_caller"
26
+ end
@@ -0,0 +1,31 @@
1
+ require "pp"
2
+ require "erubis"
3
+ require "coderay"
4
+
5
+ require "better_errors/version"
6
+ require "better_errors/error_page"
7
+ require "better_errors/error_frame"
8
+ require "better_errors/middleware"
9
+
10
+ class << BetterErrors
11
+ attr_accessor :application_root, :binding_of_caller_available
12
+
13
+ alias_method :binding_of_caller_available?, :binding_of_caller_available
14
+ end
15
+
16
+ begin
17
+ require "binding_of_caller"
18
+ BetterErrors.binding_of_caller_available = true
19
+ rescue LoadError => e
20
+ BetterErrors.binding_of_caller_available = false
21
+ end
22
+
23
+ if BetterErrors.binding_of_caller_available?
24
+ require "better_errors/core_ext/exception"
25
+ else
26
+ warn "BetterErrors: binding_of_caller gem unavailable, cannot display local variables on error pages."
27
+ warn "Add 'binding_of_caller' to your Gemfile to make this warning go away."
28
+ warn ""
29
+ end
30
+
31
+ require "better_errors/rails" if defined? Rails::Railtie
@@ -0,0 +1,20 @@
1
+ class Exception
2
+ attr_reader :__better_errors_bindings_stack
3
+
4
+ original_initialize = instance_method(:initialize)
5
+
6
+ define_method :initialize do |*args|
7
+ unless Thread.current[:__better_errors_exception_lock]
8
+ Thread.current[:__better_errors_exception_lock] = true
9
+ begin
10
+ @__better_errors_bindings_stack = []
11
+ 2.upto(caller.size) do |index|
12
+ @__better_errors_bindings_stack << binding.of_caller(index) rescue break
13
+ end
14
+ ensure
15
+ Thread.current[:__better_errors_exception_lock] = false
16
+ end
17
+ end
18
+ original_initialize.bind(self).call(*args)
19
+ end
20
+ end
@@ -0,0 +1,72 @@
1
+ module BetterErrors
2
+ class ErrorFrame
3
+ def self.from_exception(exception)
4
+ exception.backtrace.each_with_index.map { |frame, idx|
5
+ next unless frame =~ /\A(.*):(\d*):in `(.*)'\z/
6
+ ErrorFrame.new($1, $2.to_i, $3, exception.__better_errors_bindings_stack[idx])
7
+ }.compact
8
+ end
9
+
10
+ attr_reader :filename, :line, :name, :frame_binding
11
+
12
+ def initialize(filename, line, name, frame_binding)
13
+ @filename = filename
14
+ @line = line
15
+ @name = name
16
+ @frame_binding = frame_binding
17
+ end
18
+
19
+ def application?
20
+ starts_with? filename, BetterErrors.application_root if BetterErrors.application_root
21
+ end
22
+
23
+ def application_path
24
+ filename[(BetterErrors.application_root.length+1)..-1]
25
+ end
26
+
27
+ def gem?
28
+ Gem.path.any? { |path| starts_with? filename, path }
29
+ end
30
+
31
+ def gem_path
32
+ Gem.path.each do |path|
33
+ if starts_with? filename, path
34
+ return filename.gsub("#{path}/gems/", "(gem) ")
35
+ end
36
+ end
37
+ end
38
+
39
+ def context
40
+ if application?
41
+ :application
42
+ elsif gem?
43
+ :gem
44
+ else
45
+ :dunno
46
+ end
47
+ end
48
+
49
+ def pretty_path
50
+ case context
51
+ when :application; application_path
52
+ when :gem; gem_path
53
+ else filename
54
+ end
55
+ end
56
+
57
+ def local_variables
58
+ return {} unless frame_binding
59
+ Hash[frame_binding.eval("local_variables").map { |x| [x, frame_binding.eval(x.to_s)] }]
60
+ end
61
+
62
+ def instance_variables
63
+ return {} unless frame_binding
64
+ Hash[frame_binding.eval("instance_variables").map { |x| [x, frame_binding.eval(x.to_s)] }]
65
+ end
66
+
67
+ private
68
+ def starts_with?(haystack, needle)
69
+ haystack[0, needle.length] == needle
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,244 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title><%= exception.class %> at <%= request_path %></title>
5
+ <style>
6
+ * {
7
+ margin:0;
8
+ padding:0;
9
+ }
10
+ 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 #ea6756;
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
+ .frames {
45
+ width:50%;
46
+ float:left;
47
+ }
48
+ .frames li {
49
+ list-style:none;
50
+ display:block;
51
+ padding:12px;
52
+ overflow:hidden;
53
+ cursor:pointer;
54
+ background-color: #f4f7ff;
55
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#f4f7ff), to(#e4ebfe)); /* Safari 4+, Chrome */
56
+ background-image: -webkit-linear-gradient(top, #f4f7ff, #e4ebfe); /* Chrome 10+, Safari 5.1+, iOS 5+ */
57
+ background-image: -moz-linear-gradient(top, #f4f7ff, #e4ebfe); /* Firefox 3.6-15 */
58
+ background-image: -o-linear-gradient(top, #f4f7ff, #e4ebfe); /* Opera 11.10-12.00 */
59
+ background-image: linear-gradient(to bottom, #f4f7ff, #e4ebfe); /* Firefox 16+, IE10, Opera 12.50+ */
60
+ border-bottom:1px solid #cccccc;
61
+ }
62
+ .frames li:hover, .frames li.selected {
63
+ background-color: #e4ebfe;
64
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#e4ebfe), to(#c2d3fe)); /* Safari 4+, Chrome */
65
+ background-image: -webkit-linear-gradient(top, #e4ebfe, #c2d3fe); /* Chrome 10+, Safari 5.1+, iOS 5+ */
66
+ background-image: -moz-linear-gradient(top, #e4ebfe, #c2d3fe); /* Firefox 3.6-15 */
67
+ background-image: -o-linear-gradient(top, #e4ebfe, #c2d3fe); /* Opera 11.10-12.00 */
68
+ background-image: linear-gradient(to bottom, #e4ebfe, #c2d3fe); /* Firefox 16+, IE10, Opera 12.50+ */
69
+ }
70
+ .frames .name, .frame_info h2.name {
71
+ font-family:Monaco, Incosolata, Consolas, monospace;
72
+ font-size:14px;
73
+ margin-bottom:4px;
74
+ }
75
+ .location {
76
+ color:#888888;
77
+ }
78
+ .location .filename, .location .line {
79
+ color:#333333;
80
+ }
81
+ .frame_info {
82
+ background-color:#efefef;
83
+ border-bottom:1px solid #cccccc;
84
+ float:left;
85
+ width:50%;
86
+ }
87
+ .frame_info > * {
88
+ margin:16px;
89
+ }
90
+ .frame_info h2 {
91
+ font-family:Monaco, Incosolata, Consolas, monospace;
92
+ }
93
+ .frame_info .code {
94
+ font-family:Monaco, Incosolata, Consolas, monospace;
95
+ background-color:#ffffff;
96
+ border:1px solid #cccccc;
97
+ border-collapse:collapse;
98
+ overflow:auto;
99
+ }
100
+ .frame_info .code pre:nth-child(2n+1) {
101
+ background-color:#f9f9f9;
102
+ }
103
+ .frame_info .code pre:nth-child(2n) {
104
+ background-color:#f3f3f3;
105
+ }
106
+ .frame_info .code pre.highlight {
107
+ background-color:#ffeaaa;
108
+ }
109
+ .frame_info .code .line {
110
+ text-align:right;
111
+ padding-right:12px;
112
+ padding-left:0px;
113
+ }
114
+ code {
115
+ background-color:#f0f0f0;
116
+ padding:2px 4px;
117
+ border:1px solid #d0d0d0;
118
+ }
119
+ h3 {
120
+ font-weight:normal;
121
+ border-top:1px solid #cccccc;
122
+ padding-top:16px;
123
+ }
124
+ .var_table {
125
+ border-collapse:collapse;
126
+ }
127
+ .var_table td {
128
+ padding:8px;
129
+ }
130
+ .var_table td.name {
131
+ font-style:italic;
132
+ }
133
+ .var_table tr {
134
+ border-bottom:1px solid #cccccc;
135
+ }
136
+ </style>
137
+ </head>
138
+ <body>
139
+ <header>
140
+ <h2><%= exception.class %> <span>at <%= request_path %></span></h2>
141
+ <table>
142
+ <tr>
143
+ <th>Message</th>
144
+ <td><%= exception.message %></td>
145
+ </tr>
146
+ <% if backtrace_frames.any? %>
147
+ <tr>
148
+ <th>File</th>
149
+ <td><%= backtrace_frames.first.filename %></td>
150
+ </tr>
151
+ <tr>
152
+ <th>Line</th>
153
+ <td><%= backtrace_frames.first.line %></td>
154
+ </tr>
155
+ <% end %>
156
+ </table>
157
+ </header>
158
+ <section class="backtrace">
159
+ <ul class="frames">
160
+ <% backtrace_frames.each_with_index do |frame, index| %>
161
+ <li
162
+ data-context="<%= frame.context %>"
163
+ data-full-filename="<%= frame.filename %>"
164
+ data-filename="<%= frame.pretty_path %>"
165
+ data-line="<%= frame.line %>"
166
+ data-name="<%= frame.name %>"
167
+ data-index="<%= index %>"
168
+ >
169
+ <div class="name"><%= frame.name %></div>
170
+ <div class="location"><span class="filename"><%= frame.pretty_path %></span>, line <span class="line"><%= frame.line %></span></div>
171
+ </li>
172
+ <% end %>
173
+ </ul>
174
+ <% backtrace_frames.each_with_index do |frame, index| %>
175
+ <div class="frame_info" id="frame_info_<%= index %>" style="display:none;">
176
+ <h2 class="name"><%= frame.name %></h2>
177
+ <div class="location"><span class="filename"><%= frame.pretty_path %></span>, line <span class="line"><%= frame.line %></span></div>
178
+ <%== highlighted_code_block frame %>
179
+
180
+ <h3>Local Variables</h3>
181
+ <table class="var_table">
182
+ <% frame.local_variables.each do |name, value| %>
183
+ <tr><td class="name"><%= name %></td><td><pre><%= value.inspect %></pre></td></tr>
184
+ <% end %>
185
+ </table>
186
+
187
+ <h3>Instance Variables</h3>
188
+ <table class="var_table">
189
+ <% frame.instance_variables.each do |name, value| %>
190
+ <tr><td class="name"><%= name %></td><td><pre><%= value.inspect %></pre></td></tr>
191
+ <% end %>
192
+ </table>
193
+ </div>
194
+ <% end %>
195
+ <div style="clear:both"></div>
196
+ </section>
197
+ </body>
198
+ <script>
199
+ (function() {
200
+ var previous = null;
201
+ var previousFrameInfo = null;
202
+ var frames = document.querySelectorAll("ul.frames li");
203
+
204
+ var header = document.querySelector("header");
205
+ var headerHeight = header.offsetHeight;
206
+
207
+ function selectFrameInfo(index) {
208
+ var el = document.getElementById("frame_info_" + index);
209
+
210
+ if(previousFrameInfo) {
211
+ previousFrameInfo.style.display = "none";
212
+ }
213
+ previousFrameInfo = el;
214
+ previousFrameInfo.style.display = "block";
215
+ }
216
+
217
+ function updateMarginTop() {
218
+ return;
219
+ if(previousFrameInfo) {
220
+ previousFrameInfo.style.marginTop = Math.max(window.scrollY - headerHeight, 0) + "px";
221
+ }
222
+ }
223
+
224
+ window.onscroll = updateMarginTop;
225
+
226
+ for(var i = 0; i < frames.length; i++) {
227
+ (function(el) {
228
+ el.onclick = function() {
229
+ if(previous) {
230
+ previous.className = "";
231
+ }
232
+ el.className = "selected";
233
+ previous = el;
234
+
235
+ selectFrameInfo(el.attributes["data-index"].value);
236
+ updateMarginTop();
237
+ };
238
+ })(frames[i]);
239
+ }
240
+
241
+ document.querySelector(".frames li:first-child").click();
242
+ })();
243
+ </script>
244
+ </html>
@@ -0,0 +1,82 @@
1
+ require "json"
2
+
3
+ module BetterErrors
4
+ class ErrorPage
5
+ def self.template_path
6
+ __FILE__.gsub(/\.rb$/, ".erb")
7
+ end
8
+
9
+ def self.template
10
+ Erubis::EscapedEruby.new(File.read(template_path))
11
+ end
12
+
13
+ attr_reader :exception, :env
14
+
15
+ def initialize(exception, env)
16
+ @exception = real_exception(exception)
17
+ @env = env
18
+ end
19
+
20
+ def render
21
+ self.class.template.result binding
22
+ end
23
+
24
+ private
25
+ def real_exception(exception)
26
+ loop do
27
+ case exception
28
+ when ActionView::Template::Error; exception = exception.original_exception
29
+ else
30
+ return exception
31
+ end
32
+ end
33
+ end
34
+
35
+ def request_path
36
+ env["REQUEST_PATH"]
37
+ end
38
+
39
+ def backtrace_frames
40
+ @backtrace_frames ||= ErrorFrame.from_exception(exception)
41
+ end
42
+
43
+ def coderay_scanner_for_ext(ext)
44
+ case ext
45
+ when "rb"; :ruby
46
+ when "html"; :html
47
+ when "erb"; :erb
48
+ when "haml"; :haml
49
+ end
50
+ end
51
+
52
+ def file_extension(filename)
53
+ filename.split(".").last
54
+ end
55
+
56
+ def code_extract(frame, lines_of_context = 5)
57
+ lines = File.readlines(frame.filename)
58
+ min_line = [1, frame.line - lines_of_context].max - 1
59
+ max_line = [frame.line + lines_of_context, lines.count + 1].min - 1
60
+ [min_line, max_line, lines[min_line..max_line].join]
61
+ end
62
+
63
+ def highlighted_code_block(frame)
64
+ ext = file_extension(frame.filename)
65
+ scanner = coderay_scanner_for_ext(ext)
66
+ min_line, max_line, code = code_extract(frame)
67
+ highlighted_code = CodeRay.scan(code, scanner).div wrap: nil
68
+ "".tap do |html|
69
+ html << "<div class='code'>"
70
+ highlighted_code.each_line.each_with_index do |str, index|
71
+ if min_line + index + 1 == frame.line
72
+ html << "<pre class='highlight'>"
73
+ else
74
+ html << "<pre>"
75
+ end
76
+ html << sprintf("%5d", min_line + index + 1) << " " << str << "</pre>"
77
+ end
78
+ html << "</div>"
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,15 @@
1
+ module BetterErrors
2
+ class Middleware
3
+ def initialize(app, handler = ErrorPage)
4
+ @app = app
5
+ @handler = handler
6
+ end
7
+
8
+ def call(env)
9
+ @app.call env
10
+ rescue Exception => ex
11
+ error_page = @handler.new ex, env
12
+ [500, { "Content-Type" => "text/html; charset=utf-8" }, [error_page.render]]
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,10 @@
1
+ module BetterErrors
2
+ class Railtie < Rails::Railtie
3
+ initializer "better_errors.configure_rails_initialization" do
4
+ middleware = Rails.application.middleware
5
+ middleware.use BetterErrors::Middleware
6
+
7
+ BetterErrors.application_root = Rails.root.to_s
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ module BetterErrors
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,61 @@
1
+ require "spec_helper"
2
+
3
+ module BetterErrors
4
+ describe ErrorFrame do
5
+ context "#application?" do
6
+ it "should be true for application filenames" do
7
+ BetterErrors.stub!(:application_root).and_return("/abc/xyz")
8
+ frame = ErrorFrame.new("/abc/xyz/app/controllers/crap_controller.rb", 123, "index")
9
+
10
+ frame.application?.should be_true
11
+ end
12
+
13
+ it "should be false for everything else" do
14
+ BetterErrors.stub!(:application_root).and_return("/abc/xyz")
15
+ frame = ErrorFrame.new("/abc/nope", 123, "foo")
16
+
17
+ frame.application?.should be_false
18
+ end
19
+
20
+ it "should not care if no application_root is set" do
21
+ frame = ErrorFrame.new("/abc/xyz/app/controllers/crap_controller.rb", 123, "index")
22
+
23
+ frame.application?.should be_false
24
+ end
25
+ end
26
+
27
+ context "#gem?" do
28
+ it "should be true for gem filenames" do
29
+ Gem.stub!(:path).and_return(["/abc/xyz"])
30
+ frame = ErrorFrame.new("/abc/xyz/gems/whatever-1.2.3/lib/whatever.rb", 123, "foo")
31
+
32
+ frame.gem?.should be_true
33
+ end
34
+
35
+ it "should be false for everything else" do
36
+ Gem.stub!(:path).and_return(["/abc/xyz"])
37
+ frame = ErrorFrame.new("/abc/nope", 123, "foo")
38
+
39
+ frame.gem?.should be_false
40
+ end
41
+ end
42
+
43
+ context "#application_path" do
44
+ it "should chop off the application root" do
45
+ BetterErrors.stub!(:application_root).and_return("/abc/xyz")
46
+ frame = ErrorFrame.new("/abc/xyz/app/controllers/crap_controller.rb", 123, "index")
47
+
48
+ frame.application_path.should == "app/controllers/crap_controller.rb"
49
+ end
50
+ end
51
+
52
+ context "#gem_path" do
53
+ it "should chop of the gem path and stick (gem) there" do
54
+ Gem.stub!(:path).and_return(["/abc/xyz"])
55
+ frame = ErrorFrame.new("/abc/xyz/gems/whatever-1.2.3/lib/whatever.rb", 123, "foo")
56
+
57
+ frame.gem_path.should == "(gem) whatever-1.2.3/lib/whatever.rb"
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,45 @@
1
+ require "spec_helper"
2
+
3
+ module BetterErrors
4
+ describe ErrorPage do
5
+ let(:exception) { raise ZeroDivisionError, "you divided by zero you silly goose!" rescue $! }
6
+
7
+ let(:error_page) { ErrorPage.new exception, { "REQUEST_PATH" => "/some/path" } }
8
+
9
+ let(:response) { error_page.render }
10
+
11
+ it "should include the error message" do
12
+ response.should include("you divided by zero you silly goose!")
13
+ end
14
+
15
+ it "should include the request path" do
16
+ response.should include("/some/path")
17
+ end
18
+
19
+ it "should include the exception class" do
20
+ response.should include("ZeroDivisionError")
21
+ end
22
+
23
+ context "when showing source code" do
24
+ before do
25
+ exception.stub!(:backtrace).and_return([
26
+ "#{File.expand_path("../support/my_source.rb", __FILE__)}:8:in `some_method'"
27
+ ])
28
+ end
29
+
30
+ it "should show the line where the exception was raised" do
31
+ response.should include("8 eight")
32
+ end
33
+
34
+ it "should show five lines of context" do
35
+ response.should include("3 three")
36
+ response.should include("13 thirteen")
37
+ end
38
+
39
+ it "should not show more than five lines of context" do
40
+ response.should_not include("2 two")
41
+ response.should_not include("14 fourteen")
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,26 @@
1
+ require "spec_helper"
2
+
3
+ module BetterErrors
4
+ describe Middleware do
5
+ it "should pass non-error responses through" do
6
+ app = Middleware.new(->env { ":)" })
7
+ app.call({}).should == ":)"
8
+ end
9
+
10
+ context "when handling an error" do
11
+ let(:app) { Middleware.new(->env { raise "oh no :(" }) }
12
+
13
+ it "should return status 500" do
14
+ status, headers, body = app.call({})
15
+
16
+ status.should == 500
17
+ end
18
+
19
+ it "should return UTF-8 error pages" do
20
+ status, headers, body = app.call({})
21
+
22
+ headers["Content-Type"].should == "text/html; charset=utf-8"
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,20 @@
1
+ one
2
+ two
3
+ three
4
+ four
5
+ five
6
+ six
7
+ seven
8
+ eight
9
+ nine
10
+ ten
11
+ eleven
12
+ twelve
13
+ thirteen
14
+ fourteen
15
+ fifteen
16
+ sixteen
17
+ seventeen
18
+ eighteen
19
+ nineteen
20
+ twenty
@@ -0,0 +1,3 @@
1
+ $: << File.expand_path("../../lib", __FILE__)
2
+ require "better_errors"
3
+ require "ostruct"
metadata ADDED
@@ -0,0 +1,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: better_errors
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Charlie Somerville
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-12-08 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: erubis
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: coderay
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: Better Errors gives Rails a better error page.
63
+ email:
64
+ - charlie@charliesomerville.com
65
+ executables: []
66
+ extensions: []
67
+ extra_rdoc_files: []
68
+ files:
69
+ - .gitignore
70
+ - Gemfile
71
+ - LICENSE.txt
72
+ - README.md
73
+ - Rakefile
74
+ - better_errors.gemspec
75
+ - lib/better_errors.rb
76
+ - lib/better_errors/core_ext/exception.rb
77
+ - lib/better_errors/error_frame.rb
78
+ - lib/better_errors/error_page.erb
79
+ - lib/better_errors/error_page.rb
80
+ - lib/better_errors/middleware.rb
81
+ - lib/better_errors/rails.rb
82
+ - lib/better_errors/version.rb
83
+ - spec/better_errors/error_frame_spec.rb
84
+ - spec/better_errors/error_page_spec.rb
85
+ - spec/better_errors/middleware_spec.rb
86
+ - spec/better_errors/support/my_source.rb
87
+ - spec/spec_helper.rb
88
+ homepage: https://github.com/charliesome/better_errors
89
+ licenses:
90
+ - MIT
91
+ post_install_message:
92
+ rdoc_options: []
93
+ require_paths:
94
+ - lib
95
+ required_ruby_version: !ruby/object:Gem::Requirement
96
+ none: false
97
+ requirements:
98
+ - - ! '>='
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ none: false
103
+ requirements:
104
+ - - ! '>='
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ requirements: []
108
+ rubyforge_project:
109
+ rubygems_version: 1.8.24
110
+ signing_key:
111
+ specification_version: 3
112
+ summary: Better Errors gives Rails a better error page
113
+ test_files:
114
+ - spec/better_errors/error_frame_spec.rb
115
+ - spec/better_errors/error_page_spec.rb
116
+ - spec/better_errors/middleware_spec.rb
117
+ - spec/better_errors/support/my_source.rb
118
+ - spec/spec_helper.rb
119
+ has_rdoc: