better_errors 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.

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: