pry-exception_explorer 0.1.1pre1 → 0.1.1pre3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gemtest +0 -0
- data/.gitignore +7 -0
- data/.travis.yml +15 -0
- data/.yardopts +1 -0
- data/Gemfile +2 -0
- data/LICENSE +25 -0
- data/Rakefile +89 -74
- data/lib/pry-exception_explorer/commands.rb +42 -0
- data/lib/pry-exception_explorer/exception_wrap.rb +14 -2
- data/lib/pry-exception_explorer/lazy_frame.rb +32 -0
- data/lib/pry-exception_explorer/version.rb +1 -1
- data/lib/pry-exception_explorer.rb +73 -37
- data/pry-exception_explorer.gemspec +36 -0
- data/test/helper.rb +101 -0
- data/test/test_exception_explorer.rb +159 -0
- data/test/test_exceptions_in_pry.rb +29 -0
- data/test/test_wrapped_exceptions.rb +160 -0
- metadata +48 -11
- data/test/test.rb +0 -12
data/.gemtest
ADDED
File without changes
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--markup markdown
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
License
|
2
|
+
-------
|
3
|
+
|
4
|
+
(The MIT License)
|
5
|
+
|
6
|
+
Copyright (c) 2011 John Mair (banisterfiend)
|
7
|
+
|
8
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
9
|
+
a copy of this software and associated documentation files (the
|
10
|
+
'Software'), to deal in the Software without restriction, including
|
11
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
12
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
13
|
+
permit persons to whom the Software is furnished to do so, subject to
|
14
|
+
the following conditions:
|
15
|
+
|
16
|
+
The above copyright notice and this permission notice shall be
|
17
|
+
included in all copies or substantial portions of the Software.
|
18
|
+
|
19
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
20
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
21
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
22
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
23
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
24
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
25
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
CHANGED
@@ -1,76 +1,91 @@
|
|
1
|
-
$:.unshift 'lib'
|
2
|
-
|
3
|
-
dlext =
|
4
|
-
direc = File.dirname(__FILE__)
|
5
|
-
|
6
|
-
PROJECT_NAME = "pry-exception_explorer"
|
7
|
-
|
8
|
-
require 'rake/clean'
|
9
|
-
require 'rake/gempackagetask'
|
10
|
-
require "#{PROJECT_NAME}/version"
|
11
|
-
|
12
|
-
CLOBBER.include("**/*~", "**/*#*", "**/*.log")
|
13
|
-
CLEAN.include("**/*#*", "**/*#*.*", "**/*_flymake*.*", "**/*_flymake",
|
14
|
-
"**/*.rbc", "**/.#*.*")
|
15
|
-
|
16
|
-
def apply_spec_defaults(s)
|
17
|
-
s.name = PROJECT_NAME
|
18
|
-
s.summary = "
|
19
|
-
s.version = PryExceptionExplorer::VERSION
|
20
|
-
s.date = Time.now.strftime '%Y-%m-%d'
|
21
|
-
s.author = "John Mair (banisterfiend)"
|
22
|
-
s.email = 'jrmair@gmail.com'
|
23
|
-
s.description = s.summary
|
24
|
-
s.require_path = 'lib'
|
25
|
-
s.homepage = "https://github.com/banister/pry-exception_explorer"
|
26
|
-
|
27
|
-
s.
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
1
|
+
$:.unshift 'lib'
|
2
|
+
|
3
|
+
dlext = RbConfig::CONFIG['DLEXT']
|
4
|
+
direc = File.dirname(__FILE__)
|
5
|
+
|
6
|
+
PROJECT_NAME = "pry-exception_explorer"
|
7
|
+
|
8
|
+
require 'rake/clean'
|
9
|
+
require 'rake/gempackagetask'
|
10
|
+
require "#{PROJECT_NAME}/version"
|
11
|
+
|
12
|
+
CLOBBER.include("**/*~", "**/*#*", "**/*.log")
|
13
|
+
CLEAN.include("**/*#*", "**/*#*.*", "**/*_flymake*.*", "**/*_flymake",
|
14
|
+
"**/*.rbc", "**/.#*.*")
|
15
|
+
|
16
|
+
def apply_spec_defaults(s)
|
17
|
+
s.name = PROJECT_NAME
|
18
|
+
s.summary = "Enter the context of exceptions"
|
19
|
+
s.version = PryExceptionExplorer::VERSION
|
20
|
+
s.date = Time.now.strftime '%Y-%m-%d'
|
21
|
+
s.author = "John Mair (banisterfiend)"
|
22
|
+
s.email = 'jrmair@gmail.com'
|
23
|
+
s.description = s.summary
|
24
|
+
s.require_path = 'lib'
|
25
|
+
s.homepage = "https://github.com/banister/pry-exception_explorer"
|
26
|
+
s.add_dependency('pry-stack_explorer')
|
27
|
+
s.add_development_dependency("bacon","~>1.1.0")
|
28
|
+
s.add_development_dependency('rake', '~> 0.9')
|
29
|
+
|
30
|
+
s.files = `git ls-files`.split("\n")
|
31
|
+
s.test_files = `git ls-files -- test/*`.split("\n")
|
32
|
+
end
|
33
|
+
|
34
|
+
desc "run pry with plugin enabled"
|
35
|
+
task :pry do
|
36
|
+
exec("pry -I#{direc}/lib/ -r #{direc}/lib/#{PROJECT_NAME}")
|
37
|
+
end
|
38
|
+
|
39
|
+
desc "reinstall gem"
|
40
|
+
task :reinstall => :gems do
|
41
|
+
sh "rm -rf ~/.pry-exception_explorer"
|
37
42
|
sh "gem uninstall pry-exception_explorer" rescue nil
|
38
|
-
sh "gem install #{direc}/pkg/pry-exception_explorer-#{PryExceptionExplorer::VERSION}.gem"
|
43
|
+
sh "gem install #{direc}/pkg/pry-exception_explorer-#{PryExceptionExplorer::VERSION}.gem"
|
44
|
+
end
|
45
|
+
|
46
|
+
desc "run tests"
|
47
|
+
task :test do
|
48
|
+
sh "bacon -Itest -rubygems -a"
|
49
|
+
end
|
50
|
+
|
51
|
+
desc "Build gemspec"
|
52
|
+
task :gemspec => "ruby:gemspec"
|
53
|
+
|
54
|
+
namespace :ruby do
|
55
|
+
spec = Gem::Specification.new do |s|
|
56
|
+
apply_spec_defaults(s)
|
57
|
+
s.platform = Gem::Platform::RUBY
|
58
|
+
end
|
59
|
+
|
60
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
61
|
+
pkg.need_zip = false
|
62
|
+
pkg.need_tar = false
|
63
|
+
end
|
64
|
+
|
65
|
+
desc "Generate gemspec file"
|
66
|
+
task :gemspec do
|
67
|
+
File.open("#{spec.name}.gemspec", "w") do |f|
|
68
|
+
f << spec.to_ruby
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
desc "shorthand for :gems task"
|
74
|
+
task :gem => :gems
|
75
|
+
|
76
|
+
desc "build all platform gems at once"
|
77
|
+
task :gems => [:clean, :rmgems, "ruby:gem"]
|
78
|
+
|
79
|
+
desc "remove all platform gems"
|
80
|
+
task :rmgems => ["ruby:clobber_package"]
|
81
|
+
|
82
|
+
desc "build and push latest gems"
|
83
|
+
task :pushgems => :gems do
|
84
|
+
chdir("#{File.dirname(__FILE__)}/pkg") do
|
85
|
+
Dir["*.gem"].each do |gemfile|
|
86
|
+
sh "gem push #{gemfile}"
|
87
|
+
end
|
88
|
+
end
|
39
89
|
end
|
40
|
-
|
41
|
-
|
42
|
-
task :test do
|
43
|
-
sh "bacon -Itest -rubygems -a"
|
44
|
-
end
|
45
|
-
|
46
|
-
namespace :ruby do
|
47
|
-
spec = Gem::Specification.new do |s|
|
48
|
-
apply_spec_defaults(s)
|
49
|
-
s.platform = Gem::Platform::RUBY
|
50
|
-
end
|
51
|
-
|
52
|
-
Rake::GemPackageTask.new(spec) do |pkg|
|
53
|
-
pkg.need_zip = false
|
54
|
-
pkg.need_tar = false
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
desc "shorthand for :gems task"
|
59
|
-
task :gem => :gems
|
60
|
-
|
61
|
-
desc "build all platform gems at once"
|
62
|
-
task :gems => [:clean, :rmgems, "ruby:gem"]
|
63
|
-
|
64
|
-
desc "remove all platform gems"
|
65
|
-
task :rmgems => ["ruby:clobber_package"]
|
66
|
-
|
67
|
-
desc "build and push latest gems"
|
68
|
-
task :pushgems => :gems do
|
69
|
-
chdir("#{File.dirname(__FILE__)}/pkg") do
|
70
|
-
Dir["*.gem"].each do |gemfile|
|
71
|
-
sh "gem push #{gemfile}"
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
|
90
|
+
|
91
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'pry-stack_explorer'
|
2
|
+
|
3
|
+
PryExceptionExplorer::Commands = Pry::CommandSet.new do
|
4
|
+
|
5
|
+
command "enter-exception", "Enter the context of the last exception" do
|
6
|
+
ex = _pry_.last_exception
|
7
|
+
if ex && ex.exception_call_stack
|
8
|
+
PryStackExplorer.create_and_push_frame_manager(ex.exception_call_stack, _pry_)
|
9
|
+
PryStackExplorer.frame_manager(_pry_).user[:exception] = ex
|
10
|
+
PryStackExplorer.frame_manager(_pry_).refresh_frame
|
11
|
+
elsif ex
|
12
|
+
output.puts "Current exception can't be entered! (perhaps a C exception)"
|
13
|
+
else
|
14
|
+
output.puts "No exception to enter!"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
command "exit-exception", "Leave the context of the current exception." do
|
19
|
+
fm = PryStackExplorer.frame_manager(_pry_)
|
20
|
+
if fm && fm.user[:exception]
|
21
|
+
PryStackExplorer.pop_frame_manager(_pry_)
|
22
|
+
PryStackExplorer.frame_manager(_pry_).refresh_frame
|
23
|
+
else
|
24
|
+
output.puts "You are not in an exception!"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
command "continue-exception", "Attempt to continue the current exception." do
|
29
|
+
fm = PryStackExplorer.frame_manager(_pry_)
|
30
|
+
|
31
|
+
if fm && fm.user[:exception] && fm.user[:inline_exception]
|
32
|
+
_pry_.run_command "exit-all PryExceptionExplorer::CONTINUE_INLINE_EXCEPTION"
|
33
|
+
PryStackExplorer.pop_frame_manager(_pry_)
|
34
|
+
elsif fm && fm.user[:exception] && fm.user[:exception].continuation
|
35
|
+
PryStackExplorer.pop_frame_manager(_pry_)
|
36
|
+
fm.user[:exception].continue
|
37
|
+
else
|
38
|
+
output.puts "No exception to continue!"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -1,9 +1,14 @@
|
|
1
|
-
require '
|
1
|
+
require 'pry-exception_explorer'
|
2
2
|
|
3
3
|
Pry.config.hooks.delete_hook(:when_started, :save_caller_bindings)
|
4
4
|
|
5
|
+
# default is to capture all exceptions that bubble to the top
|
6
|
+
PryExceptionExplorer.intercept { true }
|
7
|
+
|
5
8
|
module PryExceptionExplorer
|
9
|
+
|
6
10
|
def self.wrap
|
11
|
+
self.wrap_active = true
|
7
12
|
yield
|
8
13
|
rescue Exception => ex
|
9
14
|
Pry.config.hooks.add_hook(:when_started, :setup_exception_context) do |binding_stack, _pry_|
|
@@ -12,6 +17,13 @@ module PryExceptionExplorer
|
|
12
17
|
PryStackExplorer.frame_manager(_pry_).user[:exception] = ex
|
13
18
|
end
|
14
19
|
|
15
|
-
|
20
|
+
if ex.should_capture?
|
21
|
+
pry
|
22
|
+
else
|
23
|
+
raise ex
|
24
|
+
end
|
25
|
+
ensure
|
26
|
+
self.wrap_active = false
|
16
27
|
end
|
17
28
|
end
|
29
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module PryExceptionExplorer
|
2
|
+
class LazyFrame
|
3
|
+
|
4
|
+
# we need to jump over a few irrelevant frames to begin with
|
5
|
+
START_FRAME_OFFSET = 5
|
6
|
+
|
7
|
+
def initialize(frame, frame_counter = 0)
|
8
|
+
@frame = frame
|
9
|
+
@frame_counter = frame_counter
|
10
|
+
end
|
11
|
+
|
12
|
+
def raw_frame
|
13
|
+
@frame
|
14
|
+
end
|
15
|
+
|
16
|
+
def klass
|
17
|
+
@frame.eval("self.class")
|
18
|
+
end
|
19
|
+
|
20
|
+
def self
|
21
|
+
@frame.eval("self")
|
22
|
+
end
|
23
|
+
|
24
|
+
def method_name
|
25
|
+
@frame.eval("__method__")
|
26
|
+
end
|
27
|
+
|
28
|
+
def prev
|
29
|
+
LazyFrame.new(binding.of_caller(@frame_counter + START_FRAME_OFFSET), @frame_counter + 1)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -3,22 +3,78 @@
|
|
3
3
|
|
4
4
|
require 'pry-stack_explorer'
|
5
5
|
require "pry-exception_explorer/version"
|
6
|
+
require "pry-exception_explorer/lazy_frame"
|
7
|
+
require "pry-exception_explorer/commands"
|
6
8
|
require "pry"
|
7
9
|
|
8
10
|
if RUBY_VERSION =~ /1.9/
|
9
11
|
require 'continuation'
|
10
12
|
end
|
11
13
|
|
14
|
+
module PryExceptionExplorer
|
15
|
+
CONTINUE_INLINE_EXCEPTION = Object.new
|
16
|
+
|
17
|
+
class << self
|
18
|
+
def wrap_active=(v)
|
19
|
+
Thread.current[:__pry_exception_explorer_wrap__] = v
|
20
|
+
end
|
21
|
+
|
22
|
+
def wrap_active
|
23
|
+
!!Thread.current[:__pry_exception_explorer_wrap__]
|
24
|
+
end
|
25
|
+
|
26
|
+
alias_method :wrap_active?, :wrap_active
|
27
|
+
end
|
28
|
+
|
29
|
+
self.wrap_active = false
|
30
|
+
|
31
|
+
def self.should_capture_exception?(ex)
|
32
|
+
true
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.intercept(&block)
|
36
|
+
Thread.current[:__pry_exception_explorer_intercept_block__] = block
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.intercept_block
|
40
|
+
Thread.current[:__pry_exception_explorer_intercept_block__]
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.should_capture_exception?(ex, frame)
|
44
|
+
if intercept_block
|
45
|
+
intercept_block.call(LazyFrame.new(frame), ex)
|
46
|
+
else
|
47
|
+
false
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.enter_exception_inline(ex)
|
52
|
+
_pry_ = Pry.new
|
53
|
+
|
54
|
+
Pry.initial_session_setup
|
55
|
+
PryStackExplorer.create_and_push_frame_manager(ex.exception_call_stack, _pry_)
|
56
|
+
PryStackExplorer.frame_manager(_pry_).user[:exception] = ex
|
57
|
+
PryStackExplorer.frame_manager(_pry_).user[:inline_exception] = true
|
58
|
+
_pry_.repl(ex.exception_call_stack.first)
|
59
|
+
|
60
|
+
ensure
|
61
|
+
PryStackExplorer.clear_frame_managers(_pry_)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
12
65
|
class Exception
|
13
66
|
NoContinuation = Class.new(StandardError)
|
14
67
|
|
15
68
|
attr_accessor :continuation
|
16
69
|
attr_accessor :exception_call_stack
|
70
|
+
attr_accessor :should_capture
|
17
71
|
|
18
72
|
def continue
|
19
73
|
raise NoContinuation unless continuation.respond_to?(:call)
|
20
74
|
continuation.call
|
21
75
|
end
|
76
|
+
|
77
|
+
alias_method :should_capture?, :should_capture
|
22
78
|
end
|
23
79
|
|
24
80
|
class Object
|
@@ -30,51 +86,31 @@ class Object
|
|
30
86
|
|
31
87
|
ex = exception.exception(string)
|
32
88
|
ex.set_backtrace(array)
|
33
|
-
ex.exception_call_stack = binding.callers.tap(&:shift)
|
34
|
-
|
35
|
-
callcc do |cc|
|
36
|
-
ex.continuation = cc
|
37
|
-
super(ex)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
89
|
|
42
|
-
PryExceptionExplorer
|
90
|
+
if PryExceptionExplorer.should_capture_exception?(ex, binding.of_caller(1))
|
91
|
+
ex.exception_call_stack = binding.callers.tap(&:shift)
|
92
|
+
ex.should_capture = true
|
43
93
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
PryStackExplorer.create_and_push_frame_manager(ex.exception_call_stack, _pry_)
|
48
|
-
PryStackExplorer.frame_manager(_pry_).user[:exception] = ex
|
49
|
-
PryStackExplorer.frame_manager(_pry_).refresh_frame
|
50
|
-
elsif ex
|
51
|
-
output.puts "Current exception can't be entered! (perhaps a C exception)"
|
52
|
-
else
|
53
|
-
output.puts "No exception to enter!"
|
94
|
+
if !PryExceptionExplorer.wrap_active?
|
95
|
+
retval = PryExceptionExplorer.enter_exception_inline(ex)
|
96
|
+
end
|
54
97
|
end
|
55
|
-
end
|
56
98
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
else
|
63
|
-
output.puts "You are not in an exception!"
|
99
|
+
if retval != PryExceptionExplorer::CONTINUE_INLINE_EXCEPTION
|
100
|
+
callcc do |cc|
|
101
|
+
ex.continuation = cc
|
102
|
+
super(ex)
|
103
|
+
end
|
64
104
|
end
|
65
105
|
end
|
106
|
+
end
|
66
107
|
|
67
|
-
command "continue-exception", "Attempt to continue the current exception." do
|
68
|
-
fm = PryStackExplorer.frame_manager(_pry_)
|
69
108
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
else
|
74
|
-
output.puts "No exception to continue!"
|
75
|
-
end
|
76
|
-
end
|
109
|
+
# Let exceptions get caught by Pry REPL loop (i.e dont catch
|
110
|
+
# immediately at point of 'raise')
|
111
|
+
PryExceptionExplorer.wrap_active = true
|
77
112
|
|
78
|
-
|
113
|
+
# default is to capture all exceptions that bubble to the top
|
114
|
+
PryExceptionExplorer.intercept { true }
|
79
115
|
|
80
116
|
Pry.config.commands.import PryExceptionExplorer::Commands
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = "pry-exception_explorer"
|
5
|
+
s.version = "0.1.1pre3"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["John Mair (banisterfiend)"]
|
9
|
+
s.date = "2012-01-05"
|
10
|
+
s.description = "Enter the context of exceptions"
|
11
|
+
s.email = "jrmair@gmail.com"
|
12
|
+
s.files = [".gemtest", ".gitignore", ".travis.yml", ".yardopts", "CHANGELOG", "Gemfile", "LICENSE", "README.md", "Rakefile", "lib/pry-exception_explorer.rb", "lib/pry-exception_explorer/cli.rb", "lib/pry-exception_explorer/commands.rb", "lib/pry-exception_explorer/exception_wrap.rb", "lib/pry-exception_explorer/lazy_frame.rb", "lib/pry-exception_explorer/shim_builder.rb", "lib/pry-exception_explorer/version.rb", "pry-exception_explorer.gemspec", "test/helper.rb", "test/test_exception_explorer.rb", "test/test_exceptions_in_pry.rb", "test/test_wrapped_exceptions.rb"]
|
13
|
+
s.homepage = "https://github.com/banister/pry-exception_explorer"
|
14
|
+
s.require_paths = ["lib"]
|
15
|
+
s.rubygems_version = "1.8.11"
|
16
|
+
s.summary = "Enter the context of exceptions"
|
17
|
+
s.test_files = ["test/helper.rb", "test/test_exception_explorer.rb", "test/test_exceptions_in_pry.rb", "test/test_wrapped_exceptions.rb"]
|
18
|
+
|
19
|
+
if s.respond_to? :specification_version then
|
20
|
+
s.specification_version = 3
|
21
|
+
|
22
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
23
|
+
s.add_runtime_dependency(%q<pry-stack_explorer>, [">= 0"])
|
24
|
+
s.add_development_dependency(%q<bacon>, ["~> 1.1.0"])
|
25
|
+
s.add_development_dependency(%q<rake>, ["~> 0.9"])
|
26
|
+
else
|
27
|
+
s.add_dependency(%q<pry-stack_explorer>, [">= 0"])
|
28
|
+
s.add_dependency(%q<bacon>, ["~> 1.1.0"])
|
29
|
+
s.add_dependency(%q<rake>, ["~> 0.9"])
|
30
|
+
end
|
31
|
+
else
|
32
|
+
s.add_dependency(%q<pry-stack_explorer>, [">= 0"])
|
33
|
+
s.add_dependency(%q<bacon>, ["~> 1.1.0"])
|
34
|
+
s.add_dependency(%q<rake>, ["~> 0.9"])
|
35
|
+
end
|
36
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
unless Object.const_defined? 'PryExceptionExplorer'
|
4
|
+
$:.unshift File.expand_path '../../lib', __FILE__
|
5
|
+
require 'pry-exception_explorer'
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'bacon'
|
9
|
+
|
10
|
+
puts "Testing pry-exception_explorer version #{PryExceptionExplorer::VERSION}..."
|
11
|
+
puts "Ruby version: #{RUBY_VERSION}"
|
12
|
+
|
13
|
+
EE = PryExceptionExplorer
|
14
|
+
|
15
|
+
class Ratty
|
16
|
+
def ratty
|
17
|
+
Weasel.new.weasel
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Weasel
|
22
|
+
def weasel
|
23
|
+
Toad.new.toad
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class Toad
|
28
|
+
def toad
|
29
|
+
raise "toad hall"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class << Pry
|
34
|
+
alias_method :orig_reset_defaults, :reset_defaults
|
35
|
+
def reset_defaults
|
36
|
+
orig_reset_defaults
|
37
|
+
|
38
|
+
Pry.color = false
|
39
|
+
Pry.pager = false
|
40
|
+
Pry.config.should_load_rc = false
|
41
|
+
Pry.config.plugins.enabled = false
|
42
|
+
Pry.config.history.should_load = false
|
43
|
+
Pry.config.history.should_save = false
|
44
|
+
Pry.config.auto_indent = false
|
45
|
+
Pry.config.hooks = Pry::Hooks.new
|
46
|
+
Pry.config.collision_warning = false
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
Pry.reset_defaults
|
51
|
+
|
52
|
+
class InputTester
|
53
|
+
def initialize(*actions)
|
54
|
+
if actions.last.is_a?(Hash) && actions.last.keys == [:history]
|
55
|
+
@hist = actions.pop[:history]
|
56
|
+
end
|
57
|
+
@orig_actions = actions.dup
|
58
|
+
@actions = actions
|
59
|
+
end
|
60
|
+
|
61
|
+
def readline(*)
|
62
|
+
@actions.shift.tap{ |line| @hist << line if @hist }
|
63
|
+
end
|
64
|
+
|
65
|
+
def rewind
|
66
|
+
@actions = @orig_actions.dup
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Set I/O streams.
|
71
|
+
#
|
72
|
+
# Out defaults to an anonymous StringIO.
|
73
|
+
#
|
74
|
+
def redirect_pry_io(new_in, new_out = StringIO.new)
|
75
|
+
old_in = Pry.input
|
76
|
+
old_out = Pry.output
|
77
|
+
|
78
|
+
Pry.input = new_in
|
79
|
+
Pry.output = new_out
|
80
|
+
begin
|
81
|
+
yield
|
82
|
+
ensure
|
83
|
+
Pry.input = old_in
|
84
|
+
Pry.output = old_out
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def mock_pry(*args)
|
89
|
+
|
90
|
+
binding = args.first.is_a?(Binding) ? args.shift : binding()
|
91
|
+
|
92
|
+
input = InputTester.new(*args)
|
93
|
+
output = StringIO.new
|
94
|
+
|
95
|
+
redirect_pry_io(input, output) do
|
96
|
+
binding.pry
|
97
|
+
end
|
98
|
+
|
99
|
+
output.string
|
100
|
+
end
|
101
|
+
|
@@ -0,0 +1,159 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
|
4
|
+
# override enter_exception_inline so we can use it for testing purposes
|
5
|
+
EE.instance_eval do
|
6
|
+
alias original_enter_exception_inline enter_exception_inline
|
7
|
+
end
|
8
|
+
|
9
|
+
def EE.exception_intercepted?
|
10
|
+
@exception_intercepted
|
11
|
+
end
|
12
|
+
|
13
|
+
EE.instance_eval do
|
14
|
+
@exception_intercepted = false
|
15
|
+
end
|
16
|
+
|
17
|
+
def EE.enter_exception_inline(ex)
|
18
|
+
@exception_intercepted = true
|
19
|
+
EE::CONTINUE_INLINE_EXCEPTION
|
20
|
+
end
|
21
|
+
|
22
|
+
prev_wrap_state = PryExceptionExplorer.wrap_active
|
23
|
+
PryExceptionExplorer.wrap_active = false
|
24
|
+
|
25
|
+
describe PryExceptionExplorer do
|
26
|
+
|
27
|
+
before do
|
28
|
+
PryExceptionExplorer.wrap_active = false
|
29
|
+
end
|
30
|
+
|
31
|
+
after do
|
32
|
+
EE.instance_eval do
|
33
|
+
@exception_intercepted = false
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "PryExceptionExplorer.intercept" do
|
38
|
+
describe "class" do
|
39
|
+
describe "first frame" do
|
40
|
+
it "should intercept exception based on first frame's method name" do
|
41
|
+
EE.intercept { |frame, ex| frame.klass == Toad }
|
42
|
+
Ratty.new.ratty
|
43
|
+
EE.exception_intercepted?.should == true
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should NOT intercept exception if method name doesn't match" do
|
47
|
+
EE.intercept { |frame, ex| frame.klass == Ratty }
|
48
|
+
begin
|
49
|
+
Ratty.new.ratty
|
50
|
+
rescue Exception => ex
|
51
|
+
ex.is_a?(RuntimeError).should == true
|
52
|
+
end
|
53
|
+
EE.exception_intercepted?.should == false
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "second frame" do
|
58
|
+
it "should intercept exception based on second frame's method name" do
|
59
|
+
EE.intercept { |frame, ex| frame.prev.klass == Weasel }
|
60
|
+
Ratty.new.ratty
|
61
|
+
EE.exception_intercepted?.should == true
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should NOT intercept exception if method name doesn't match" do
|
65
|
+
EE.intercept { |frame, ex| frame.prev.klass == Toad }
|
66
|
+
begin
|
67
|
+
Ratty.new.ratty
|
68
|
+
rescue Exception => ex
|
69
|
+
ex.is_a?(RuntimeError).should == true
|
70
|
+
end
|
71
|
+
EE.exception_intercepted?.should == false
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "third frame" do
|
76
|
+
it "should intercept exception based on third frame's method name" do
|
77
|
+
EE.intercept { |frame, ex| frame.prev.prev.klass == Ratty }
|
78
|
+
Ratty.new.ratty
|
79
|
+
EE.exception_intercepted?.should == true
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should NOT intercept exception if method name doesn't match" do
|
83
|
+
EE.intercept { |frame, ex| frame.prev.prev.klass == Toad }
|
84
|
+
begin
|
85
|
+
Ratty.new.ratty
|
86
|
+
rescue Exception => ex
|
87
|
+
ex.is_a?(RuntimeError).should == true
|
88
|
+
end
|
89
|
+
EE.exception_intercepted?.should == false
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
describe "method_name" do
|
96
|
+
describe "first frame" do
|
97
|
+
it "should intercept exception based on first frame's method name" do
|
98
|
+
EE.intercept { |frame, ex| frame.method_name == :toad }
|
99
|
+
Ratty.new.ratty
|
100
|
+
EE.exception_intercepted?.should == true
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should NOT intercept exception if method name doesn't match" do
|
104
|
+
EE.intercept { |frame, ex| frame.method_name == :ratty }
|
105
|
+
begin
|
106
|
+
Ratty.new.ratty
|
107
|
+
rescue Exception => ex
|
108
|
+
ex.is_a?(RuntimeError).should == true
|
109
|
+
end
|
110
|
+
EE.exception_intercepted?.should == false
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe "second frame" do
|
115
|
+
it "should intercept exception based on second frame's method name" do
|
116
|
+
EE.intercept { |frame, ex| frame.prev.method_name == :weasel }
|
117
|
+
Ratty.new.ratty
|
118
|
+
EE.exception_intercepted?.should == true
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should NOT intercept exception if method name doesn't match" do
|
122
|
+
EE.intercept { |frame, ex| frame.prev.method_name == :toad }
|
123
|
+
begin
|
124
|
+
Ratty.new.ratty
|
125
|
+
rescue Exception => ex
|
126
|
+
ex.is_a?(RuntimeError).should == true
|
127
|
+
end
|
128
|
+
EE.exception_intercepted?.should == false
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
describe "third frame" do
|
133
|
+
it "should intercept exception based on third frame's method name" do
|
134
|
+
EE.intercept { |frame, ex| frame.prev.prev.method_name == :ratty }
|
135
|
+
Ratty.new.ratty
|
136
|
+
EE.exception_intercepted?.should == true
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should NOT intercept exception if method name doesn't match" do
|
140
|
+
EE.intercept { |frame, ex| frame.prev.prev.method_name == :toad }
|
141
|
+
begin
|
142
|
+
Ratty.new.ratty
|
143
|
+
rescue Exception => ex
|
144
|
+
ex.is_a?(RuntimeError).should == true
|
145
|
+
end
|
146
|
+
EE.exception_intercepted?.should == false
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
EE.instance_eval do
|
156
|
+
alias enter_exception_inline original_enter_exception_inline
|
157
|
+
end
|
158
|
+
|
159
|
+
PryExceptionExplorer.wrap_active = prev_wrap_state
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe PryExceptionExplorer do
|
4
|
+
|
5
|
+
describe "Exceptions caught by Pry" do
|
6
|
+
describe "enter-exception" do
|
7
|
+
it "should be able to enter an exception caught by pry" do
|
8
|
+
|
9
|
+
PryExceptionExplorer.intercept { true }
|
10
|
+
|
11
|
+
# there are 3 types of situations where exception_explorer is invoked:
|
12
|
+
# 1. when 'wrap' is used, i.e only exceptions that bubble to
|
13
|
+
# the top are intercepted.
|
14
|
+
# 2. when exceptions are intercepted 'inline' (i.e dropped
|
15
|
+
# into pry directly from `raise` itself)
|
16
|
+
# 3. exceptions are caught by pry and entered into by using
|
17
|
+
# the 'enter-exception' command
|
18
|
+
# The case of 1. and 3. are actually very similar, but in
|
19
|
+
# 3. the exception never bubbles to the top as it's caught by
|
20
|
+
# pry instead; also in 3. a pry session is not started
|
21
|
+
# automatically, the user must explicitly type
|
22
|
+
# `enter-exception` to start the session.
|
23
|
+
#
|
24
|
+
# This test is for type 3.
|
25
|
+
mock_pry("Ratty.new.ratty", "enter-exception", "show-stack", "exit").should =~ /toad.*?weasel.*?ratty/m
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
require 'pry-exception_explorer/exception_wrap'
|
4
|
+
|
5
|
+
CaughtException = Class.new(StandardError)
|
6
|
+
UncaughtException = Class.new(StandardError)
|
7
|
+
|
8
|
+
describe PryExceptionExplorer do
|
9
|
+
|
10
|
+
before do
|
11
|
+
Pry.config.input = StringIO.new("exit :caught\n")
|
12
|
+
Pry.config.output = StringIO.new
|
13
|
+
end
|
14
|
+
|
15
|
+
after do
|
16
|
+
Pry.config.hooks.clear(:when_started)
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "PryExceptionExplorer.wrap" do
|
20
|
+
|
21
|
+
it 'should default to capturing ALL exceptions' do
|
22
|
+
PryExceptionExplorer.wrap do
|
23
|
+
raise CaughtException, "catch me if u can"
|
24
|
+
end.should == :caught
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should NOT capture rescued exceptions' do
|
28
|
+
o = Object.new
|
29
|
+
def o.evil_fish
|
30
|
+
Ratty.new.ratty
|
31
|
+
rescue Exception
|
32
|
+
end
|
33
|
+
|
34
|
+
PryExceptionExplorer.intercept { true }
|
35
|
+
|
36
|
+
PryExceptionExplorer.wrap do
|
37
|
+
o.evil_fish
|
38
|
+
end.should.not == :caught
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should have the full callstack attached to exception' do
|
42
|
+
PryExceptionExplorer.intercept { |frame, ex| frame.method_name == :toad }
|
43
|
+
|
44
|
+
PryExceptionExplorer.wrap do
|
45
|
+
begin
|
46
|
+
Ratty.new.ratty
|
47
|
+
rescue Exception => ex
|
48
|
+
ex.exception_call_stack[0..2].map { |b| b.eval("__method__") }.should == [:toad, :weasel, :ratty]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should NOT have callstack attached if exception not matched' do
|
54
|
+
PryExceptionExplorer.intercept { |frame, ex| false }
|
55
|
+
|
56
|
+
begin
|
57
|
+
PryExceptionExplorer.wrap do
|
58
|
+
raise UncaughtException, "Catch me if you can't.."
|
59
|
+
end
|
60
|
+
rescue UncaughtException => ex
|
61
|
+
ex.exception_call_stack.should == nil
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "PryExceptionExplorer.intercept with wrapped exceptions" do
|
66
|
+
describe "klass" do
|
67
|
+
describe "first frame" do
|
68
|
+
it 'should catch a matched exception based on klass' do
|
69
|
+
PryExceptionExplorer.intercept { |frame, ex| frame.klass == Toad }
|
70
|
+
|
71
|
+
PryExceptionExplorer.wrap do
|
72
|
+
Ratty.new.ratty
|
73
|
+
end.should == :caught
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'should NOT catch an unmatched exception' do
|
77
|
+
PryExceptionExplorer.intercept { |frame, ex| frame.klass == Weasel }
|
78
|
+
|
79
|
+
begin
|
80
|
+
PryExceptionExplorer.wrap do
|
81
|
+
raise UncaughtException, "Catch me if you can't.."
|
82
|
+
end
|
83
|
+
rescue Exception => ex
|
84
|
+
ex.is_a?(UncaughtException).should == true
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "third frame" do
|
90
|
+
it 'should catch a matched exception' do
|
91
|
+
PryExceptionExplorer.intercept { |frame, ex| frame.prev.prev.klass == Ratty }
|
92
|
+
|
93
|
+
PryExceptionExplorer.wrap do
|
94
|
+
Ratty.new.ratty
|
95
|
+
end.should == :caught
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'should NOT catch an unmatched exception' do
|
99
|
+
PryExceptionExplorer.intercept { |frame, ex| frame.prev.prev.klass == Weasel }
|
100
|
+
|
101
|
+
begin
|
102
|
+
PryExceptionExplorer.wrap do
|
103
|
+
raise UncaughtException, "Catch me if you can't.."
|
104
|
+
end
|
105
|
+
rescue Exception => ex
|
106
|
+
ex.is_a?(UncaughtException).should == true
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe "method_name" do
|
113
|
+
describe "first frame" do
|
114
|
+
it 'should catch a matched exception' do
|
115
|
+
PryExceptionExplorer.intercept { |frame, ex| frame.method_name == :toad }
|
116
|
+
|
117
|
+
PryExceptionExplorer.wrap do
|
118
|
+
Ratty.new.ratty
|
119
|
+
end.should == :caught
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'should NOT catch an unmatched exception' do
|
123
|
+
PryExceptionExplorer.intercept { |frame, ex| frame.method_name == :weasel }
|
124
|
+
|
125
|
+
begin
|
126
|
+
PryExceptionExplorer.wrap do
|
127
|
+
raise UncaughtException, "Catch me if you can't.."
|
128
|
+
end
|
129
|
+
rescue Exception => ex
|
130
|
+
ex.is_a?(UncaughtException).should == true
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
describe "third frame" do
|
136
|
+
it 'should catch a matched exception' do
|
137
|
+
PryExceptionExplorer.intercept { |frame, ex| frame.prev.prev.method_name == :ratty }
|
138
|
+
|
139
|
+
PryExceptionExplorer.wrap do
|
140
|
+
Ratty.new.ratty
|
141
|
+
end.should == :caught
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'should NOT catch an unmatched exception' do
|
145
|
+
PryExceptionExplorer.intercept { |frame, ex| frame.prev.prev.method_name == :weasel }
|
146
|
+
|
147
|
+
begin
|
148
|
+
PryExceptionExplorer.wrap do
|
149
|
+
raise UncaughtException, "Catch me if you can't.."
|
150
|
+
end
|
151
|
+
rescue Exception => ex
|
152
|
+
ex.is_a?(UncaughtException).should == true
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: pry-exception_explorer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease: 5
|
5
|
-
version: 0.1.
|
5
|
+
version: 0.1.1pre3
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- John Mair (banisterfiend)
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date:
|
13
|
+
date: 2012-01-05 00:00:00 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: pry-stack_explorer
|
@@ -23,7 +23,29 @@ dependencies:
|
|
23
23
|
version: "0"
|
24
24
|
type: :runtime
|
25
25
|
version_requirements: *id001
|
26
|
-
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: bacon
|
28
|
+
prerelease: false
|
29
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
30
|
+
none: false
|
31
|
+
requirements:
|
32
|
+
- - ~>
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 1.1.0
|
35
|
+
type: :development
|
36
|
+
version_requirements: *id002
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: rake
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: "0.9"
|
46
|
+
type: :development
|
47
|
+
version_requirements: *id003
|
48
|
+
description: Enter the context of exceptions
|
27
49
|
email: jrmair@gmail.com
|
28
50
|
executables: []
|
29
51
|
|
@@ -32,15 +54,27 @@ extensions: []
|
|
32
54
|
extra_rdoc_files: []
|
33
55
|
|
34
56
|
files:
|
57
|
+
- .gemtest
|
58
|
+
- .gitignore
|
59
|
+
- .travis.yml
|
60
|
+
- .yardopts
|
61
|
+
- CHANGELOG
|
62
|
+
- Gemfile
|
63
|
+
- LICENSE
|
64
|
+
- README.md
|
65
|
+
- Rakefile
|
66
|
+
- lib/pry-exception_explorer.rb
|
35
67
|
- lib/pry-exception_explorer/cli.rb
|
68
|
+
- lib/pry-exception_explorer/commands.rb
|
36
69
|
- lib/pry-exception_explorer/exception_wrap.rb
|
70
|
+
- lib/pry-exception_explorer/lazy_frame.rb
|
37
71
|
- lib/pry-exception_explorer/shim_builder.rb
|
38
72
|
- lib/pry-exception_explorer/version.rb
|
39
|
-
-
|
40
|
-
- test/
|
41
|
-
-
|
42
|
-
-
|
43
|
-
-
|
73
|
+
- pry-exception_explorer.gemspec
|
74
|
+
- test/helper.rb
|
75
|
+
- test/test_exception_explorer.rb
|
76
|
+
- test/test_exceptions_in_pry.rb
|
77
|
+
- test/test_wrapped_exceptions.rb
|
44
78
|
homepage: https://github.com/banister/pry-exception_explorer
|
45
79
|
licenses: []
|
46
80
|
|
@@ -67,6 +101,9 @@ rubyforge_project:
|
|
67
101
|
rubygems_version: 1.8.11
|
68
102
|
signing_key:
|
69
103
|
specification_version: 3
|
70
|
-
summary:
|
71
|
-
test_files:
|
72
|
-
|
104
|
+
summary: Enter the context of exceptions
|
105
|
+
test_files:
|
106
|
+
- test/helper.rb
|
107
|
+
- test/test_exception_explorer.rb
|
108
|
+
- test/test_exceptions_in_pry.rb
|
109
|
+
- test/test_wrapped_exceptions.rb
|
data/test/test.rb
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
direc = File.dirname(__FILE__)
|
2
|
-
|
3
|
-
require 'rubygems'
|
4
|
-
require "#{direc}/../lib/pry-exception_explorer"
|
5
|
-
require 'bacon'
|
6
|
-
|
7
|
-
puts "Testing pry-exception_explorer version #{PryExceptionExplorer::VERSION}..."
|
8
|
-
puts "Ruby version: #{RUBY_VERSION}"
|
9
|
-
|
10
|
-
describe PryExceptionExplorer do
|
11
|
-
end
|
12
|
-
|