better_errors 2.2.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.

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"