better_errors 1.1.0 → 2.0.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.
Potentially problematic release.
This version of better_errors might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.gitignore +7 -5
- data/.travis.yml +1 -3
- data/Gemfile +1 -1
- data/LICENSE.txt +1 -1
- data/README.md +3 -1
- data/Rakefile +12 -3
- data/better_errors.gemspec +3 -3
- data/lib/better_errors.rb +5 -5
- data/lib/better_errors/error_page.rb +22 -33
- data/lib/better_errors/exception_extension.rb +17 -0
- data/lib/better_errors/middleware.rb +7 -7
- data/lib/better_errors/raised_exception.rb +66 -0
- data/lib/better_errors/repl/pry.rb +2 -2
- data/lib/better_errors/stack_frame.rb +6 -55
- data/lib/better_errors/templates/main.erb +4 -4
- data/lib/better_errors/templates/text.erb +2 -2
- data/lib/better_errors/version.rb +1 -1
- data/spec/better_errors/middleware_spec.rb +8 -0
- data/spec/better_errors/raised_exception_spec.rb +52 -0
- data/spec/better_errors/stack_frame_spec.rb +26 -30
- data/spec/spec_helper.rb +2 -4
- data/spec/without_binding_of_caller.rb +9 -0
- metadata +33 -15
- data/lib/better_errors/core_ext/exception.rb +0 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bc36d3113c7041816a7697fbd1e50333f5976003
|
4
|
+
data.tar.gz: 834f3f4a4903a45f150d83adde3f25452d2fd86b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 130d61a4ce2e5509eb1585dfa0e3c620bf54387ac6a0931d1a534296460a0e06601a6d71ce41b3d3ffbd15951626ddfd7e753bb1bc911c35cf76cfa52cfcd771
|
7
|
+
data.tar.gz: 5906697a352187036b92cdefe124fea459405d7e3cc80f3bcc6f07c7a2952f328367f452e88272947edef464a4cc75fbe3d276c24580b9b633b6f9e60c99a60d
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Better Errors [](https://rubygems.org/gems/better_errors) [](https://travis-ci.org/charliesome/better_errors) [](https://codeclimate.com/github/charliesome/better_errors)
|
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
|
|
@@ -29,6 +29,8 @@ gem "binding_of_caller"
|
|
29
29
|
|
30
30
|
This is an optional dependency however, and Better Errors will work without it.
|
31
31
|
|
32
|
+
_Note: If you discover that Better Errors isn't working - particularly after upgrading from version 0.5.0 or less - be sure to set `config.consider_all_requests_local = true` in `config/environments/development.rb`._
|
33
|
+
|
32
34
|
## Security
|
33
35
|
|
34
36
|
**NOTE:** It is *critical* you put better\_errors in the **development** section. **Do NOT run better_errors in production, or on Internet facing hosts.**
|
data/Rakefile
CHANGED
@@ -1,4 +1,13 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
|
-
|
3
|
-
|
4
|
-
|
2
|
+
require "rspec/core/rake_task"
|
3
|
+
|
4
|
+
namespace :test do
|
5
|
+
RSpec::Core::RakeTask.new(:with_binding_of_caller)
|
6
|
+
|
7
|
+
without_task = RSpec::Core::RakeTask.new(:without_binding_of_caller)
|
8
|
+
without_task.ruby_opts = "-I spec -r without_binding_of_caller"
|
9
|
+
|
10
|
+
task :all => [:with_binding_of_caller, :without_binding_of_caller]
|
11
|
+
end
|
12
|
+
|
13
|
+
task :default => "test:all"
|
data/better_errors.gemspec
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
1
|
lib = File.expand_path('../lib', __FILE__)
|
3
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
3
|
require 'better_errors/version'
|
@@ -17,10 +16,11 @@ Gem::Specification.new do |s|
|
|
17
16
|
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
18
17
|
s.require_paths = ["lib"]
|
19
18
|
|
20
|
-
s.required_ruby_version = ">=
|
21
|
-
|
19
|
+
s.required_ruby_version = ">= 2.0.0"
|
20
|
+
|
22
21
|
s.add_dependency "erubis", ">= 2.6.6"
|
23
22
|
s.add_dependency "coderay", ">= 1.0.0"
|
23
|
+
s.add_dependency "rack", ">= 0.9.0"
|
24
24
|
|
25
25
|
# optional dependencies:
|
26
26
|
# s.add_dependency "binding_of_caller"
|
data/lib/better_errors.rb
CHANGED
@@ -3,12 +3,13 @@ require "erubis"
|
|
3
3
|
require "coderay"
|
4
4
|
require "uri"
|
5
5
|
|
6
|
-
require "better_errors/
|
6
|
+
require "better_errors/code_formatter"
|
7
7
|
require "better_errors/error_page"
|
8
|
-
require "better_errors/stack_frame"
|
9
8
|
require "better_errors/middleware"
|
10
|
-
require "better_errors/
|
9
|
+
require "better_errors/raised_exception"
|
11
10
|
require "better_errors/repl"
|
11
|
+
require "better_errors/stack_frame"
|
12
|
+
require "better_errors/version"
|
12
13
|
|
13
14
|
module BetterErrors
|
14
15
|
POSSIBLE_EDITOR_PRESETS = [
|
@@ -136,11 +137,10 @@ end
|
|
136
137
|
|
137
138
|
begin
|
138
139
|
require "binding_of_caller"
|
140
|
+
require "better_errors/exception_extension"
|
139
141
|
BetterErrors.binding_of_caller_available = true
|
140
142
|
rescue LoadError => e
|
141
143
|
BetterErrors.binding_of_caller_available = false
|
142
144
|
end
|
143
145
|
|
144
|
-
require "better_errors/core_ext/exception"
|
145
|
-
|
146
146
|
require "better_errors/rails" if defined? Rails::Railtie
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require "cgi"
|
2
2
|
require "json"
|
3
|
+
require "securerandom"
|
3
4
|
|
4
5
|
module BetterErrors
|
5
6
|
# @private
|
@@ -7,42 +8,46 @@ module BetterErrors
|
|
7
8
|
def self.template_path(template_name)
|
8
9
|
File.expand_path("../templates/#{template_name}.erb", __FILE__)
|
9
10
|
end
|
10
|
-
|
11
|
+
|
11
12
|
def self.template(template_name)
|
12
13
|
Erubis::EscapedEruby.new(File.read(template_path(template_name)))
|
13
14
|
end
|
14
|
-
|
15
|
+
|
15
16
|
attr_reader :exception, :env, :repls
|
16
|
-
|
17
|
+
|
17
18
|
def initialize(exception, env)
|
18
|
-
@exception =
|
19
|
+
@exception = RaisedException.new(exception)
|
19
20
|
@env = env
|
20
21
|
@start_time = Time.now.to_f
|
21
22
|
@repls = []
|
22
23
|
end
|
23
|
-
|
24
|
+
|
25
|
+
def id
|
26
|
+
@id ||= SecureRandom.hex(8)
|
27
|
+
end
|
28
|
+
|
24
29
|
def render(template_name = "main")
|
25
30
|
self.class.template(template_name).result binding
|
26
31
|
end
|
27
|
-
|
32
|
+
|
28
33
|
def do_variables(opts)
|
29
34
|
index = opts["index"].to_i
|
30
35
|
@frame = backtrace_frames[index]
|
31
36
|
@var_start_time = Time.now.to_f
|
32
37
|
{ html: render("variable_info") }
|
33
38
|
end
|
34
|
-
|
39
|
+
|
35
40
|
def do_eval(opts)
|
36
41
|
index = opts["index"].to_i
|
37
42
|
code = opts["source"]
|
38
|
-
|
43
|
+
|
39
44
|
unless binding = backtrace_frames[index].frame_binding
|
40
45
|
return { error: "REPL unavailable in this stack frame" }
|
41
46
|
end
|
42
|
-
|
47
|
+
|
43
48
|
result, prompt, prefilled_input =
|
44
49
|
(@repls[index] ||= REPL.provider.new(binding)).send_input(code)
|
45
|
-
|
50
|
+
|
46
51
|
{ result: result,
|
47
52
|
prompt: prompt,
|
48
53
|
prefilled_input: prefilled_input,
|
@@ -50,22 +55,22 @@ module BetterErrors
|
|
50
55
|
end
|
51
56
|
|
52
57
|
def backtrace_frames
|
53
|
-
|
58
|
+
exception.backtrace
|
54
59
|
end
|
55
60
|
|
56
61
|
def application_frames
|
57
|
-
backtrace_frames.select
|
62
|
+
backtrace_frames.select(&:application?)
|
58
63
|
end
|
59
64
|
|
60
65
|
def first_frame
|
61
|
-
|
66
|
+
application_frames.first || backtrace_frames.first
|
62
67
|
end
|
63
|
-
|
68
|
+
|
64
69
|
private
|
65
70
|
def editor_url(frame)
|
66
71
|
BetterErrors.editor[frame.filename, frame.line]
|
67
72
|
end
|
68
|
-
|
73
|
+
|
69
74
|
def rack_session
|
70
75
|
env['rack.session']
|
71
76
|
end
|
@@ -77,31 +82,15 @@ module BetterErrors
|
|
77
82
|
def uri_prefix
|
78
83
|
env["SCRIPT_NAME"] || ""
|
79
84
|
end
|
80
|
-
|
81
|
-
def exception_message
|
82
|
-
if exception.is_a?(SyntaxError) && exception.message =~ /\A.*:\d*: (.*)$/
|
83
|
-
$1
|
84
|
-
else
|
85
|
-
exception.message
|
86
|
-
end
|
87
|
-
end
|
88
85
|
|
89
|
-
def real_exception(exception)
|
90
|
-
if exception.respond_to?(:original_exception) && exception.original_exception.is_a?(Exception)
|
91
|
-
exception.original_exception
|
92
|
-
else
|
93
|
-
exception
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
86
|
def request_path
|
98
87
|
env["PATH_INFO"]
|
99
88
|
end
|
100
|
-
|
89
|
+
|
101
90
|
def html_formatted_code_block(frame)
|
102
91
|
CodeFormatter::HTML.new(frame.filename, frame.line).output
|
103
92
|
end
|
104
|
-
|
93
|
+
|
105
94
|
def text_formatted_code_block(frame)
|
106
95
|
CodeFormatter::Text.new(frame.filename, frame.line).output
|
107
96
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module BetterErrors
|
2
|
+
module ExceptionExtension
|
3
|
+
prepend_features Exception
|
4
|
+
|
5
|
+
def set_backtrace(*)
|
6
|
+
if caller_locations.none? { |loc| loc.path == __FILE__ }
|
7
|
+
@__better_errors_bindings_stack = ::Kernel.binding.callers.drop(1)
|
8
|
+
end
|
9
|
+
|
10
|
+
super
|
11
|
+
end
|
12
|
+
|
13
|
+
def __better_errors_bindings_stack
|
14
|
+
@__better_errors_bindings_stack || []
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require "json"
|
2
2
|
require "ipaddr"
|
3
3
|
require "set"
|
4
|
+
require "rack"
|
4
5
|
|
5
6
|
module BetterErrors
|
6
7
|
# Better Errors' error handling middleware. Including this in your middleware
|
@@ -62,16 +63,15 @@ module BetterErrors
|
|
62
63
|
private
|
63
64
|
|
64
65
|
def allow_ip?(env)
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
ip = IPAddr.new env["REMOTE_ADDR"].split("%").first
|
66
|
+
request = Rack::Request.new(env)
|
67
|
+
return true unless request.ip and !request.ip.strip.empty?
|
68
|
+
ip = IPAddr.new request.ip.split("%").first
|
69
69
|
ALLOWED_IPS.any? { |subnet| subnet.include? ip }
|
70
70
|
end
|
71
71
|
|
72
72
|
def better_errors_call(env)
|
73
73
|
case env["PATH_INFO"]
|
74
|
-
when %r{/__better_errors/(?<
|
74
|
+
when %r{/__better_errors/(?<id>.+?)/(?<method>\w+)\z}
|
75
75
|
internal_call env, $~
|
76
76
|
when %r{/__better_errors/?\z}
|
77
77
|
show_error_page env
|
@@ -115,7 +115,7 @@ module BetterErrors
|
|
115
115
|
def log_exception
|
116
116
|
return unless BetterErrors.logger
|
117
117
|
|
118
|
-
message = "\n#{@error_page.exception.
|
118
|
+
message = "\n#{@error_page.exception.type} - #{@error_page.exception.message}:\n"
|
119
119
|
@error_page.backtrace_frames.each do |frame|
|
120
120
|
message << " #{frame}\n"
|
121
121
|
end
|
@@ -124,7 +124,7 @@ module BetterErrors
|
|
124
124
|
end
|
125
125
|
|
126
126
|
def internal_call(env, opts)
|
127
|
-
if opts[:
|
127
|
+
if opts[:id] != @error_page.id
|
128
128
|
return [200, { "Content-Type" => "text/plain; charset=utf-8" }, [JSON.dump(error: "Session expired")]]
|
129
129
|
end
|
130
130
|
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# @private
|
2
|
+
module BetterErrors
|
3
|
+
class RaisedException
|
4
|
+
attr_reader :exception, :message, :backtrace
|
5
|
+
|
6
|
+
def initialize(exception)
|
7
|
+
if exception.respond_to?(:original_exception) && exception.original_exception
|
8
|
+
exception = exception.original_exception
|
9
|
+
end
|
10
|
+
|
11
|
+
@exception = exception
|
12
|
+
@message = exception.message
|
13
|
+
|
14
|
+
setup_backtrace
|
15
|
+
massage_syntax_error
|
16
|
+
end
|
17
|
+
|
18
|
+
def type
|
19
|
+
exception.class
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
def has_bindings?
|
24
|
+
exception.respond_to?(:__better_errors_bindings_stack) && exception.__better_errors_bindings_stack.any?
|
25
|
+
end
|
26
|
+
|
27
|
+
def setup_backtrace
|
28
|
+
if has_bindings?
|
29
|
+
setup_backtrace_from_bindings
|
30
|
+
else
|
31
|
+
setup_backtrace_from_backtrace
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def setup_backtrace_from_bindings
|
36
|
+
@backtrace = exception.__better_errors_bindings_stack.map { |binding|
|
37
|
+
file = binding.eval "__FILE__"
|
38
|
+
line = binding.eval "__LINE__"
|
39
|
+
name = binding.frame_description
|
40
|
+
StackFrame.new(file, line, name, binding)
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
def setup_backtrace_from_backtrace
|
45
|
+
@backtrace = (exception.backtrace || []).map { |frame|
|
46
|
+
if /\A(?<file>.*?):(?<line>\d+)(:in `(?<name>.*)')?/ =~ frame
|
47
|
+
StackFrame.new(file, line.to_i, name)
|
48
|
+
end
|
49
|
+
}.compact
|
50
|
+
end
|
51
|
+
|
52
|
+
def massage_syntax_error
|
53
|
+
case exception.class.to_s
|
54
|
+
when "Haml::SyntaxError"
|
55
|
+
if /\A(.+?):(\d+)/ =~ exception.backtrace.first
|
56
|
+
backtrace.unshift(StackFrame.new($1, $2.to_i, ""))
|
57
|
+
end
|
58
|
+
when "SyntaxError"
|
59
|
+
if /\A(.+?):(\d+): (.*)/m =~ exception.message
|
60
|
+
backtrace.unshift(StackFrame.new($1, $2.to_i, ""))
|
61
|
+
@message = $3
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -36,8 +36,8 @@ module BetterErrors
|
|
36
36
|
@fiber = Fiber.new do
|
37
37
|
@pry.repl binding
|
38
38
|
end
|
39
|
-
@input = Input.new
|
40
|
-
@output = Output.new
|
39
|
+
@input = BetterErrors::REPL::Pry::Input.new
|
40
|
+
@output = BetterErrors::REPL::Pry::Output.new
|
41
41
|
@pry = ::Pry.new input: @input, output: @output
|
42
42
|
@pry.hooks.clear_all if defined?(@pry.hooks.clear_all)
|
43
43
|
@fiber.resume
|
@@ -4,49 +4,7 @@ module BetterErrors
|
|
4
4
|
# @private
|
5
5
|
class StackFrame
|
6
6
|
def self.from_exception(exception)
|
7
|
-
|
8
|
-
list = exception.__better_errors_bindings_stack.map { |binding|
|
9
|
-
file = binding.eval "__FILE__"
|
10
|
-
line = binding.eval "__LINE__"
|
11
|
-
name = binding.frame_description
|
12
|
-
StackFrame.new(file, line, name, binding)
|
13
|
-
}
|
14
|
-
else
|
15
|
-
list = (exception.backtrace || []).map { |frame|
|
16
|
-
next unless md = /\A(?<file>.*?):(?<line>\d+)(:in `(?<name>.*)')?/.match(frame)
|
17
|
-
StackFrame.new(md[:file], md[:line].to_i, md[:name])
|
18
|
-
}.compact
|
19
|
-
end
|
20
|
-
|
21
|
-
if syntax_error?(exception)
|
22
|
-
if trace = exception.backtrace and trace.first =~ /\A(.*):(\d+)/
|
23
|
-
list.unshift StackFrame.new($1, $2.to_i, "")
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
list
|
28
|
-
end
|
29
|
-
|
30
|
-
def self.syntax_error_classes
|
31
|
-
# Better Errors may be loaded before some of the gems that provide these
|
32
|
-
# classes, so we lazily set up the set of syntax error classes at runtime
|
33
|
-
# after everything has hopefully had a chance to load.
|
34
|
-
#
|
35
|
-
@syntax_error_classes ||= begin
|
36
|
-
class_names = %w[
|
37
|
-
Haml::SyntaxError
|
38
|
-
]
|
39
|
-
|
40
|
-
Set.new(class_names.map { |klass| eval(klass) rescue nil }.compact)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def self.syntax_error?(exception)
|
45
|
-
exception.is_a?(SyntaxError) || syntax_error_classes.include?(exception.class)
|
46
|
-
end
|
47
|
-
|
48
|
-
def self.has_binding_stack?(exception)
|
49
|
-
exception.respond_to?(:__better_errors_bindings_stack) && exception.__better_errors_bindings_stack.any?
|
7
|
+
RaisedException.new(exception).backtrace
|
50
8
|
end
|
51
9
|
|
52
10
|
attr_reader :filename, :line, :name, :frame_binding
|
@@ -111,15 +69,10 @@ module BetterErrors
|
|
111
69
|
def local_variables
|
112
70
|
return {} unless frame_binding
|
113
71
|
frame_binding.eval("local_variables").each_with_object({}) do |name, hash|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
hash[name] = frame_binding.eval(name.to_s)
|
119
|
-
end
|
120
|
-
rescue NameError => e
|
121
|
-
# local_variables sometimes returns broken variables.
|
122
|
-
# https://bugs.ruby-lang.org/issues/7536
|
72
|
+
if defined?(frame_binding.local_variable_get)
|
73
|
+
hash[name] = frame_binding.local_variable_get(name)
|
74
|
+
else
|
75
|
+
hash[name] = frame_binding.eval(name.to_s)
|
123
76
|
end
|
124
77
|
end
|
125
78
|
end
|
@@ -141,14 +94,12 @@ module BetterErrors
|
|
141
94
|
|
142
95
|
private
|
143
96
|
def set_pretty_method_name
|
144
|
-
return if RUBY_VERSION < "2.0.0"
|
145
|
-
|
146
97
|
name =~ /\A(block (\([^)]+\) )?in )?/
|
147
98
|
recv = frame_binding.eval("self")
|
148
99
|
|
149
100
|
return unless method_name = frame_binding.eval("::Kernel.__method__")
|
150
101
|
|
151
|
-
if
|
102
|
+
if Module === recv
|
152
103
|
@class_name = "#{$1}#{recv}"
|
153
104
|
@method_name = ".#{method_name}"
|
154
105
|
else
|
@@ -1,7 +1,7 @@
|
|
1
1
|
<!DOCTYPE html>
|
2
2
|
<html>
|
3
3
|
<head>
|
4
|
-
<title><%= exception.
|
4
|
+
<title><%= exception.type %> at <%= request_path %></title>
|
5
5
|
</head>
|
6
6
|
<body>
|
7
7
|
<%# Stylesheets are placed in the <body> for Turbolinks compatibility. %>
|
@@ -731,8 +731,8 @@
|
|
731
731
|
|
732
732
|
<div class='top'>
|
733
733
|
<header class="exception">
|
734
|
-
<h2><strong><%= exception.
|
735
|
-
<p><%=
|
734
|
+
<h2><strong><%= exception.type %></strong> <span>at <%= request_path %></span></h2>
|
735
|
+
<p><%= exception.message %></p>
|
736
736
|
</header>
|
737
737
|
</div>
|
738
738
|
|
@@ -768,7 +768,7 @@
|
|
768
768
|
<script>
|
769
769
|
(function() {
|
770
770
|
|
771
|
-
var OID =
|
771
|
+
var OID = "<%= id %>";
|
772
772
|
|
773
773
|
var previousFrame = null;
|
774
774
|
var previousFrameInfo = null;
|
@@ -1,6 +1,6 @@
|
|
1
|
-
<%== text_heading("=", "%s at %s" % [exception.
|
1
|
+
<%== text_heading("=", "%s at %s" % [exception.type, request_path]) %>
|
2
2
|
|
3
|
-
> <%==
|
3
|
+
> <%== exception.message %>
|
4
4
|
<% if backtrace_frames.any? %>
|
5
5
|
|
6
6
|
<%== text_heading("-", "%s, line %i" % [first_frame.pretty_path, first_frame.line]) %>
|
@@ -40,6 +40,14 @@ module BetterErrors
|
|
40
40
|
app.call("REMOTE_ADDR" => "77.55.33.11")
|
41
41
|
end
|
42
42
|
|
43
|
+
it "respects the X-Forwarded-For header" do
|
44
|
+
app.should_not_receive :better_errors_call
|
45
|
+
app.call(
|
46
|
+
"REMOTE_ADDR" => "127.0.0.1",
|
47
|
+
"HTTP_X_FORWARDED_FOR" => "1.2.3.4",
|
48
|
+
)
|
49
|
+
end
|
50
|
+
|
43
51
|
it "doesn't blow up when given a blank REMOTE_ADDR" do
|
44
52
|
expect { app.call("REMOTE_ADDR" => " ") }.to_not raise_error
|
45
53
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
module BetterErrors
|
4
|
+
describe RaisedException do
|
5
|
+
let(:exception) { RuntimeError.new("whoops") }
|
6
|
+
subject { RaisedException.new(exception) }
|
7
|
+
|
8
|
+
its(:exception) { should == exception }
|
9
|
+
its(:message) { should == "whoops" }
|
10
|
+
its(:type) { should == RuntimeError }
|
11
|
+
|
12
|
+
context "when the exception wraps another exception" do
|
13
|
+
let(:original_exception) { RuntimeError.new("something went wrong!") }
|
14
|
+
let(:exception) { double(:original_exception => original_exception) }
|
15
|
+
|
16
|
+
its(:exception) { should == original_exception }
|
17
|
+
its(:message) { should == "something went wrong!" }
|
18
|
+
end
|
19
|
+
|
20
|
+
context "when the exception is a syntax error" do
|
21
|
+
let(:exception) { SyntaxError.new("foo.rb:123: you made a typo!") }
|
22
|
+
|
23
|
+
its(:message) { should == "you made a typo!" }
|
24
|
+
its(:type) { should == SyntaxError }
|
25
|
+
|
26
|
+
it "has the right filename and line number in the backtrace" do
|
27
|
+
subject.backtrace.first.filename.should == "foo.rb"
|
28
|
+
subject.backtrace.first.line.should == 123
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "when the exception is a HAML syntax error" do
|
33
|
+
before do
|
34
|
+
stub_const("Haml::SyntaxError", Class.new(SyntaxError))
|
35
|
+
end
|
36
|
+
|
37
|
+
let(:exception) {
|
38
|
+
Haml::SyntaxError.new("you made a typo!").tap do |ex|
|
39
|
+
ex.set_backtrace(["foo.rb:123", "haml/internals/blah.rb:123456"])
|
40
|
+
end
|
41
|
+
}
|
42
|
+
|
43
|
+
its(:message) { should == "you made a typo!" }
|
44
|
+
its(:type) { should == Haml::SyntaxError }
|
45
|
+
|
46
|
+
it "has the right filename and line number in the backtrace" do
|
47
|
+
subject.backtrace.first.filename.should == "foo.rb"
|
48
|
+
subject.backtrace.first.line.should == 123
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -6,77 +6,77 @@ module BetterErrors
|
|
6
6
|
it "is true for application filenames" do
|
7
7
|
BetterErrors.stub(:application_root).and_return("/abc/xyz")
|
8
8
|
frame = StackFrame.new("/abc/xyz/app/controllers/crap_controller.rb", 123, "index")
|
9
|
-
|
9
|
+
|
10
10
|
frame.application?.should be_true
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
it "is false for everything else" do
|
14
14
|
BetterErrors.stub(:application_root).and_return("/abc/xyz")
|
15
15
|
frame = StackFrame.new("/abc/nope", 123, "foo")
|
16
|
-
|
16
|
+
|
17
17
|
frame.application?.should be_false
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
it "doesn't care if no application_root is set" do
|
21
21
|
frame = StackFrame.new("/abc/xyz/app/controllers/crap_controller.rb", 123, "index")
|
22
|
-
|
22
|
+
|
23
23
|
frame.application?.should be_false
|
24
24
|
end
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
context "#gem?" do
|
28
28
|
it "is true for gem filenames" do
|
29
29
|
Gem.stub(:path).and_return(["/abc/xyz"])
|
30
30
|
frame = StackFrame.new("/abc/xyz/gems/whatever-1.2.3/lib/whatever.rb", 123, "foo")
|
31
|
-
|
31
|
+
|
32
32
|
frame.gem?.should be_true
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
it "is false for everything else" do
|
36
36
|
Gem.stub(:path).and_return(["/abc/xyz"])
|
37
37
|
frame = StackFrame.new("/abc/nope", 123, "foo")
|
38
|
-
|
38
|
+
|
39
39
|
frame.gem?.should be_false
|
40
40
|
end
|
41
41
|
end
|
42
|
-
|
42
|
+
|
43
43
|
context "#application_path" do
|
44
44
|
it "chops off the application root" do
|
45
45
|
BetterErrors.stub(:application_root).and_return("/abc/xyz")
|
46
46
|
frame = StackFrame.new("/abc/xyz/app/controllers/crap_controller.rb", 123, "index")
|
47
|
-
|
47
|
+
|
48
48
|
frame.application_path.should == "app/controllers/crap_controller.rb"
|
49
49
|
end
|
50
50
|
end
|
51
|
-
|
51
|
+
|
52
52
|
context "#gem_path" do
|
53
53
|
it "chops of the gem path and stick (gem) there" do
|
54
54
|
Gem.stub(:path).and_return(["/abc/xyz"])
|
55
55
|
frame = StackFrame.new("/abc/xyz/gems/whatever-1.2.3/lib/whatever.rb", 123, "foo")
|
56
|
-
|
56
|
+
|
57
57
|
frame.gem_path.should == "whatever (1.2.3) lib/whatever.rb"
|
58
58
|
end
|
59
|
-
|
59
|
+
|
60
60
|
it "prioritizes gem path over application path" do
|
61
61
|
BetterErrors.stub(:application_root).and_return("/abc/xyz")
|
62
62
|
Gem.stub(:path).and_return(["/abc/xyz/vendor"])
|
63
63
|
frame = StackFrame.new("/abc/xyz/vendor/gems/whatever-1.2.3/lib/whatever.rb", 123, "foo")
|
64
|
-
|
64
|
+
|
65
65
|
frame.gem_path.should == "whatever (1.2.3) lib/whatever.rb"
|
66
66
|
end
|
67
67
|
end
|
68
|
-
|
68
|
+
|
69
69
|
context "#pretty_path" do
|
70
70
|
it "returns #application_path for application paths" do
|
71
71
|
BetterErrors.stub(:application_root).and_return("/abc/xyz")
|
72
72
|
frame = StackFrame.new("/abc/xyz/app/controllers/crap_controller.rb", 123, "index")
|
73
73
|
frame.pretty_path.should == frame.application_path
|
74
74
|
end
|
75
|
-
|
75
|
+
|
76
76
|
it "returns #gem_path for gem paths" do
|
77
77
|
Gem.stub(:path).and_return(["/abc/xyz"])
|
78
78
|
frame = StackFrame.new("/abc/xyz/gems/whatever-1.2.3/lib/whatever.rb", 123, "foo")
|
79
|
-
|
79
|
+
|
80
80
|
frame.pretty_path.should == frame.gem_path
|
81
81
|
end
|
82
82
|
end
|
@@ -90,28 +90,28 @@ module BetterErrors
|
|
90
90
|
frames.first.filename.should == "my_file.rb"
|
91
91
|
frames.first.line.should == 123
|
92
92
|
end
|
93
|
-
|
93
|
+
|
94
94
|
it "doesn't blow up if no method name is given" do
|
95
95
|
error = StandardError.allocate
|
96
|
-
|
96
|
+
|
97
97
|
error.stub(:backtrace).and_return(["foo.rb:123"])
|
98
98
|
frames = StackFrame.from_exception(error)
|
99
99
|
frames.first.filename.should == "foo.rb"
|
100
100
|
frames.first.line.should == 123
|
101
|
-
|
101
|
+
|
102
102
|
error.stub(:backtrace).and_return(["foo.rb:123: this is an error message"])
|
103
103
|
frames = StackFrame.from_exception(error)
|
104
104
|
frames.first.filename.should == "foo.rb"
|
105
105
|
frames.first.line.should == 123
|
106
106
|
end
|
107
|
-
|
107
|
+
|
108
108
|
it "ignores a backtrace line if its format doesn't make any sense at all" do
|
109
109
|
error = StandardError.allocate
|
110
110
|
error.stub(:backtrace).and_return(["foo.rb:123:in `foo'", "C:in `find'", "bar.rb:123:in `bar'"])
|
111
111
|
frames = StackFrame.from_exception(error)
|
112
112
|
frames.count.should == 2
|
113
113
|
end
|
114
|
-
|
114
|
+
|
115
115
|
it "doesn't blow up if a filename contains a colon" do
|
116
116
|
error = StandardError.allocate
|
117
117
|
error.stub(:backtrace).and_return(["crap:filename.rb:123"])
|
@@ -125,11 +125,7 @@ module BetterErrors
|
|
125
125
|
::Kernel.binding
|
126
126
|
end
|
127
127
|
frame = StackFrame.new("/abc/xyz/app/controllers/crap_controller.rb", 123, "index", obj.my_binding)
|
128
|
-
|
129
|
-
frame.class_name.should == 'BasicObject'
|
130
|
-
else
|
131
|
-
frame.class_name.should be_nil
|
132
|
-
end
|
128
|
+
frame.class_name.should == 'BasicObject'
|
133
129
|
end
|
134
130
|
|
135
131
|
it "sets method names properly" do
|
@@ -143,12 +139,12 @@ module BetterErrors
|
|
143
139
|
end
|
144
140
|
|
145
141
|
frame = StackFrame.from_exception(obj.my_method).first
|
146
|
-
if
|
142
|
+
if BetterErrors.binding_of_caller_available?
|
147
143
|
frame.method_name.should == "#my_method"
|
148
144
|
frame.class_name.should == "String"
|
149
145
|
else
|
150
146
|
frame.method_name.should == "my_method"
|
151
|
-
frame.class_name.should
|
147
|
+
frame.class_name.should == nil
|
152
148
|
end
|
153
149
|
end
|
154
150
|
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,43 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: better_errors
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Charlie Somerville
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2014-08-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: erubis
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 2.6.6
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 2.6.6
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: coderay
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: 1.0.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 1.0.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rack
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.9.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.9.0
|
41
55
|
description: Provides a better error page for Rails and other Rack apps. Includes
|
42
56
|
source code inspection, a live REPL and local/instance variable inspection for all
|
43
57
|
stack frames.
|
@@ -47,9 +61,9 @@ executables: []
|
|
47
61
|
extensions: []
|
48
62
|
extra_rdoc_files: []
|
49
63
|
files:
|
50
|
-
- .gitignore
|
51
|
-
- .travis.yml
|
52
|
-
- .yardopts
|
64
|
+
- ".gitignore"
|
65
|
+
- ".travis.yml"
|
66
|
+
- ".yardopts"
|
53
67
|
- CHANGELOG.md
|
54
68
|
- Gemfile
|
55
69
|
- LICENSE.txt
|
@@ -60,10 +74,11 @@ files:
|
|
60
74
|
- lib/better_errors/code_formatter.rb
|
61
75
|
- lib/better_errors/code_formatter/html.rb
|
62
76
|
- lib/better_errors/code_formatter/text.rb
|
63
|
-
- lib/better_errors/core_ext/exception.rb
|
64
77
|
- lib/better_errors/error_page.rb
|
78
|
+
- lib/better_errors/exception_extension.rb
|
65
79
|
- lib/better_errors/middleware.rb
|
66
80
|
- lib/better_errors/rails.rb
|
81
|
+
- lib/better_errors/raised_exception.rb
|
67
82
|
- lib/better_errors/repl.rb
|
68
83
|
- lib/better_errors/repl/basic.rb
|
69
84
|
- lib/better_errors/repl/pry.rb
|
@@ -75,6 +90,7 @@ files:
|
|
75
90
|
- spec/better_errors/code_formatter_spec.rb
|
76
91
|
- spec/better_errors/error_page_spec.rb
|
77
92
|
- spec/better_errors/middleware_spec.rb
|
93
|
+
- spec/better_errors/raised_exception_spec.rb
|
78
94
|
- spec/better_errors/repl/basic_spec.rb
|
79
95
|
- spec/better_errors/repl/pry_spec.rb
|
80
96
|
- spec/better_errors/repl/shared_examples.rb
|
@@ -82,6 +98,7 @@ files:
|
|
82
98
|
- spec/better_errors/support/my_source.rb
|
83
99
|
- spec/better_errors_spec.rb
|
84
100
|
- spec/spec_helper.rb
|
101
|
+
- spec/without_binding_of_caller.rb
|
85
102
|
homepage: https://github.com/charliesome/better_errors
|
86
103
|
licenses:
|
87
104
|
- MIT
|
@@ -92,17 +109,17 @@ require_paths:
|
|
92
109
|
- lib
|
93
110
|
required_ruby_version: !ruby/object:Gem::Requirement
|
94
111
|
requirements:
|
95
|
-
- -
|
112
|
+
- - ">="
|
96
113
|
- !ruby/object:Gem::Version
|
97
|
-
version:
|
114
|
+
version: 2.0.0
|
98
115
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
99
116
|
requirements:
|
100
|
-
- -
|
117
|
+
- - ">="
|
101
118
|
- !ruby/object:Gem::Version
|
102
119
|
version: '0'
|
103
120
|
requirements: []
|
104
121
|
rubyforge_project:
|
105
|
-
rubygems_version: 2.
|
122
|
+
rubygems_version: 2.2.2
|
106
123
|
signing_key:
|
107
124
|
specification_version: 4
|
108
125
|
summary: Better error page for Rails and other Rack apps
|
@@ -110,6 +127,7 @@ test_files:
|
|
110
127
|
- spec/better_errors/code_formatter_spec.rb
|
111
128
|
- spec/better_errors/error_page_spec.rb
|
112
129
|
- spec/better_errors/middleware_spec.rb
|
130
|
+
- spec/better_errors/raised_exception_spec.rb
|
113
131
|
- spec/better_errors/repl/basic_spec.rb
|
114
132
|
- spec/better_errors/repl/pry_spec.rb
|
115
133
|
- spec/better_errors/repl/shared_examples.rb
|
@@ -117,4 +135,4 @@ test_files:
|
|
117
135
|
- spec/better_errors/support/my_source.rb
|
118
136
|
- spec/better_errors_spec.rb
|
119
137
|
- spec/spec_helper.rb
|
120
|
-
|
138
|
+
- spec/without_binding_of_caller.rb
|
@@ -1,21 +0,0 @@
|
|
1
|
-
class Exception
|
2
|
-
original_set_backtrace = instance_method(:set_backtrace)
|
3
|
-
|
4
|
-
if BetterErrors.binding_of_caller_available?
|
5
|
-
define_method :set_backtrace do |*args|
|
6
|
-
unless Thread.current[:__better_errors_exception_lock]
|
7
|
-
Thread.current[:__better_errors_exception_lock] = true
|
8
|
-
begin
|
9
|
-
@__better_errors_bindings_stack = binding.callers.drop(1)
|
10
|
-
ensure
|
11
|
-
Thread.current[:__better_errors_exception_lock] = false
|
12
|
-
end
|
13
|
-
end
|
14
|
-
original_set_backtrace.bind(self).call(*args)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def __better_errors_bindings_stack
|
19
|
-
@__better_errors_bindings_stack || []
|
20
|
-
end
|
21
|
-
end
|