pry-rescue 0.3

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,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: