pry-capture 0.1.pre.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2012 Conrad Irwin <conrad.irwin@gmail.com>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -0,0 +1,94 @@
1
+ pry-capture allows you to start a Pry session on any unhandled exceptions in your code.
2
+
3
+
4
+ Installation
5
+ ============
6
+ Either `gem install pry-capture`, or add it to the development section of your Gemfile:
7
+
8
+ ```ruby
9
+ source :rubygems
10
+ group :development do
11
+ gem 'pry-capture'
12
+ gem 'pry-stack_explorer' # if you're using MRI 1.9 and you want it to be awesome.
13
+ end
14
+ ```
15
+
16
+ Usage
17
+ =====
18
+
19
+ In development, wrap your code in `Pry::capture{ }`; then any exceptions that are raised
20
+ but not rescued will open a pry session.
21
+
22
+ ```ruby
23
+ require 'pry-capture'
24
+
25
+ def test
26
+ raise "foo"
27
+ rescue => e
28
+ raise "bar"
29
+ end
30
+
31
+ Pry.capture do
32
+ test
33
+ end
34
+ ```
35
+
36
+ This will land you in a pry-session:
37
+
38
+ ```
39
+ From: examples/example.rb @ line 4 Object#test:
40
+
41
+ 4: def test
42
+ 5: raise "foo"
43
+ 6: rescue => e
44
+ => 7: raise "bar"
45
+ 8: end
46
+
47
+ RuntimeError: bar
48
+ from examples/example.rb:7:in `rescue in test'
49
+ [1] pry(main)>
50
+ ```
51
+
52
+ If you need to find the reason that the exception happened, you can use the `cd-cause`
53
+ command:
54
+
55
+ ```
56
+ [1] pry(main)> cd-cause
57
+ From: examples/example.rb @ line 4 Object#test:
58
+
59
+ 4: def test
60
+ => 5: raise "foo"
61
+ 6: rescue => e
62
+ 7: raise "bar"
63
+ 8: end
64
+
65
+ RuntimeError: foo
66
+ from examples/example.rb:5:in `test'
67
+ [1] pry(main)>
68
+ ```
69
+
70
+ To get back from `cd-cause` you can either type `<ctrl+d>` or `cd ..`.
71
+
72
+ pry-stack explorer
73
+ ==================
74
+
75
+ If you're running rubinius, or ruby-1.9, then you can use `pry-capture` alongside
76
+ `pry-stack_explorer`. This gives you the ability to move `up` or `down the stack so that
77
+ you can get a better idea of why your function ended up in a bad state. See
78
+ example2.rb](https://github.com/ConradIrwin/pry-capture/blob/master/examples/example2.rb) to get a feel for what this is like.
79
+
80
+ Known bugs
81
+ ==========
82
+
83
+ Occasionally, when using ruby-1.8 or jruby, the value for `self` will be incorrect. You
84
+ will still be able to access local variables, but calling methods will not work as you
85
+ expect.
86
+
87
+ On rbx we are unable to intercept some exceptions thrown from inside the C++ VM, for
88
+ example the ZeroDivisionError in `1 / 0`.
89
+
90
+ Meta-fu
91
+ =======
92
+
93
+ Released under the MIT license, see LICENSE.MIT for details. Contributions and bug-reports
94
+ are welcome.
@@ -0,0 +1,16 @@
1
+ desc "Run example"
2
+ task :example do
3
+ sh "ruby -I./lib/ ./examples/example.rb "
4
+ end
5
+
6
+ desc "Run example 2"
7
+ task :example2 do
8
+ sh "ruby -I./lib/ ./examples/example2.rb "
9
+ end
10
+
11
+ desc "Run tests"
12
+ task :test do
13
+ sh 'rspec spec -r ./spec/spec_helpers.rb'
14
+ end
15
+
16
+
@@ -0,0 +1,21 @@
1
+ $:.unshift File.expand_path '../../lib', __FILE__
2
+ require 'pry-capture'
3
+
4
+ Pry.capture do
5
+
6
+ def a
7
+ begin
8
+ begin
9
+ raise "foo"
10
+
11
+ rescue => e
12
+ raise "bar"
13
+ end
14
+
15
+ rescue => e
16
+ 1 / 0
17
+
18
+ end
19
+ end
20
+ a
21
+ end
@@ -0,0 +1,20 @@
1
+ $:.unshift File.expand_path '../../lib', __FILE__
2
+ require 'pry-capture'
3
+
4
+ def alpha
5
+ x = 1
6
+ beta
7
+ end
8
+
9
+ def beta
10
+ y = 30
11
+ gamma(1, 2)
12
+ end
13
+
14
+ def gamma(x)
15
+ greeting = x
16
+ end
17
+
18
+ Pry.capture do
19
+ alpha
20
+ end
@@ -0,0 +1,54 @@
1
+ require 'rubygems'
2
+ require 'interception'
3
+ require 'pry'
4
+
5
+ require File.expand_path('../pry-capture/core_ext', __FILE__)
6
+ require File.expand_path('../pry-capture/commands', __FILE__)
7
+
8
+ begin
9
+ require 'pry-stack_explorer'
10
+ rescue LoadError
11
+ end
12
+
13
+ class PryCapture
14
+ class << self
15
+
16
+ # Start a Pry session in the context of the exception.
17
+ # @param [Exception] exception The exception.
18
+ # @param [Array<Binding>] bindings The call stack.
19
+ def enter_exception_context(raised)
20
+ exception, bindings = raised.last
21
+
22
+ prune_call_stack!(bindings)
23
+
24
+ if defined?(PryStackExplorer)
25
+ pry :call_stack => bindings, :hooks => pry_hooks(exception, raised)
26
+ else
27
+ bindings.first.pry :hooks => pry_hooks(exception, raised)
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ # Define the :before_session hook for the Pry instance.
34
+ # This ensures that the `_ex_` and `_raised_` sticky locals are
35
+ # properly set.
36
+ def pry_hooks(ex, raised)
37
+ hooks = Pry.config.hooks.dup
38
+ hooks.add_hook(:before_session, :save_captured_exception) do |_, _, _pry_|
39
+ _pry_.last_exception = ex
40
+ _pry_.backtrace = ex.backtrace
41
+ _pry_.sticky_locals.merge!({ :_raised_ => raised })
42
+ _pry_.exception_handler.call(_pry_.output, ex, _pry_)
43
+ end
44
+
45
+ hooks
46
+ end
47
+
48
+ # Sanitize the call stack.
49
+ # @param [Array<Binding>] bindings The call stack.
50
+ def prune_call_stack!(bindings)
51
+ bindings.delete_if { |b| [Pry, Interception].include?(b.eval("self")) }
52
+ end
53
+ end
54
+ end
@@ -0,0 +1 @@
1
+ require 'pry-capture'
@@ -0,0 +1,44 @@
1
+ Pry::Commands.create_command "cd-cause", "Move to the previously raised exception" do
2
+
3
+ banner <<-BANNER
4
+ Usage: cd-cause
5
+
6
+ Starts a new pry session at the previously raised exception.
7
+
8
+ This is useful if you've caught one exception, and raised another,
9
+ if you need to find out why the original was raised.
10
+
11
+ @example
12
+ 5. def foo
13
+ 6. raise "one"
14
+ 7. rescue
15
+ 8. => raise "two"
16
+ 9. end
17
+
18
+ pry> cd-cause
19
+
20
+ 5. def foo
21
+ 6. => raise "one"
22
+ 7. rescue
23
+ 8. raise "two"
24
+ 9. end
25
+
26
+ Once you have finished with the internal exception type <ctrl+d> or cd .. to
27
+ return to where you were.
28
+
29
+ If you have many layers of exceptions that are rescued and then re-raised, you
30
+ can repeat cd-cause as many times as you need.
31
+ BANNER
32
+
33
+ def process
34
+ raised = target.eval("_raised_ rescue nil")
35
+ raise Pry::CommandError, "cd-cause only works in a pry session created by Pry::capture{}" unless raised
36
+ raised.pop
37
+
38
+ if raised.any?
39
+ PryCapture.enter_exception_context(raised)
40
+ else
41
+ raise Pry::CommandError, "No previous exception detected"
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,27 @@
1
+ class Pry
2
+
3
+ # Start a pry session on any unhandled exceptions within this block.
4
+ #
5
+ # @example
6
+ # Pry::capture do
7
+ # raise "foo"
8
+ # end
9
+ #
10
+ # @return [Object] The return value of the block
11
+ def self.capture(&block)
12
+ raised = []
13
+
14
+ Interception.listen(block) do |exception, binding|
15
+ if defined?(PryStackExplorer)
16
+ raised << [exception, binding.callers]
17
+ else
18
+ raised << [exception, Array(binding)]
19
+ end
20
+ end
21
+
22
+ ensure
23
+ if raised.any?
24
+ PryCapture.enter_exception_context(raised)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,16 @@
1
+ # For packaging Octokey, please use "rake gems; rake pushgems".
2
+ # This gemspec will only generate the correct gem for the current platform.
3
+ Gem::Specification.new do |s|
4
+
5
+ s.name = 'pry-capture'
6
+ s.version = '0.1.pre.1'
7
+ s.summary = 'Open a pry session on any unhandled exceptions'
8
+ s.description = 'Allows you to wrap code in Pry::capture{ } to open a pry session at any unhandled exceptions'
9
+ s.homepage = 'https://github.com/ConradIrwin/pry-capture'
10
+ s.email = ['conrad.irwin@gmail.com', 'jrmair@gmail.com']
11
+ s.authors = ['Conrad Irwin', 'banisterfiend']
12
+ s.files = `git ls-files`.split("\n")
13
+ s.require_paths = ["lib"]
14
+
15
+ s.add_dependency 'pry-stack_explorer'
16
+ end
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pry-capture
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.pre.1
5
+ prerelease: 4
6
+ platform: ruby
7
+ authors:
8
+ - Conrad Irwin
9
+ - banisterfiend
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2012-08-12 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: pry-stack_explorer
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ! '>='
29
+ - !ruby/object:Gem::Version
30
+ version: '0'
31
+ description: Allows you to wrap code in Pry::capture{ } to open a pry session at any
32
+ unhandled exceptions
33
+ email:
34
+ - conrad.irwin@gmail.com
35
+ - jrmair@gmail.com
36
+ executables: []
37
+ extensions: []
38
+ extra_rdoc_files: []
39
+ files:
40
+ - LICENSE.MIT
41
+ - README.md
42
+ - Rakefile
43
+ - examples/example.rb
44
+ - examples/example2.rb
45
+ - lib/pry-capture.rb
46
+ - lib/pry-capture/cli.rb
47
+ - lib/pry-capture/commands.rb
48
+ - lib/pry-capture/core_ext.rb
49
+ - pry-capture.gemspec
50
+ homepage: https://github.com/ConradIrwin/pry-capture
51
+ licenses: []
52
+ post_install_message:
53
+ rdoc_options: []
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ! '>'
66
+ - !ruby/object:Gem::Version
67
+ version: 1.3.1
68
+ requirements: []
69
+ rubyforge_project:
70
+ rubygems_version: 1.8.24
71
+ signing_key:
72
+ specification_version: 3
73
+ summary: Open a pry session on any unhandled exceptions
74
+ test_files: []
75
+ has_rdoc: