better_errors 0.0.2 → 0.2.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.
@@ -0,0 +1,21 @@
1
+ <div class="sub">
2
+ <h3>Local Variables</h3>
3
+ <div class='inset variables'>
4
+ <table class="var_table">
5
+ <% @frame.local_variables.each do |name, value| %>
6
+ <tr><td class="name"><%= name %></td><td><pre><%= value.inspect %></pre></td></tr>
7
+ <% end %>
8
+ </table>
9
+ </div>
10
+ </div>
11
+
12
+ <div class="sub">
13
+ <h3>Instance Variables</h3>
14
+ <div class="inset variables">
15
+ <table class="var_table">
16
+ <% @frame.instance_variables.each do |name, value| %>
17
+ <tr><td class="name"><%= name %></td><td><pre><%= value.inspect %></pre></td></tr>
18
+ <% end %>
19
+ </table>
20
+ </div>
21
+ </div>
@@ -1,3 +1,3 @@
1
1
  module BetterErrors
2
- VERSION = "0.0.2"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/better_errors.rb CHANGED
@@ -4,11 +4,13 @@ require "coderay"
4
4
 
5
5
  require "better_errors/version"
6
6
  require "better_errors/error_page"
7
- require "better_errors/error_frame"
7
+ require "better_errors/stack_frame"
8
8
  require "better_errors/middleware"
9
+ require "better_errors/code_formatter"
10
+ require "better_errors/repl"
9
11
 
10
12
  class << BetterErrors
11
- attr_accessor :application_root, :binding_of_caller_available
13
+ attr_accessor :application_root, :binding_of_caller_available, :logger
12
14
 
13
15
  alias_method :binding_of_caller_available?, :binding_of_caller_available
14
16
  end
@@ -20,12 +22,12 @@ rescue LoadError => e
20
22
  BetterErrors.binding_of_caller_available = false
21
23
  end
22
24
 
23
- if BetterErrors.binding_of_caller_available?
24
- require "better_errors/core_ext/exception"
25
- else
25
+ unless BetterErrors.binding_of_caller_available?
26
26
  warn "BetterErrors: binding_of_caller gem unavailable, cannot display local variables on error pages."
27
27
  warn "Add 'binding_of_caller' to your Gemfile to make this warning go away."
28
28
  warn ""
29
29
  end
30
30
 
31
+ require "better_errors/core_ext/exception"
32
+
31
33
  require "better_errors/rails" if defined? Rails::Railtie
@@ -0,0 +1,51 @@
1
+ require "spec_helper"
2
+
3
+ module BetterErrors
4
+ describe CodeFormatter do
5
+ let(:filename) { File.expand_path("../support/my_source.rb", __FILE__) }
6
+
7
+ let(:formatter) { CodeFormatter.new(filename, 8) }
8
+
9
+ it "should pick an appropriate scanner" do
10
+ formatter.coderay_scanner.should == :ruby
11
+ end
12
+
13
+ it "should show 5 lines of context" do
14
+ formatter.line_range.should == (3..13)
15
+
16
+ formatter.context_lines.should == [
17
+ "three\n",
18
+ "four\n",
19
+ "five\n",
20
+ "six\n",
21
+ "seven\n",
22
+ "eight\n",
23
+ "nine\n",
24
+ "ten\n",
25
+ "eleven\n",
26
+ "twelve\n",
27
+ "thirteen\n"
28
+ ]
29
+ end
30
+
31
+ it "should highlight the erroring line" do
32
+ formatter.html.should =~ /highlight.*eight/
33
+ end
34
+
35
+ it "should work when the line is right on the edge" do
36
+ formatter = CodeFormatter.new(filename, 20)
37
+ formatter.line_range.should == (15..20)
38
+ formatter.html.should_not == formatter.source_unavailable
39
+ end
40
+
41
+ it "should not barf when the lines don't make any sense" do
42
+ formatter = CodeFormatter.new(filename, 999)
43
+ formatter.html.should == formatter.source_unavailable
44
+ end
45
+
46
+ it "should not barf when the file doesn't exist" do
47
+ formatter = CodeFormatter.new("fkdguhskd7e l", 1)
48
+ formatter.html.should == formatter.source_unavailable
49
+ end
50
+ end
51
+ end
@@ -7,6 +7,16 @@ module BetterErrors
7
7
  let(:error_page) { ErrorPage.new exception, { "REQUEST_PATH" => "/some/path" } }
8
8
 
9
9
  let(:response) { error_page.render }
10
+
11
+ let(:empty_binding) {
12
+ local_a = :value_for_local_a
13
+ local_b = :value_for_local_b
14
+
15
+ @inst_c = :value_for_inst_c
16
+ @inst_d = :value_for_inst_d
17
+
18
+ binding
19
+ }
10
20
 
11
21
  it "should include the error message" do
12
22
  response.should include("you divided by zero you silly goose!")
@@ -20,26 +30,31 @@ module BetterErrors
20
30
  response.should include("ZeroDivisionError")
21
31
  end
22
32
 
23
- context "when showing source code" do
24
- before do
25
- exception.stub!(:backtrace).and_return([
26
- "#{File.expand_path("../support/my_source.rb", __FILE__)}:8:in `some_method'"
27
- ])
28
- end
33
+ context "variable inspection" do
34
+ let(:exception) { empty_binding.eval("raise") rescue $! }
29
35
 
30
- it "should show the line where the exception was raised" do
31
- response.should include("8 eight")
36
+ it "should show local variables" do
37
+ html = error_page.do_variables("index" => 0)[:html]
38
+ html.should include("local_a")
39
+ html.should include(":value_for_local_a")
40
+ html.should include("local_b")
41
+ html.should include(":value_for_local_b")
32
42
  end
33
43
 
34
- it "should show five lines of context" do
35
- response.should include("3 three")
36
- response.should include("13 thirteen")
37
- end
38
-
39
- it "should not show more than five lines of context" do
40
- response.should_not include("2 two")
41
- response.should_not include("14 fourteen")
44
+ it "should show instance variables" do
45
+ html = error_page.do_variables("index" => 0)[:html]
46
+ html.should include("inst_c")
47
+ html.should include(":value_for_inst_c")
48
+ html.should include("inst_d")
49
+ html.should include(":value_for_inst_d")
42
50
  end
43
51
  end
52
+
53
+ it "should not die if the source file is not a real filename" do
54
+ exception.stub!(:backtrace).and_return([
55
+ "<internal:prelude>:10:in `spawn_rack_application'"
56
+ ])
57
+ response.should include("Source unavailable")
58
+ end
44
59
  end
45
60
  end
@@ -21,6 +21,14 @@ module BetterErrors
21
21
 
22
22
  headers["Content-Type"].should == "text/html; charset=utf-8"
23
23
  end
24
+
25
+ it "should log the exception" do
26
+ logger = Object.new
27
+ logger.should_receive :fatal
28
+ BetterErrors.stub!(:logger).and_return(logger)
29
+
30
+ app.call({})
31
+ end
24
32
  end
25
33
  end
26
34
  end
@@ -0,0 +1,32 @@
1
+ require "spec_helper"
2
+ require "better_errors/repl/basic"
3
+
4
+ module BetterErrors
5
+ module REPL
6
+ describe Basic do
7
+ let(:fresh_binding) {
8
+ local_a = 123
9
+ binding
10
+ }
11
+
12
+ let(:repl) { Basic.new fresh_binding }
13
+
14
+ it "should evaluate ruby code in a given context" do
15
+ repl.send_input("local_a = 456")
16
+ fresh_binding.eval("local_a").should == 456
17
+ end
18
+
19
+ it "should return a tuple of output and the new prompt" do
20
+ output, prompt = repl.send_input("1 + 2")
21
+ output.should == "=> 3\n"
22
+ prompt.should == ">>"
23
+ end
24
+
25
+ it "should not barf if the code throws an exception" do
26
+ output, prompt = repl.send_input("raise Exception")
27
+ output.should == "!! #<Exception: Exception>\n"
28
+ prompt.should == ">>"
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,24 +1,24 @@
1
1
  require "spec_helper"
2
2
 
3
3
  module BetterErrors
4
- describe ErrorFrame do
4
+ describe StackFrame do
5
5
  context "#application?" do
6
6
  it "should be true for application filenames" do
7
7
  BetterErrors.stub!(:application_root).and_return("/abc/xyz")
8
- frame = ErrorFrame.new("/abc/xyz/app/controllers/crap_controller.rb", 123, "index")
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 "should be false for everything else" do
14
14
  BetterErrors.stub!(:application_root).and_return("/abc/xyz")
15
- frame = ErrorFrame.new("/abc/nope", 123, "foo")
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 "should not care if no application_root is set" do
21
- frame = ErrorFrame.new("/abc/xyz/app/controllers/crap_controller.rb", 123, "index")
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
@@ -27,14 +27,14 @@ module BetterErrors
27
27
  context "#gem?" do
28
28
  it "should be true for gem filenames" do
29
29
  Gem.stub!(:path).and_return(["/abc/xyz"])
30
- frame = ErrorFrame.new("/abc/xyz/gems/whatever-1.2.3/lib/whatever.rb", 123, "foo")
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 "should be false for everything else" do
36
36
  Gem.stub!(:path).and_return(["/abc/xyz"])
37
- frame = ErrorFrame.new("/abc/nope", 123, "foo")
37
+ frame = StackFrame.new("/abc/nope", 123, "foo")
38
38
 
39
39
  frame.gem?.should be_false
40
40
  end
@@ -43,7 +43,7 @@ module BetterErrors
43
43
  context "#application_path" do
44
44
  it "should chop off the application root" do
45
45
  BetterErrors.stub!(:application_root).and_return("/abc/xyz")
46
- frame = ErrorFrame.new("/abc/xyz/app/controllers/crap_controller.rb", 123, "index")
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
@@ -52,10 +52,33 @@ module BetterErrors
52
52
  context "#gem_path" do
53
53
  it "should chop of the gem path and stick (gem) there" do
54
54
  Gem.stub!(:path).and_return(["/abc/xyz"])
55
- frame = ErrorFrame.new("/abc/xyz/gems/whatever-1.2.3/lib/whatever.rb", 123, "foo")
55
+ frame = StackFrame.new("/abc/xyz/gems/whatever-1.2.3/lib/whatever.rb", 123, "foo")
56
56
 
57
57
  frame.gem_path.should == "(gem) whatever-1.2.3/lib/whatever.rb"
58
58
  end
59
59
  end
60
+
61
+ it "should special case SyntaxErrors" do
62
+ syntax_error = SyntaxError.new "my_file.rb:123: you wrote bad ruby!"
63
+ syntax_error.stub!(:backtrace).and_return([])
64
+ frames = StackFrame.from_exception(syntax_error)
65
+ frames.count.should == 1
66
+ frames.first.filename.should == "my_file.rb"
67
+ frames.first.line.should == 123
68
+ end
69
+
70
+ it "should not blow up if no method name is given" do
71
+ error = StandardError.new
72
+
73
+ error.stub!(:backtrace).and_return(["foo.rb:123"])
74
+ frames = StackFrame.from_exception(error)
75
+ frames.first.filename.should == "foo.rb"
76
+ frames.first.line.should == 123
77
+
78
+ error.stub!(:backtrace).and_return(["foo.rb:123: this is an error message"])
79
+ frames = StackFrame.from_exception(error)
80
+ frames.first.filename.should == "foo.rb"
81
+ frames.first.line.should == 123
82
+ end
60
83
  end
61
84
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: better_errors
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-08 00:00:00.000000000 Z
12
+ date: 2012-12-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -34,7 +34,7 @@ dependencies:
34
34
  requirements:
35
35
  - - ! '>='
36
36
  - !ruby/object:Gem::Version
37
- version: '0'
37
+ version: 2.7.0
38
38
  type: :runtime
39
39
  prerelease: false
40
40
  version_requirements: !ruby/object:Gem::Requirement
@@ -42,7 +42,7 @@ dependencies:
42
42
  requirements:
43
43
  - - ! '>='
44
44
  - !ruby/object:Gem::Version
45
- version: '0'
45
+ version: 2.7.0
46
46
  - !ruby/object:Gem::Dependency
47
47
  name: coderay
48
48
  requirement: !ruby/object:Gem::Requirement
@@ -50,7 +50,7 @@ dependencies:
50
50
  requirements:
51
51
  - - ! '>='
52
52
  - !ruby/object:Gem::Version
53
- version: '0'
53
+ version: 1.0.0
54
54
  type: :runtime
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
@@ -58,8 +58,10 @@ dependencies:
58
58
  requirements:
59
59
  - - ! '>='
60
60
  - !ruby/object:Gem::Version
61
- version: '0'
62
- description: Better Errors gives Rails a better error page.
61
+ version: 1.0.0
62
+ description: Provides a better error page for Rails and other Rack apps. Includes
63
+ source code inspection, a live REPL and local/instance variable inspection for all
64
+ stack frames.
63
65
  email:
64
66
  - charlie@charliesomerville.com
65
67
  executables: []
@@ -73,16 +75,23 @@ files:
73
75
  - Rakefile
74
76
  - better_errors.gemspec
75
77
  - lib/better_errors.rb
78
+ - lib/better_errors/code_formatter.rb
76
79
  - lib/better_errors/core_ext/exception.rb
77
- - lib/better_errors/error_frame.rb
78
- - lib/better_errors/error_page.erb
79
80
  - lib/better_errors/error_page.rb
80
81
  - lib/better_errors/middleware.rb
81
82
  - lib/better_errors/rails.rb
83
+ - lib/better_errors/repl.rb
84
+ - lib/better_errors/repl/basic.rb
85
+ - lib/better_errors/repl/pry.rb
86
+ - lib/better_errors/stack_frame.rb
87
+ - lib/better_errors/templates/main.erb
88
+ - lib/better_errors/templates/variable_info.erb
82
89
  - lib/better_errors/version.rb
83
- - spec/better_errors/error_frame_spec.rb
90
+ - spec/better_errors/code_formatter_spec.rb
84
91
  - spec/better_errors/error_page_spec.rb
85
92
  - spec/better_errors/middleware_spec.rb
93
+ - spec/better_errors/repl/basic_spec.rb
94
+ - spec/better_errors/stack_frame_spec.rb
86
95
  - spec/better_errors/support/my_source.rb
87
96
  - spec/spec_helper.rb
88
97
  homepage: https://github.com/charliesome/better_errors
@@ -109,11 +118,13 @@ rubyforge_project:
109
118
  rubygems_version: 1.8.24
110
119
  signing_key:
111
120
  specification_version: 3
112
- summary: Better Errors gives Rails a better error page
121
+ summary: Better error page for Rails and other Rack apps
113
122
  test_files:
114
- - spec/better_errors/error_frame_spec.rb
123
+ - spec/better_errors/code_formatter_spec.rb
115
124
  - spec/better_errors/error_page_spec.rb
116
125
  - spec/better_errors/middleware_spec.rb
126
+ - spec/better_errors/repl/basic_spec.rb
127
+ - spec/better_errors/stack_frame_spec.rb
117
128
  - spec/better_errors/support/my_source.rb
118
129
  - spec/spec_helper.rb
119
130
  has_rdoc:
@@ -1,86 +0,0 @@
1
- module BetterErrors
2
- class ErrorFrame
3
- def self.from_exception(exception)
4
- exception.backtrace.each_with_index.map { |frame, idx|
5
- next unless frame =~ /\A(.*):(\d*):in `(.*)'\z/
6
- b = exception.__better_errors_bindings_stack[idx]
7
- ErrorFrame.new($1, $2.to_i, $3, b)
8
- }.compact
9
- end
10
-
11
- attr_reader :filename, :line, :name, :frame_binding
12
-
13
- def initialize(filename, line, name, frame_binding = nil)
14
- @filename = filename
15
- @line = line
16
- @name = name
17
- @frame_binding = frame_binding
18
-
19
- set_pretty_method_name if frame_binding
20
- end
21
-
22
- def application?
23
- starts_with? filename, BetterErrors.application_root if BetterErrors.application_root
24
- end
25
-
26
- def application_path
27
- filename[(BetterErrors.application_root.length+1)..-1]
28
- end
29
-
30
- def gem?
31
- Gem.path.any? { |path| starts_with? filename, path }
32
- end
33
-
34
- def gem_path
35
- Gem.path.each do |path|
36
- if starts_with? filename, path
37
- return filename.gsub("#{path}/gems/", "(gem) ")
38
- end
39
- end
40
- end
41
-
42
- def context
43
- if application?
44
- :application
45
- elsif gem?
46
- :gem
47
- else
48
- :dunno
49
- end
50
- end
51
-
52
- def pretty_path
53
- case context
54
- when :application; application_path
55
- when :gem; gem_path
56
- else filename
57
- end
58
- end
59
-
60
- def local_variables
61
- return {} unless frame_binding
62
- Hash[frame_binding.eval("local_variables").map { |x| [x, frame_binding.eval(x.to_s)] }]
63
- end
64
-
65
- def instance_variables
66
- return {} unless frame_binding
67
- Hash[frame_binding.eval("instance_variables").map { |x| [x, frame_binding.eval(x.to_s)] }]
68
- end
69
-
70
- private
71
- def set_pretty_method_name
72
- name =~ /\A(block (\([^)]+\) )?in )?/
73
- recv = frame_binding.eval("self")
74
- method = frame_binding.eval("__method__")
75
- @name = if recv.is_a? Module
76
- "#{$1}#{recv}.#{method}"
77
- else
78
- "#{$1}#{recv.class}##{method}"
79
- end
80
- end
81
-
82
- def starts_with?(haystack, needle)
83
- haystack[0, needle.length] == needle
84
- end
85
- end
86
- end