pry-rescue 0.5 → 0.6

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.
data/bin/rescue CHANGED
@@ -23,7 +23,7 @@ if script = ARGV.shift
23
23
  begin; require 'pry-stack_explorer'; rescue LoadError; end
24
24
 
25
25
  $0 = File.expand_path script
26
- Pry.rescue { load script }
26
+ PryRescue.load script
27
27
  else
28
28
  $stderr.puts "Error: #{script.inspect} not found."
29
29
  end
@@ -18,28 +18,85 @@ class PryRescue
18
18
  # @param [Array<Binding>] bindings The call stack.
19
19
  def enter_exception_context(raised)
20
20
 
21
- exception, bindings = raised.last
22
- prune_call_stack!(bindings)
23
-
24
- if bindings.size > 1 && internal_binding?(bindings.first)
25
- raised.pop
26
- exception, bindings = raised.last
27
- prune_call_stack!(bindings)
21
+ raised = raised.map do |e, bs|
22
+ [e, without_bindings_below_raise(bs)]
28
23
  end
29
24
 
25
+ raised.pop if phantom_load_raise?(*raised.last)
26
+ exception, bindings = raised.last
27
+
30
28
  if defined?(PryStackExplorer)
31
- pry :call_stack => bindings, :hooks => pry_hooks(exception, raised)
29
+ pry :call_stack => without_duplicates(bindings),
30
+ :hooks => pry_hooks(exception, raised),
31
+ :initial_frame => initial_frame(bindings)
32
32
  else
33
- bindings.first.pry :hooks => pry_hooks(exception, raised)
33
+ Pry.start bindings.first, :hooks => pry_hooks(exception, raised)
34
34
  end
35
35
  end
36
36
 
37
+ # Load a script wrapped in Pry::rescue{ }
38
+ # @param [String] The name of the script
39
+ def load(script)
40
+ Pry::rescue{ Kernel.load script }
41
+ end
42
+
37
43
  private
38
44
 
39
- # Is this binding within pry-rescue?
40
- def internal_binding?(binding)
41
- binding.eval("__FILE__").start_with?(File.expand_path('../../lib', __FILE__)) ||
42
- binding.eval("__FILE__").start_with?(File.expand_path('../../bin', __FILE__))
45
+ # Did this raise happen within pry-rescue?
46
+ #
47
+ # This is designed to remove the extra raise that is caused by PryRescue.load.
48
+ # TODO: we should figure out why it happens...
49
+ # @param [Array<Binding>]
50
+ def phantom_load_raise?(e, bindings)
51
+ bindings.any? && bindings.first.eval("__FILE__") == __FILE__
52
+ end
53
+
54
+ # When using pry-stack-explorer we want to start the rescue session outside of gems
55
+ # and the standard library, as that is most helpful for users.
56
+ #
57
+ # @param [Array<Bindings>] All bindings
58
+ # @return [Fixnum] The offset of the first binding of user code
59
+ def initial_frame(bindings)
60
+ bindings.each_with_index do |binding, i|
61
+ return i if user_path?(binding.eval("__FILE__"))
62
+ end
63
+
64
+ 0
65
+ end
66
+
67
+ # Is this path likely to be code the user is working with right now?
68
+ #
69
+ # @param [String] the absolute path
70
+ # @return [Boolean]
71
+ def user_path?(file)
72
+ !file.start_with?(RbConfig::CONFIG['libdir']) &&
73
+ !Gem::Specification.any?{ |gem| file.start_with?(gem.full_gem_path) }
74
+ end
75
+
76
+ # Remove bindings that are part of Interception/Pry.rescue's internal
77
+ # event handling that happens as part of the exception hooking process.
78
+ #
79
+ # @param [Array<Binding>] bindings The call stack.
80
+ def without_bindings_below_raise(bindings)
81
+ return bindings if bindings.size <= 1
82
+ bindings.drop_while do |b|
83
+ b.eval("__FILE__") == File.expand_path("../pry-rescue/core_ext.rb", __FILE__)
84
+ end.drop_while do |b|
85
+ b.eval("self") == Interception
86
+ end
87
+ end
88
+
89
+ # Remove multiple bindings for the same function.
90
+ #
91
+ # @param [Array<Bindings>]
92
+ # @return [Array<Bindings>]
93
+ def without_duplicates(bindings)
94
+ bindings.zip([nil] + bindings).reject do |b, c|
95
+ # The eval('__method__') is there as a shortcut as loading a method
96
+ # from a binding is very slow.
97
+ c && (b.eval("__method__") == c.eval("__method__")) &&
98
+ Pry::Method.from_binding(b) == Pry::Method.from_binding(c)
99
+ end.map(&:first)
43
100
  end
44
101
 
45
102
  # Define the :before_session hook for the Pry instance.
@@ -56,11 +113,5 @@ class PryRescue
56
113
 
57
114
  hooks
58
115
  end
59
-
60
- # Sanitize the call stack.
61
- # @param [Array<Binding>] bindings The call stack.
62
- def prune_call_stack!(bindings)
63
- bindings.delete_if { |b| [Pry, Interception].include?(b.eval("self")) }
64
- end
65
116
  end
66
117
  end
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'pry-rescue'
3
- s.version = '0.5'
3
+ s.version = '0.6'
4
4
  s.summary = 'Open a pry session on any unhandled exceptions'
5
5
  s.description = 'Allows you to wrap code in Pry::rescue{ } to open a pry session at any unhandled exceptions'
6
6
  s.homepage = 'https://github.com/ConradIrwin/pry-rescue'
@@ -0,0 +1,3 @@
1
+ require 'coderay'
2
+
3
+ CodeRay.scan(123,123).tokens
@@ -0,0 +1 @@
1
+ raise "fixtures/simple"
@@ -0,0 +1,2 @@
1
+ require 'uri'
2
+ URI.parse(0)
@@ -0,0 +1,70 @@
1
+ require File.expand_path('../../lib/pry-rescue.rb', __FILE__)
2
+ require 'uri'
3
+
4
+ describe "PryRescue.load" do
5
+ if defined?(PryStackExplorer)
6
+ it "should open at the correct point" do
7
+ PryRescue.should_receive(:pry).once{ |opts|
8
+ opts[:call_stack].first.eval("__FILE__").should end_with('spec/fixtures/simple.rb')
9
+ }
10
+ lambda{
11
+ PryRescue.load("spec/fixtures/simple.rb")
12
+ }.should raise_error(/fixtures.simple/)
13
+ end
14
+
15
+ it "should open above the standard library" do
16
+ PryRescue.should_receive(:pry).once do |opts|
17
+ opts[:call_stack][opts[:initial_frame]].eval("__FILE__").should end_with('spec/fixtures/uri.rb')
18
+ end
19
+ lambda{
20
+ PryRescue.load("spec/fixtures/uri.rb")
21
+ }.should raise_error(URI::InvalidURIError)
22
+ end
23
+
24
+ it "should keep the standard library on the binding stack" do
25
+ PryRescue.should_receive(:pry).once do |opts|
26
+ opts[:call_stack].first.eval("__FILE__").should start_with(RbConfig::CONFIG['libdir'])
27
+ end
28
+ lambda{
29
+ PryRescue.load("spec/fixtures/uri.rb")
30
+ }.should raise_error(URI::InvalidURIError)
31
+ end
32
+
33
+ it "should open above gems" do
34
+ PryRescue.should_receive(:pry).once do |opts|
35
+ opts[:call_stack][opts[:initial_frame]].eval("__FILE__").should end_with('spec/fixtures/coderay.rb')
36
+ end
37
+ lambda{
38
+ PryRescue.load("spec/fixtures/coderay.rb")
39
+ }.should raise_error(ArgumentError)
40
+ end
41
+
42
+ it "should open above gems" do
43
+ PryRescue.should_receive(:pry).once do |opts|
44
+ opts[:call_stack].first.eval("__FILE__").should start_with(Gem::Specification.detect{|x| x.name == 'coderay' }.full_gem_path)
45
+ end
46
+ lambda{
47
+ PryRescue.load("spec/fixtures/coderay.rb")
48
+ }.should raise_error(ArgumentError)
49
+ end
50
+
51
+ it "should filter out duplicate stack frames" do
52
+ PryRescue.should_receive(:pry).once do |opts|
53
+ opts[:call_stack][0].eval("__LINE__").should == 4
54
+ opts[:call_stack][1].eval("__LINE__").should == 12
55
+ end
56
+ lambda{
57
+ PryRescue.load("spec/fixtures/super.rb")
58
+ }.should raise_error(/fixtures.super/)
59
+ end
60
+ else
61
+ it "should open at the correct point" do
62
+ Pry.should_receive(:start).once{ |binding, h|
63
+ binding.eval("__FILE__").should end_with('spec/fixtures/simple.rb')
64
+ }
65
+ lambda{
66
+ PryRescue.load("spec/fixtures/simple.rb")
67
+ }.should raise_error(/fixtures.simple/)
68
+ end
69
+ end
70
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pry-rescue
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.5'
4
+ version: '0.6'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -70,6 +70,10 @@ files:
70
70
  - lib/pry/rescue.rb
71
71
  - pry-rescue.gemspec
72
72
  - spec/core_ext_spec.rb
73
+ - spec/fixtures/coderay.rb
74
+ - spec/fixtures/simple.rb
75
+ - spec/fixtures/uri.rb
76
+ - spec/pry_rescue_spec.rb
73
77
  homepage: https://github.com/ConradIrwin/pry-rescue
74
78
  licenses: []
75
79
  post_install_message: