pry-rescue 0.3

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,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,133 @@
1
+
2
+ **pry-rescue** helps you quickly figure out why your code broke; when an exception is raised that would normally kill your program, Pry comes to the rescue, opening a Pry session in the context of code that raised the exception.
3
+
4
+ Installation
5
+ ============
6
+
7
+ Either `gem install pry-rescue`, or add it to the development section of your Gemfile:
8
+
9
+ ```ruby
10
+ source :rubygems
11
+ group :development do
12
+ gem 'pry-rescue'
13
+ gem 'pry-stack_explorer' # if you're using MRI 1.9 and you want it to be awesome.
14
+ end
15
+ ```
16
+
17
+ Usage
18
+ =====
19
+
20
+ There are *two ways* to use pry-rescue:
21
+
22
+ Wrap an entire script
23
+ ---------------------
24
+
25
+ Use the launcher script:
26
+
27
+ ```
28
+ rescue <script.rb> [arguments..]
29
+ ```
30
+
31
+ Wrap a block in your code
32
+ -------------------------
33
+ In development, wrap your code in `Pry::rescue{ }`; then any exceptions that are raised
34
+ but not rescued will open a pry session. This is particularly useful for debugging
35
+ servers and other long-running processes.
36
+
37
+ ```ruby
38
+ require 'pry-rescue'
39
+
40
+ def test
41
+ raise "foo"
42
+ rescue => e
43
+ raise "bar"
44
+ end
45
+
46
+ Pry.rescue do
47
+ test
48
+ end
49
+ ```
50
+
51
+ This will land you in a pry-session:
52
+
53
+ ```
54
+ From: examples/example.rb @ line 4 Object#test:
55
+
56
+ 4: def test
57
+ 5: raise "foo"
58
+ 6: rescue => e
59
+ => 7: raise "bar"
60
+ 8: end
61
+
62
+ RuntimeError: bar
63
+ from examples/example.rb:7:in `rescue in test'
64
+ [1] pry(main)>
65
+ ```
66
+
67
+ cd-cause
68
+ ========
69
+
70
+ If you need to find the reason that the exception happened, you can use the `cd-cause`
71
+ command:
72
+
73
+ ```
74
+ [1] pry(main)> cd-cause
75
+ From: examples/example.rb @ line 4 Object#test:
76
+
77
+ 4: def test
78
+ => 5: raise "foo"
79
+ 6: rescue => e
80
+ 7: raise "bar"
81
+ 8: end
82
+
83
+ RuntimeError: foo
84
+ from examples/example.rb:5:in `test'
85
+ [1] pry(main)>
86
+ ```
87
+
88
+ To get back from `cd-cause` you can either type `<ctrl+d>` or `cd ..`.
89
+
90
+ try-again
91
+ =========
92
+
93
+ Once you've used Pry's `edit` or `edit-method` commands to fix your code, you can issue a
94
+ `try-again` command to re-run your code. (Either from the start in the case of using the
95
+ `rescue` script, or from the block if you're using that API).
96
+
97
+ ```
98
+ [1] pry(main)> edit-method
99
+ [2] pry(main)> whereami
100
+ From: examples/example.rb @ line 4 Object#test:
101
+
102
+ 4: def test
103
+ => 5: puts "foo"
104
+ 6: rescue => e
105
+ 7: raise "bar"
106
+ 8: end
107
+ [3] pry(main)> try-again
108
+ foo
109
+ ```
110
+
111
+ pry-stack explorer
112
+ ==================
113
+
114
+ If you're running rubinius, or ruby-1.9, then you can use `pry-rescue` alongside
115
+ `pry-stack_explorer`. This gives you the ability to move `up` or `down` the stack so that
116
+ you can get a better idea of why your function ended up in a bad state. Run
117
+ [example2.rb](https://github.com/ConradIrwin/pry-rescue/blob/master/examples/example2.rb) to get a feel for what this is like.
118
+
119
+ Known bugs
120
+ ==========
121
+
122
+ Occasionally, when using ruby-1.8 or jruby, the value for `self` will be incorrect. You
123
+ will still be able to access local variables, but calling methods will not work as you
124
+ expect.
125
+
126
+ On rbx we are unable to intercept some exceptions thrown from inside the C++ VM, for
127
+ example the ZeroDivisionError in `1 / 0`.
128
+
129
+ Meta-fu
130
+ =======
131
+
132
+ Released under the MIT license, see LICENSE.MIT for details. Contributions and bug-reports
133
+ are welcome.
@@ -0,0 +1,22 @@
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
+ task :build do
17
+ sh 'gem build *.gemspec'
18
+ end
19
+
20
+ task :install => :build do
21
+ sh 'gem install *.gem'
22
+ end
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ USAGE = %{
4
+ rescue (pry-rescue wrapper)
5
+
6
+ Usage:
7
+ rescue <script.rb> [arguments...]
8
+
9
+ What it does:
10
+ Runs <script.rb>, and if an uncaught exception is raised,
11
+ pry will come to the rescue, giving you a pry prompt in the
12
+ context where the exception was raised.
13
+
14
+ You can then poke around to figure out why your code broke!
15
+
16
+ (Not yet available: fixing the problem and continuing your program.)
17
+
18
+ }
19
+
20
+ if script = ARGV.shift
21
+ if File.exists? script
22
+ require 'pry-rescue'
23
+ begin; require 'pry-stack_explorer'; rescue LoadError; end
24
+
25
+ $0 = File.expand_path script
26
+ Pry.rescue { load script }
27
+ else
28
+ $stderr.puts "Error: #{script.inspect} not found."
29
+ end
30
+ else
31
+ puts USAGE
32
+ end
@@ -0,0 +1,21 @@
1
+ $:.unshift File.expand_path '../../lib', __FILE__
2
+ require 'pry-rescue'
3
+
4
+ Pry.rescue 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-rescue'
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.rescue 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-rescue/core_ext', __FILE__)
6
+ require File.expand_path('../pry-rescue/commands', __FILE__)
7
+
8
+ begin
9
+ require 'pry-stack_explorer'
10
+ rescue LoadError
11
+ end
12
+
13
+ class PryRescue
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-rescue'
@@ -0,0 +1,65 @@
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::rescue{}" unless raised
36
+ raised.pop
37
+
38
+ if raised.any?
39
+ PryRescue.enter_exception_context(raised)
40
+ else
41
+ raise Pry::CommandError, "No previous exception detected"
42
+ end
43
+ end
44
+ end
45
+
46
+ Pry::Commands.create_command "try-again", "Re-try the code that caused this exception" do
47
+
48
+ banner <<-BANNER
49
+ Usage: try-again
50
+
51
+ Runs the code wrapped by Pry::rescue{ } again.
52
+
53
+ This is useful if you've used `edit` or `edit-method` to fix the problem
54
+ that caused this exception to be raised and you want a quick way to test
55
+ your changes.
56
+
57
+ NOTE: try-again may cause confusing results if the code that's run have
58
+ side-effects (like deleting rows from a database) as it will try to do that
59
+ again, which may not work.
60
+ BANNER
61
+
62
+ def process
63
+ run "exit", ":try_again"
64
+ end
65
+ end
@@ -0,0 +1,30 @@
1
+ class Pry
2
+
3
+ # Start a pry session on any unhandled exceptions within this block.
4
+ #
5
+ # @example
6
+ # Pry::rescue do
7
+ # raise "foo"
8
+ # end
9
+ #
10
+ # @return [Object] The return value of the block
11
+ def self.rescue(&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
+ rescue Exception => e
23
+ case PryRescue.enter_exception_context(raised)
24
+ when :try_again
25
+ retry
26
+ else
27
+ raise
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,14 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'pry-rescue'
3
+ s.version = '0.3'
4
+ s.summary = 'Open a pry session on any unhandled exceptions'
5
+ s.description = 'Allows you to wrap code in Pry::rescue{ } to open a pry session at any unhandled exceptions'
6
+ s.homepage = 'https://github.com/ConradIrwin/pry-rescue'
7
+ s.email = ['conrad.irwin@gmail.com', 'jrmair@gmail.com', 'chris@ill-logic.com']
8
+ s.authors = ['Conrad Irwin', 'banisterfiend', 'epitron']
9
+ s.files = `git ls-files`.split("\n")
10
+ s.require_paths = ['lib']
11
+ s.executables = ['rescue']
12
+
13
+ s.add_dependency 'interception'
14
+ end
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pry-rescue
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.3'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Conrad Irwin
9
+ - banisterfiend
10
+ - epitron
11
+ autorequire:
12
+ bindir: bin
13
+ cert_chain: []
14
+ date: 2012-08-15 00:00:00.000000000 Z
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: interception
18
+ requirement: !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ! '>='
22
+ - !ruby/object:Gem::Version
23
+ version: '0'
24
+ type: :runtime
25
+ prerelease: false
26
+ version_requirements: !ruby/object:Gem::Requirement
27
+ none: false
28
+ requirements:
29
+ - - ! '>='
30
+ - !ruby/object:Gem::Version
31
+ version: '0'
32
+ description: Allows you to wrap code in Pry::rescue{ } to open a pry session at any
33
+ unhandled exceptions
34
+ email:
35
+ - conrad.irwin@gmail.com
36
+ - jrmair@gmail.com
37
+ - chris@ill-logic.com
38
+ executables:
39
+ - rescue
40
+ extensions: []
41
+ extra_rdoc_files: []
42
+ files:
43
+ - LICENSE.MIT
44
+ - README.md
45
+ - Rakefile
46
+ - bin/rescue
47
+ - examples/example.rb
48
+ - examples/example2.rb
49
+ - lib/pry-rescue.rb
50
+ - lib/pry-rescue/cli.rb
51
+ - lib/pry-rescue/commands.rb
52
+ - lib/pry-rescue/core_ext.rb
53
+ - pry-rescue.gemspec
54
+ homepage: https://github.com/ConradIrwin/pry-rescue
55
+ licenses: []
56
+ post_install_message:
57
+ rdoc_options: []
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ! '>='
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ requirements: []
73
+ rubyforge_project:
74
+ rubygems_version: 1.8.24
75
+ signing_key:
76
+ specification_version: 3
77
+ summary: Open a pry session on any unhandled exceptions
78
+ test_files: []
79
+ has_rdoc: