better_errors-creditkudos 2.1.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.
- 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 [](https://rubygems.org/gems/better_errors) [](https://travis-ci.org/charliesome/better_errors) [](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
|
+

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