better_errors 2.2.0 → 2.3.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.

Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +19 -51
  3. data/better_errors.gemspec +5 -3
  4. data/lib/better_errors.rb +1 -1
  5. data/lib/better_errors/error_page.rb +16 -9
  6. data/lib/better_errors/middleware.rb +30 -3
  7. data/lib/better_errors/repl.rb +3 -1
  8. data/lib/better_errors/repl/basic.rb +1 -1
  9. data/lib/better_errors/repl/pry.rb +11 -1
  10. data/lib/better_errors/stack_frame.rb +7 -0
  11. data/lib/better_errors/templates/main.erb +7 -4
  12. data/lib/better_errors/version.rb +1 -1
  13. metadata +6 -40
  14. data/Rakefile +0 -13
  15. data/feature-screenshots/1-application-error.jpg +0 -0
  16. data/feature-screenshots/2-other-application-frame.jpg +0 -0
  17. data/feature-screenshots/3-live-shell.jpg +0 -0
  18. data/feature-screenshots/4-other-frames.jpg +0 -0
  19. data/feature-screenshots/5-open-editor.jpg +0 -0
  20. data/feature-screenshots/6-local-variables.jpg +0 -0
  21. data/feature-screenshots/7-non-html-requests.jpg +0 -0
  22. data/feature-screenshots/8-xhr-shows-text-error.jpg +0 -0
  23. data/feature-screenshots/9-xhr-error-in-manual-console.jpg +0 -0
  24. data/spec/better_errors/code_formatter_spec.rb +0 -92
  25. data/spec/better_errors/error_page_spec.rb +0 -92
  26. data/spec/better_errors/middleware_spec.rb +0 -188
  27. data/spec/better_errors/raised_exception_spec.rb +0 -73
  28. data/spec/better_errors/repl/basic_spec.rb +0 -18
  29. data/spec/better_errors/repl/pry_spec.rb +0 -40
  30. data/spec/better_errors/repl/shared_examples.rb +0 -18
  31. data/spec/better_errors/stack_frame_spec.rb +0 -157
  32. data/spec/better_errors/support/my_source.rb +0 -20
  33. data/spec/better_errors_spec.rb +0 -73
  34. data/spec/spec_helper.rb +0 -5
  35. data/spec/without_binding_of_caller.rb +0 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d53ee50b3a870061cf9298e5225635771043d6d7
4
- data.tar.gz: b4280966bd31d24f4f4cb12ea54c1eea11bccdaa
3
+ metadata.gz: 4a1dc267fbb1b144d24214815df6e7a31f23411d
4
+ data.tar.gz: 2415e49dbf1e39761859473d0321d4951694c3cf
5
5
  SHA512:
6
- metadata.gz: e068142eaef86037e0cc6088672158a0a9d021e49e7fe9a823c888d1f319181e07b18a03852b46da4a6d9a0db49f6d420ac7359ceb6ec4a35549bb56b403bec5
7
- data.tar.gz: 9c184752196c2cf65b7dba20f94cf3b47428c6fd067c880ffa452bca8ed2fa6d3e84e5cd64ae6e295199622fe4e1ff2d6d09979d2a35e0b9bf36d38c6ebfdd33
6
+ metadata.gz: 0b1ca0e01a8bdacbdbf9e99a9fa6ef1f386a75baeeadf06cadb0913ac3819488c51c7374949d0e1fa9dfd61d2820296f4e8c78aadb29abfbdd80b991a5096cfb
7
+ data.tar.gz: db6bf3012259cb357efaf1fcb7929186a7d0bc0a01141310289b4a29e64ec165f3e960988b78f6645ebbe1fa99fa3a002a8a1a94f2a2dcba2029246c6002e845
data/README.md CHANGED
@@ -22,76 +22,46 @@ Add this to your Gemfile:
22
22
  ```ruby
23
23
  group :development do
24
24
  gem "better_errors"
25
+ gem "binding_of_caller"
25
26
  end
26
27
  ```
27
28
 
28
- 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:
29
-
30
- ```ruby
31
- gem "binding_of_caller"
32
- ```
33
-
34
- This is an optional dependency however, and Better Errors will work without it.
29
+ [`binding_of_caller`](https://github.com/banister/binding_of_caller) is optional, but is necessary to use Better Errors' advanced features (REPL, local/instance variable inspection, pretty stack frame names).
35
30
 
36
31
  _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`._
37
32
 
38
33
  ## Security
39
34
 
40
- **NOTE:** It is *critical* you put better\_errors in the **development** section. **Do NOT run better_errors in production, or on Internet facing hosts.**
41
-
42
- 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.
43
-
44
- 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`)
45
-
46
- ```ruby
47
- BetterErrors::Middleware.allow_ip! ENV['TRUSTED_IP'] if ENV['TRUSTED_IP']
48
- ```
49
-
50
- Then run Rails like this:
51
-
52
- ```shell
53
- TRUSTED_IP=66.68.96.220 rails s
54
- ```
35
+ **NOTE:** It is *critical* you put better\_errors only in the **development** section of your Gemfile.
36
+ **Do NOT run better_errors in production, or on Internet-facing hosts.**
55
37
 
56
- Note that the `allow_ip!` is actually backed by a `Set`, so you can add more than one IP address or subnet.
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).
39
+ Obviously, the REPL is not something you want to expose to the public, and there may be sensitive information available in the backtrace.
57
40
 
58
- **Tip:** You can find your apparent IP by hitting the old error page's "Show env dump" and looking at "REMOTE_ADDR".
59
-
60
- **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.
41
+ For more information on how to configure access, see [the wiki](https://github.com/charliesome/better_errors/wiki/Allowing-access-to-the-console).
61
42
 
62
43
  ## Usage
63
44
 
64
45
  If you're using Rails, there's nothing else you need to do.
65
46
 
66
- 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.
67
-
68
- Here's an example using Sinatra:
47
+ ### Using without Rails.
69
48
 
70
- ```ruby
71
- require "sinatra"
72
- require "better_errors"
73
-
74
- configure :development do
75
- use BetterErrors::Middleware
76
- BetterErrors.application_root = __dir__
77
- end
49
+ 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.
78
50
 
79
- get "/" do
80
- raise "oops"
81
- end
82
- ```
51
+ For instructions for your specific middleware, [see the wiki](https://github.com/charliesome/better_errors/wiki/Non-Rails-frameworks).
83
52
 
84
- ### Plain text
53
+ ### Plain text requests
85
54
 
86
55
  Better Errors will render a plain text error page when the request is an
87
56
  `XMLHttpRequest` or when the `Accept` header does *not* include 'html'.
88
57
 
89
58
  ### Unicorn, Puma, and other multi-worker servers
90
59
 
91
- Better Errors works by leaving a lot of context in server process memory. If
92
- you're using a web server that runs multiple "workers" it's likely that a second
60
+ Better Errors works by leaving a lot of context in server process memory.
61
+ If you're using a web server that runs multiple "workers" it's likely that a second
93
62
  request (as happens when you click on a stack frame) will hit a different
94
- worker. That worker won't have the necessary context in memory, and you'll see
63
+ worker.
64
+ That worker won't have the necessary context in memory, and you'll see
95
65
  a `Session Expired` message.
96
66
 
97
67
  If this is the case for you, consider turning the number of workers to one (1)
@@ -99,13 +69,11 @@ in `development`. Another option would be to use Webrick, Mongrel, Thin,
99
69
  or another single-process server as your `rails server`, when you are trying
100
70
  to troubleshoot an issue in development.
101
71
 
102
- ##Specify editor to open files in
72
+ ### Changing the link to your editor
103
73
 
104
- ```ruby
105
- # e.g. in config/initializers/better_errors.rb
106
- # Other preset values are [:mvim, :macvim, :textmate, :txmt, :tm, :sublime, :subl, :st]
107
- BetterErrors.editor = :mvim
108
- ```
74
+ Better Errors includes a link to your editor for the file and line of code that is being shown.
75
+ By default, it uses your environment to determine which editor should be opened.
76
+ See [the wiki for instructions on configuring the editor](https://github.com/charliesome/better_errors/wiki/Link-to-your-editor).
109
77
 
110
78
  ## Get in touch!
111
79
 
@@ -12,13 +12,15 @@ Gem::Specification.new do |s|
12
12
  s.homepage = "https://github.com/charliesome/better_errors"
13
13
  s.license = "MIT"
14
14
 
15
- s.files = `git ls-files`.split($/)
16
- s.test_files = s.files.grep(%r{^(test|spec|features)/})
15
+ s.files = `git ls-files -z`.split("\x0").reject do |f|
16
+ f.match(%r{^((test|spec|features|feature-screenshots)/|Rakefile)})
17
+ end
18
+
17
19
  s.require_paths = ["lib"]
18
20
 
19
21
  s.required_ruby_version = ">= 2.0.0"
20
22
 
21
- s.add_dependency "erubis", ">= 2.6.6"
23
+ s.add_dependency "erubi", ">= 1.0.0"
22
24
  s.add_dependency "coderay", ">= 1.0.0"
23
25
  s.add_dependency "rack", ">= 0.9.0"
24
26
 
@@ -1,5 +1,5 @@
1
1
  require "pp"
2
- require "erubis"
2
+ require "erubi"
3
3
  require "coderay"
4
4
  require "uri"
5
5
 
@@ -10,7 +10,7 @@ module BetterErrors
10
10
  end
11
11
 
12
12
  def self.template(template_name)
13
- Erubis::EscapedEruby.new(File.read(template_path(template_name)))
13
+ Erubi::Engine.new(File.read(template_path(template_name)), escape: true)
14
14
  end
15
15
 
16
16
  attr_reader :exception, :env, :repls
@@ -27,7 +27,7 @@ module BetterErrors
27
27
  end
28
28
 
29
29
  def render(template_name = "main")
30
- self.class.template(template_name).result binding
30
+ binding.eval(self.class.template(template_name).src)
31
31
  end
32
32
 
33
33
  def do_variables(opts)
@@ -41,17 +41,13 @@ module BetterErrors
41
41
  index = opts["index"].to_i
42
42
  code = opts["source"]
43
43
 
44
- unless binding = backtrace_frames[index].frame_binding
44
+ unless (binding = backtrace_frames[index].frame_binding)
45
45
  return { error: "REPL unavailable in this stack frame" }
46
46
  end
47
47
 
48
- result, prompt, prefilled_input =
49
- (@repls[index] ||= REPL.provider.new(binding)).send_input(code)
48
+ @repls[index] ||= REPL.provider.new(binding, exception)
50
49
 
51
- { result: result,
52
- prompt: prompt,
53
- prefilled_input: prefilled_input,
54
- highlighted_input: CodeRay.scan(code, :ruby).div(wrap: nil) }
50
+ eval_and_respond(index, code)
55
51
  end
56
52
 
57
53
  def backtrace_frames
@@ -114,5 +110,16 @@ module BetterErrors
114
110
  rescue Exception
115
111
  "<span class='unsupported'>(exception was raised in inspect)</span>"
116
112
  end
113
+
114
+ def eval_and_respond(index, code)
115
+ result, prompt, prefilled_input = @repls[index].send_input(code)
116
+
117
+ {
118
+ highlighted_input: CodeRay.scan(code, :ruby).div(wrap: nil),
119
+ prefilled_input: prefilled_input,
120
+ prompt: prompt,
121
+ result: result
122
+ }
123
+ end
117
124
  end
118
125
  end
@@ -124,9 +124,8 @@ module BetterErrors
124
124
  end
125
125
 
126
126
  def internal_call(env, opts)
127
- if opts[:id] != @error_page.id
128
- return [200, { "Content-Type" => "text/plain; charset=utf-8" }, [JSON.dump(error: "Session expired")]]
129
- end
127
+ return no_errors_json_response unless @error_page
128
+ return invalid_error_json_response if opts[:id] != @error_page.id
130
129
 
131
130
  env["rack.input"].rewind
132
131
  response = @error_page.send("do_#{opts[:method]}", JSON.parse(env["rack.input"].read))
@@ -137,5 +136,33 @@ module BetterErrors
137
136
  "<h1>No errors</h1><p>No errors have been recorded yet.</p><hr>" +
138
137
  "<code>Better Errors v#{BetterErrors::VERSION}</code>"
139
138
  end
139
+
140
+ def no_errors_json_response
141
+ explanation = if defined? Middleman
142
+ "Middleman reloads all dependencies for each request, " +
143
+ "which breaks Better Errors."
144
+ elsif defined?(Shotgun) && defined?(Hanami)
145
+ "Hanami is likely running with code-reloading enabled, which is the default. " +
146
+ "You can disable this by running hanami with the `--no-code-reloading` option."
147
+ elsif defined? Shotgun
148
+ "The shotgun gem causes everything to be reloaded for every request. " +
149
+ "You can disable shotgun in the Gemfile temporarily to use Better Errors."
150
+ else
151
+ "The application has been restarted since this page loaded, " +
152
+ "or the framework is reloading all gems before each request "
153
+ end
154
+ [200, { "Content-Type" => "text/plain; charset=utf-8" }, [JSON.dump(
155
+ error: 'No exception information available',
156
+ explanation: explanation,
157
+ )]]
158
+ end
159
+
160
+ def invalid_error_json_response
161
+ [200, { "Content-Type" => "text/plain; charset=utf-8" }, [JSON.dump(
162
+ error: "Session expired",
163
+ explanation: "This page was likely opened from a previous exception, " +
164
+ "and the exception is no longer available in memory.",
165
+ )]]
166
+ end
140
167
  end
141
168
  end
@@ -21,7 +21,9 @@ module BetterErrors
21
21
  end
22
22
 
23
23
  def self.test_provider(provider)
24
- require provider[:impl]
24
+ # We must load this file instead of `require`ing it, since during our tests we want the file
25
+ # to be reloaded. In practice, this will only be called once, so `require` is not necessary.
26
+ load "#{provider[:impl]}.rb"
25
27
  true
26
28
  rescue LoadError
27
29
  false
@@ -1,7 +1,7 @@
1
1
  module BetterErrors
2
2
  module REPL
3
3
  class Basic
4
- def initialize(binding)
4
+ def initialize(binding, _exception)
5
5
  @binding = binding
6
6
  end
7
7
 
@@ -30,9 +30,13 @@ module BetterErrors
30
30
  ensure
31
31
  @buffer = ""
32
32
  end
33
+
34
+ def print(*args)
35
+ @buffer << args.join(' ')
36
+ end
33
37
  end
34
38
 
35
- def initialize(binding)
39
+ def initialize(binding, exception)
36
40
  @fiber = Fiber.new do
37
41
  @pry.repl binding
38
42
  end
@@ -40,9 +44,15 @@ module BetterErrors
40
44
  @output = BetterErrors::REPL::Pry::Output.new
41
45
  @pry = ::Pry.new input: @input, output: @output
42
46
  @pry.hooks.clear_all if defined?(@pry.hooks.clear_all)
47
+ store_last_exception exception
43
48
  @fiber.resume
44
49
  end
45
50
 
51
+ def store_last_exception(exception)
52
+ return unless defined? ::Pry::LastException
53
+ @pry.instance_variable_set(:@last_exception, ::Pry::LastException.new(exception.exception))
54
+ end
55
+
46
56
  def send_input(str)
47
57
  local ::Pry.config, color: false, pager: false do
48
58
  @fiber.resume "#{str}\n"
@@ -68,7 +68,14 @@ module BetterErrors
68
68
 
69
69
  def local_variables
70
70
  return {} unless frame_binding
71
+
71
72
  frame_binding.eval("local_variables").each_with_object({}) do |name, hash|
73
+ # Ruby 2.2's local_variables will include the hidden #$! variable if
74
+ # called from within a rescue context. This is not a valid variable name,
75
+ # so the local_variable_get method complains. This should probably be
76
+ # considered a bug in Ruby itself, but we need to work around it.
77
+ next if name == :"\#$!"
78
+
72
79
  if defined?(frame_binding.local_variable_get)
73
80
  hash[name] = frame_binding.local_variable_get(name)
74
81
  else
@@ -777,7 +777,7 @@
777
777
 
778
778
  function apiCall(method, opts, cb) {
779
779
  var req = new XMLHttpRequest();
780
- req.open("POST", <%== uri_prefix.gsub("<", "&lt;").inspect %> + "/__better_errors/" + OID + "/" + method, true);
780
+ req.open("POST", "//" + window.location.host + <%== uri_prefix.gsub("<", "&lt;").inspect %> + "/__better_errors/" + OID + "/" + method, true);
781
781
  req.setRequestHeader("Content-Type", "application/json");
782
782
  req.send(JSON.stringify(opts));
783
783
  req.onreadystatechange = function() {
@@ -938,7 +938,11 @@
938
938
  apiCall("variables", { "index": index }, function(response) {
939
939
  el.loaded = true;
940
940
  if(response.error) {
941
- el.innerHTML = "<span class='error'>" + escapeHTML(response.error) + "</span>";
941
+ el.innerHTML = "<h2 class='error'>" + escapeHTML(response.error) + "</h2>";
942
+ if(response.explanation) {
943
+ el.innerHTML += "<p class='explanation'>" + escapeHTML(response.explanation) + "</p>";
944
+ }
945
+ el.innerHTML += "<p><a target='_new' href='https://github.com/charliesome/better_errors'>More about Better Errors</a></p>";
942
946
  } else {
943
947
  el.innerHTML = response.html;
944
948
 
@@ -946,9 +950,8 @@
946
950
  if(repl) {
947
951
  new REPL(index).install(repl);
948
952
  }
949
-
950
- switchTo(el);
951
953
  }
954
+ switchTo(el);
952
955
  });
953
956
  }
954
957
  }
@@ -1,3 +1,3 @@
1
1
  module BetterErrors
2
- VERSION = "2.2.0"
2
+ VERSION = "2.3.0"
3
3
  end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: better_errors
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.0
4
+ version: 2.3.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: 2017-07-30 00:00:00.000000000 Z
11
+ date: 2017-08-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: erubis
14
+ name: erubi
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 2.6.6
19
+ version: 1.0.0
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
- version: 2.6.6
26
+ version: 1.0.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: coderay
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -68,17 +68,7 @@ files:
68
68
  - Gemfile
69
69
  - LICENSE.txt
70
70
  - README.md
71
- - Rakefile
72
71
  - better_errors.gemspec
73
- - feature-screenshots/1-application-error.jpg
74
- - feature-screenshots/2-other-application-frame.jpg
75
- - feature-screenshots/3-live-shell.jpg
76
- - feature-screenshots/4-other-frames.jpg
77
- - feature-screenshots/5-open-editor.jpg
78
- - feature-screenshots/6-local-variables.jpg
79
- - feature-screenshots/7-non-html-requests.jpg
80
- - feature-screenshots/8-xhr-shows-text-error.jpg
81
- - feature-screenshots/9-xhr-error-in-manual-console.jpg
82
72
  - lib/better_errors.rb
83
73
  - lib/better_errors/code_formatter.rb
84
74
  - lib/better_errors/code_formatter/html.rb
@@ -96,18 +86,6 @@ files:
96
86
  - lib/better_errors/templates/text.erb
97
87
  - lib/better_errors/templates/variable_info.erb
98
88
  - lib/better_errors/version.rb
99
- - spec/better_errors/code_formatter_spec.rb
100
- - spec/better_errors/error_page_spec.rb
101
- - spec/better_errors/middleware_spec.rb
102
- - spec/better_errors/raised_exception_spec.rb
103
- - spec/better_errors/repl/basic_spec.rb
104
- - spec/better_errors/repl/pry_spec.rb
105
- - spec/better_errors/repl/shared_examples.rb
106
- - spec/better_errors/stack_frame_spec.rb
107
- - spec/better_errors/support/my_source.rb
108
- - spec/better_errors_spec.rb
109
- - spec/spec_helper.rb
110
- - spec/without_binding_of_caller.rb
111
89
  homepage: https://github.com/charliesome/better_errors
112
90
  licenses:
113
91
  - MIT
@@ -132,16 +110,4 @@ rubygems_version: 2.6.8
132
110
  signing_key:
133
111
  specification_version: 4
134
112
  summary: Better error page for Rails and other Rack apps
135
- test_files:
136
- - spec/better_errors/code_formatter_spec.rb
137
- - spec/better_errors/error_page_spec.rb
138
- - spec/better_errors/middleware_spec.rb
139
- - spec/better_errors/raised_exception_spec.rb
140
- - spec/better_errors/repl/basic_spec.rb
141
- - spec/better_errors/repl/pry_spec.rb
142
- - spec/better_errors/repl/shared_examples.rb
143
- - spec/better_errors/stack_frame_spec.rb
144
- - spec/better_errors/support/my_source.rb
145
- - spec/better_errors_spec.rb
146
- - spec/spec_helper.rb
147
- - spec/without_binding_of_caller.rb
113
+ test_files: []
data/Rakefile DELETED
@@ -1,13 +0,0 @@
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"