better_errors-creditkudos 2.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.travis.yml +8 -0
- data/.yardopts +1 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +11 -0
- data/LICENSE.txt +22 -0
- data/README.md +128 -0
- data/Rakefile +13 -0
- data/better_errors-creditkudos.gemspec +28 -0
- data/lib/better_errors.rb +152 -0
- data/lib/better_errors/code_formatter.rb +63 -0
- data/lib/better_errors/code_formatter/html.rb +26 -0
- data/lib/better_errors/code_formatter/text.rb +14 -0
- data/lib/better_errors/error_page.rb +129 -0
- data/lib/better_errors/exception_extension.rb +17 -0
- data/lib/better_errors/middleware.rb +141 -0
- data/lib/better_errors/rails.rb +28 -0
- data/lib/better_errors/raised_exception.rb +68 -0
- data/lib/better_errors/repl.rb +30 -0
- data/lib/better_errors/repl/basic.rb +20 -0
- data/lib/better_errors/repl/pry.rb +78 -0
- data/lib/better_errors/stack_frame.rb +111 -0
- data/lib/better_errors/templates/main.erb +1032 -0
- data/lib/better_errors/templates/text.erb +21 -0
- data/lib/better_errors/templates/variable_info.erb +72 -0
- data/lib/better_errors/version.rb +3 -0
- data/spec/better_errors/code_formatter_spec.rb +92 -0
- data/spec/better_errors/error_page_spec.rb +122 -0
- data/spec/better_errors/middleware_spec.rb +180 -0
- data/spec/better_errors/raised_exception_spec.rb +72 -0
- data/spec/better_errors/repl/basic_spec.rb +18 -0
- data/spec/better_errors/repl/pry_spec.rb +40 -0
- data/spec/better_errors/repl/shared_examples.rb +18 -0
- data/spec/better_errors/stack_frame_spec.rb +157 -0
- data/spec/better_errors/support/my_source.rb +20 -0
- data/spec/better_errors_spec.rb +73 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/without_binding_of_caller.rb +9 -0
- metadata +136 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f2a6d2b9e47dea68238e091ce6321912938bfd39
|
4
|
+
data.tar.gz: ba2cbaed992e4cd2f24ac099c1bfad1b3ac81926
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1e814e90c2024718b0369fa1e703d90f0d623fd0a6926388c0a5b98b220a2c67880ec3254a966b951dbdf0109bdc76f6de82ec2cdfc2af5d4fd45e8567827362
|
7
|
+
data.tar.gz: 2da774b33b1310bc8754072fa5cc61705eae2ab1f5cf1e9f695f99cda6355264added72b5935a8be76df9de6d35cb8cbcd4195e0b545e83b08af13a3fa971cd1
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--markup markdown --no-private
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012-2016 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,128 @@
|
|
1
|
+
# Better Errors [![Gem Version](https://img.shields.io/gem/v/better_errors.svg)](https://rubygems.org/gems/better_errors) [![Build Status](https://travis-ci.org/charliesome/better_errors.svg)](https://travis-ci.org/charliesome/better_errors) [![Code Climate](https://img.shields.io/codeclimate/github/charliesome/better_errors.svg)](https://codeclimate.com/github/charliesome/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 in any Rack app as Rack middleware.
|
4
|
+
|
5
|
+
![image](https://i.imgur.com/6zBGAAb.png)
|
6
|
+
|
7
|
+
## Features
|
8
|
+
|
9
|
+
* Full stack trace
|
10
|
+
* Source code inspection for all stack frames (with highlighting)
|
11
|
+
* Local and instance variable inspection
|
12
|
+
* Live REPL on every stack frame
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
Add this to your Gemfile:
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
group :development do
|
20
|
+
gem "better_errors"
|
21
|
+
end
|
22
|
+
```
|
23
|
+
|
24
|
+
If you would like to use Better Errors' **advanced features** (REPL, local/instance variable inspection, pretty stack frame names), you need to add the [`binding_of_caller`](https://github.com/banister/binding_of_caller) gem by [@banisterfiend](https://twitter.com/banisterfiend) to your Gemfile:
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
gem "binding_of_caller"
|
28
|
+
```
|
29
|
+
|
30
|
+
This is an optional dependency however, and Better Errors will work without it.
|
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
|
+
|
34
|
+
## Security
|
35
|
+
|
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.**
|
37
|
+
|
38
|
+
You will notice that the only machine that gets the Better Errors page is localhost, which means you get the default error page if you are developing on a remote host (or a virtually remote host, such as a Vagrant box). Obviously, the REPL is not something you want to expose to the public, but there may also be other pieces of sensitive information available in the backtrace.
|
39
|
+
|
40
|
+
To poke selective holes in this security mechanism, you can add a line like this to your startup (for example, on Rails it would be `config/environments/development.rb`)
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
BetterErrors::Middleware.allow_ip! ENV['TRUSTED_IP'] if ENV['TRUSTED_IP']
|
44
|
+
```
|
45
|
+
|
46
|
+
Then run Rails like this:
|
47
|
+
|
48
|
+
```shell
|
49
|
+
TRUSTED_IP=66.68.96.220 rails s
|
50
|
+
```
|
51
|
+
|
52
|
+
Note that the `allow_ip!` is actually backed by a `Set`, so you can add more than one IP address or subnet.
|
53
|
+
|
54
|
+
**Tip:** You can find your apparent IP by hitting the old error page's "Show env dump" and looking at "REMOTE_ADDR".
|
55
|
+
|
56
|
+
**VirtualBox:** If you are using VirtualBox and are accessing the guest from your host's browser, you will need to use `allow_ip!` to see the error page.
|
57
|
+
|
58
|
+
## Usage
|
59
|
+
|
60
|
+
If you're using Rails, there's nothing else you need to do.
|
61
|
+
|
62
|
+
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.
|
63
|
+
|
64
|
+
Here's an example using Sinatra:
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
require "sinatra"
|
68
|
+
require "better_errors"
|
69
|
+
|
70
|
+
configure :development do
|
71
|
+
use BetterErrors::Middleware
|
72
|
+
BetterErrors.application_root = __dir__
|
73
|
+
end
|
74
|
+
|
75
|
+
get "/" do
|
76
|
+
raise "oops"
|
77
|
+
end
|
78
|
+
```
|
79
|
+
|
80
|
+
### Plain text
|
81
|
+
|
82
|
+
Better Errors will render a plain text error page when the request is an
|
83
|
+
`XMLHttpRequest` or when the `Accept` header does *not* include 'html'.
|
84
|
+
|
85
|
+
### Unicorn, Puma, and other multi-worker servers
|
86
|
+
|
87
|
+
Better Errors works by leaving a lot of context in server process memory. If
|
88
|
+
you're using a web server that runs multiple "workers" it's likely that a second
|
89
|
+
request (as happens when you click on a stack frame) will hit a different
|
90
|
+
worker. That worker won't have the necessary context in memory, and you'll see
|
91
|
+
a `Session Expired` message.
|
92
|
+
|
93
|
+
If this is the case for you, consider turning the number of workers to one (1)
|
94
|
+
in `development`. Another option would be to use Webrick, Mongrel, Thin,
|
95
|
+
or another single-process server as your `rails server`, when you are trying
|
96
|
+
to troubleshoot an issue in development.
|
97
|
+
|
98
|
+
##Specify editor to open files in
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
# e.g. in config/initializers/better_errors.rb
|
102
|
+
# Other preset values are [:mvim, :macvim, :textmate, :txmt, :tm, :sublime, :subl, :st]
|
103
|
+
BetterErrors.editor = :mvim
|
104
|
+
```
|
105
|
+
|
106
|
+
|
107
|
+
##Set maximum variable size for inspector.
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
# e.g. in config/initializers/better_errors.rb
|
111
|
+
# This will stop BetterErrors from trying to render larger objects, which can cause
|
112
|
+
# slow loading times and browser performance problems.
|
113
|
+
# default value: 100_000
|
114
|
+
BetterErrors.maximum_variable_inspect_size = 100_000
|
115
|
+
```
|
116
|
+
|
117
|
+
|
118
|
+
## Get in touch!
|
119
|
+
|
120
|
+
If you're using better_errors, I'd love to hear from you. Drop me a line and tell me what you think!
|
121
|
+
|
122
|
+
## Contributing
|
123
|
+
|
124
|
+
1. Fork it
|
125
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
126
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
127
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
128
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
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"
|
@@ -0,0 +1,28 @@
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'better_errors/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "better_errors-creditkudos"
|
7
|
+
s.version = BetterErrors::VERSION
|
8
|
+
s.authors = ["Charlie Somerville"]
|
9
|
+
s.email = ["charlie@charliesomerville.com"]
|
10
|
+
s.description = %q{Temporary fork of better_errors with some performance improvements.}
|
11
|
+
s.summary = %q{Temporary fork of better_errors with some performance improvements.}
|
12
|
+
s.homepage = "https://github.com/creditkudos/better_errors"
|
13
|
+
s.license = "MIT"
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split($/)
|
16
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
17
|
+
s.require_paths = ["lib"]
|
18
|
+
|
19
|
+
s.required_ruby_version = ">= 2.0.0"
|
20
|
+
|
21
|
+
s.add_dependency "erubis", ">= 2.6.6"
|
22
|
+
s.add_dependency "coderay", ">= 1.0.0"
|
23
|
+
s.add_dependency "rack", ">= 0.9.0"
|
24
|
+
|
25
|
+
# optional dependencies:
|
26
|
+
# s.add_dependency "binding_of_caller"
|
27
|
+
# s.add_dependency "pry"
|
28
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
require "pp"
|
2
|
+
require "erubis"
|
3
|
+
require "coderay"
|
4
|
+
require "uri"
|
5
|
+
|
6
|
+
require "better_errors/code_formatter"
|
7
|
+
require "better_errors/error_page"
|
8
|
+
require "better_errors/middleware"
|
9
|
+
require "better_errors/raised_exception"
|
10
|
+
require "better_errors/repl"
|
11
|
+
require "better_errors/stack_frame"
|
12
|
+
require "better_errors/version"
|
13
|
+
|
14
|
+
module BetterErrors
|
15
|
+
POSSIBLE_EDITOR_PRESETS = [
|
16
|
+
{ symbols: [:emacs, :emacsclient], sniff: /emacs/i, url: "emacs://open?url=file://%{file}&line=%{line}" },
|
17
|
+
{ symbols: [:macvim, :mvim], sniff: /vim/i, url: proc { |file, line| "mvim://open?url=file://#{file}&line=#{line}" } },
|
18
|
+
{ symbols: [:sublime, :subl, :st], sniff: /subl/i, url: "subl://open?url=file://%{file}&line=%{line}" },
|
19
|
+
{ symbols: [:textmate, :txmt, :tm], sniff: /mate/i, url: "txmt://open?url=file://%{file}&line=%{line}" },
|
20
|
+
]
|
21
|
+
|
22
|
+
class << self
|
23
|
+
# The path to the root of the application. Better Errors uses this property
|
24
|
+
# to determine if a file in a backtrace should be considered an application
|
25
|
+
# frame. If you are using Better Errors with Rails, you do not need to set
|
26
|
+
# this attribute manually.
|
27
|
+
#
|
28
|
+
# @return [String]
|
29
|
+
attr_accessor :application_root
|
30
|
+
|
31
|
+
# The logger to use when logging exception details and backtraces. If you
|
32
|
+
# are using Better Errors with Rails, you do not need to set this attribute
|
33
|
+
# manually. If this attribute is `nil`, nothing will be logged.
|
34
|
+
#
|
35
|
+
# @return [Logger, nil]
|
36
|
+
attr_accessor :logger
|
37
|
+
|
38
|
+
# @private
|
39
|
+
attr_accessor :binding_of_caller_available
|
40
|
+
|
41
|
+
# @private
|
42
|
+
alias_method :binding_of_caller_available?, :binding_of_caller_available
|
43
|
+
|
44
|
+
# The ignored instance variables.
|
45
|
+
# @return [Array]
|
46
|
+
attr_accessor :ignored_instance_variables
|
47
|
+
|
48
|
+
# The maximum variable payload size. If variable.inspect exceeds this,
|
49
|
+
# the variable won't be returned.
|
50
|
+
# @return int
|
51
|
+
attr_accessor :maximum_variable_inspect_size
|
52
|
+
end
|
53
|
+
@ignored_instance_variables = []
|
54
|
+
|
55
|
+
# Returns a proc, which when called with a filename and line number argument,
|
56
|
+
# returns a URL to open the filename and line in the selected editor.
|
57
|
+
#
|
58
|
+
# Generates TextMate URLs by default.
|
59
|
+
#
|
60
|
+
# BetterErrors.editor["/some/file", 123]
|
61
|
+
# # => txmt://open?url=file:///some/file&line=123
|
62
|
+
#
|
63
|
+
# @return [Proc]
|
64
|
+
def self.editor
|
65
|
+
@editor
|
66
|
+
end
|
67
|
+
|
68
|
+
# Configures how Better Errors generates open-in-editor URLs.
|
69
|
+
#
|
70
|
+
# @overload BetterErrors.editor=(sym)
|
71
|
+
# Uses one of the preset editor configurations. Valid symbols are:
|
72
|
+
#
|
73
|
+
# * `:textmate`, `:txmt`, `:tm`
|
74
|
+
# * `:sublime`, `:subl`, `:st`
|
75
|
+
# * `:macvim`
|
76
|
+
#
|
77
|
+
# @param [Symbol] sym
|
78
|
+
#
|
79
|
+
# @overload BetterErrors.editor=(str)
|
80
|
+
# Uses `str` as the format string for generating open-in-editor URLs.
|
81
|
+
#
|
82
|
+
# Use `%{file}` and `%{line}` as placeholders for the actual values.
|
83
|
+
#
|
84
|
+
# @example
|
85
|
+
# BetterErrors.editor = "my-editor://open?url=%{file}&line=%{line}"
|
86
|
+
#
|
87
|
+
# @param [String] str
|
88
|
+
#
|
89
|
+
# @overload BetterErrors.editor=(proc)
|
90
|
+
# Uses `proc` to generate open-in-editor URLs. The proc will be called
|
91
|
+
# with `file` and `line` parameters when a URL needs to be generated.
|
92
|
+
#
|
93
|
+
# Your proc should take care to escape `file` appropriately with
|
94
|
+
# `URI.encode_www_form_component` (please note that `URI.escape` is **not**
|
95
|
+
# a suitable substitute.)
|
96
|
+
#
|
97
|
+
# @example
|
98
|
+
# BetterErrors.editor = proc { |file, line|
|
99
|
+
# "my-editor://open?url=#{URI.encode_www_form_component file}&line=#{line}"
|
100
|
+
# }
|
101
|
+
#
|
102
|
+
# @param [Proc] proc
|
103
|
+
#
|
104
|
+
def self.editor=(editor)
|
105
|
+
POSSIBLE_EDITOR_PRESETS.each do |config|
|
106
|
+
if config[:symbols].include?(editor)
|
107
|
+
return self.editor = config[:url]
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
if editor.is_a? String
|
112
|
+
self.editor = proc { |file, line| editor % { file: URI.encode_www_form_component(file), line: line } }
|
113
|
+
else
|
114
|
+
if editor.respond_to? :call
|
115
|
+
@editor = editor
|
116
|
+
else
|
117
|
+
raise TypeError, "Expected editor to be a valid editor key, a format string or a callable."
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# Enables experimental Pry support in the inline REPL
|
123
|
+
#
|
124
|
+
# If you encounter problems while using Pry, *please* file a bug report at
|
125
|
+
# https://github.com/charliesome/better_errors/issues
|
126
|
+
def self.use_pry!
|
127
|
+
REPL::PROVIDERS.unshift const: :Pry, impl: "better_errors/repl/pry"
|
128
|
+
end
|
129
|
+
|
130
|
+
# Automatically sniffs a default editor preset based on the EDITOR
|
131
|
+
# environment variable.
|
132
|
+
#
|
133
|
+
# @return [Symbol]
|
134
|
+
def self.default_editor
|
135
|
+
POSSIBLE_EDITOR_PRESETS.detect(-> { {} }) { |config|
|
136
|
+
ENV["EDITOR"] =~ config[:sniff]
|
137
|
+
}[:url] || :textmate
|
138
|
+
end
|
139
|
+
|
140
|
+
BetterErrors.editor = default_editor
|
141
|
+
end
|
142
|
+
|
143
|
+
begin
|
144
|
+
require "binding_of_caller"
|
145
|
+
require "better_errors/exception_extension"
|
146
|
+
BetterErrors.binding_of_caller_available = true
|
147
|
+
BetterErrors.maximum_variable_inspect_size ||= 100_000
|
148
|
+
rescue LoadError
|
149
|
+
BetterErrors.binding_of_caller_available = false
|
150
|
+
end
|
151
|
+
|
152
|
+
require "better_errors/rails" if defined? Rails::Railtie
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module BetterErrors
|
2
|
+
# @private
|
3
|
+
class CodeFormatter
|
4
|
+
require "better_errors/code_formatter/html"
|
5
|
+
require "better_errors/code_formatter/text"
|
6
|
+
|
7
|
+
FILE_TYPES = {
|
8
|
+
".rb" => :ruby,
|
9
|
+
"" => :ruby,
|
10
|
+
".html" => :html,
|
11
|
+
".erb" => :erb,
|
12
|
+
".haml" => :haml
|
13
|
+
}
|
14
|
+
|
15
|
+
attr_reader :filename, :line, :context
|
16
|
+
|
17
|
+
def initialize(filename, line, context = 5)
|
18
|
+
@filename = filename
|
19
|
+
@line = line
|
20
|
+
@context = context
|
21
|
+
end
|
22
|
+
|
23
|
+
def output
|
24
|
+
formatted_code
|
25
|
+
rescue Errno::ENOENT, Errno::EINVAL
|
26
|
+
source_unavailable
|
27
|
+
end
|
28
|
+
|
29
|
+
def formatted_code
|
30
|
+
formatted_lines.join
|
31
|
+
end
|
32
|
+
|
33
|
+
def coderay_scanner
|
34
|
+
ext = File.extname(filename)
|
35
|
+
FILE_TYPES[ext] || :text
|
36
|
+
end
|
37
|
+
|
38
|
+
def each_line_of(lines, &blk)
|
39
|
+
line_range.zip(lines).map { |current_line, str|
|
40
|
+
yield (current_line == line), current_line, str
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
def highlighted_lines
|
45
|
+
CodeRay.scan(context_lines.join, coderay_scanner).div(wrap: nil).lines
|
46
|
+
end
|
47
|
+
|
48
|
+
def context_lines
|
49
|
+
range = line_range
|
50
|
+
source_lines[(range.begin - 1)..(range.end - 1)] or raise Errno::EINVAL
|
51
|
+
end
|
52
|
+
|
53
|
+
def source_lines
|
54
|
+
@source_lines ||= File.readlines(filename)
|
55
|
+
end
|
56
|
+
|
57
|
+
def line_range
|
58
|
+
min = [line - context, 1].max
|
59
|
+
max = [line + context, source_lines.count].min
|
60
|
+
min..max
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|