Permalink
Browse files

Initial implementation

  • Loading branch information...
0 parents commit 331e6621ba85903702d2c77b696ba5c7b78f18c1 @nixme committed Jun 7, 2012
Showing with 256 additions and 0 deletions.
  1. +17 −0 .gitignore
  2. +3 −0 CHANGELOG.md
  3. +3 −0 Gemfile
  4. +20 −0 LICENSE
  5. +44 −0 README.md
  6. +2 −0 Rakefile
  7. +17 −0 lib/pry-debugger.rb
  8. +1 −0 lib/pry-debugger/cli.rb
  9. +39 −0 lib/pry-debugger/commands.rb
  10. +64 −0 lib/pry-debugger/processor.rb
  11. +19 −0 lib/pry-debugger/pry_ext.rb
  12. +3 −0 lib/pry-debugger/version.rb
  13. +24 −0 pry-debugger.gemspec
@@ -0,0 +1,17 @@
+*.gem
+*.rbc
+.bundle
+.config
+.yardoc
+Gemfile.lock
+InstalledFiles
+_yardoc
+coverage
+doc/
+lib/bundler/man
+pkg
+rdoc
+spec/reports
+test/tmp
+test/version_tmp
+tmp
@@ -0,0 +1,3 @@
+## 0.0.1 (2012-06-07)
+
+* First release. **step**, **next**, and **continue** commands.
@@ -0,0 +1,3 @@
+source 'http://rubygems.org'
+
+gemspec
20 LICENSE
@@ -0,0 +1,20 @@
+MIT/Expat License
+
+Copyright (c) 2012 by Gopal Patel
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,44 @@
+pry-debugger
+============
+
+_Fast execution control in Pry_
+
+Adds **step**, **next**, and **continue** commands to [Pry][pry] using
+[debugger][debugger].
+
+To use, invoke pry normally:
+
+```ruby
+def some_method
+ binding.pry # Execution will stop here.
+ puts 'Hello World' # Run 'step' or 'next' in the console to move here.
+end
+```
+
+**pry-debugger** is not yet thread-safe, so only use in single-threaded
+environments.
+
+Only supports MRI 1.9.2 and 1.9.3. For a pure-ruby approach not reliant on
+[debugger][debugger], check out [pry-nav][pry-nav]. Note: *pry-nav* and
+*pry-debugger* cannot be loaded together.
+
+Stepping through code often? Add the following shortcuts to `~/.pryrc`:
+
+```ruby
+Pry.commands.alias_command 'c', 'continue'
+Pry.commands.alias_command 's', 'step'
+Pry.commands.alias_command 'n', 'next'
+```
+
+## Contributions
+
+Patches and bug reports are welcome. Just send a [pull request][pullrequests] or
+file an [issue][issues]. [Project changelog][changelog].
+
+
+[pry]: http://pry.github.com
+[debugger]: https://github.com/cldwalker/debugger
+[pry-nav]: https://github.com/nixme/pry-nav
+[pullrequests]: https://github.com/nixme/pry-debugger/pulls
+[issues]: https://github.com/nixme/pry-debugger/issues
+[changelog]: https://github.com/nixme/pry-debugger/blob/master/CHANGELOG.md
@@ -0,0 +1,2 @@
+#!/usr/bin/env rake
+require "bundler/gem_tasks"
@@ -0,0 +1,17 @@
+require 'pry-debugger/version'
+require 'pry-debugger/pry_ext'
+require 'pry-debugger/commands'
+require 'pry-debugger/processor'
+
+module PryDebugger
+ TRACE_IGNORE_FILES = Dir[File.join(File.dirname(__FILE__), '**', '*.rb')].map { |f| File.expand_path(f) }
+
+ extend self
+
+ # Checks that a binding is in a local file context. Extracted from
+ # https://github.com/pry/pry/blob/master/lib/pry/default_commands/context.rb
+ def check_file_context(target)
+ file = target.eval('__FILE__')
+ file == Pry.eval_path || (file !~ /(\(.*\))|<.*>/ && file != '' && file != '-e')
+ end
+end
@@ -0,0 +1 @@
+require 'pry-debugger'
@@ -0,0 +1,39 @@
+require 'pry'
+
+module PryDebugger
+ Commands = Pry::CommandSet.new do
+ block_command 'step', 'Step execution into the next line or method.' do |steps|
+ check_file_context
+ breakout_navigation :step, steps
+ end
+
+ block_command 'next', 'Execute the next line within the same stack frame.' do |lines|
+ check_file_context
+ breakout_navigation :next, lines
+ end
+
+ block_command 'continue', 'Continue program execution and end the Pry session.' do
+ check_file_context
+ run 'exit-all'
+ end
+
+ helpers do
+ def breakout_navigation(action, times)
+ _pry_.binding_stack.clear # Clear the binding stack.
+ throw :breakout_nav, { # Break out of the REPL loop and
+ :action => action, # signal the tracer.
+ :times => times
+ }
+ end
+
+ # Ensures that a command is executed in a local file context.
+ def check_file_context
+ unless PryDebugger.check_file_context(target)
+ raise Pry::CommandError, 'Cannot find local context. Did you use `binding.pry`?'
+ end
+ end
+ end
+ end
+end
+
+Pry.commands.import PryDebugger::Commands
@@ -0,0 +1,64 @@
+require 'pry'
+require 'debugger'
+
+module PryDebugger
+ class Processor
+ def initialize(pry_start_options = {}, &block)
+ Debugger.handler = self
+ @pry_start_options = pry_start_options
+ end
+
+ def run(&block)
+ return_value = nil
+ command = catch(:breakout_nav) do # Throws from PryDebugger::Commands
+ return_value = yield
+ {} # Nothing thrown == no navigational command
+ end
+
+ times = (command[:times] || 1).to_i # Command argument
+ times = 1 if times <= 0
+
+ if [:step, :next].include? command[:action]
+ Debugger.start
+ if Debugger.current_context.frame_self.is_a? Debugger::Context
+ # The first binding.pry call will have a frame inside Debugger. If we
+ # step normally, it'll stop inside this Processor instead. So jump it
+ # out to the above frame.
+ #
+ # TODO: times isn't respected
+ Debugger.current_context.stop_frame = 1
+ else
+ if :next == command[:action]
+ Debugger.current_context.step_over(times, 0)
+ else # step
+ Debugger.current_context.step(times)
+ end
+ end
+ end
+
+ return_value
+ end
+
+
+ # --- Callbacks from debugger C extension ---
+
+ def at_line(context, file, line)
+ start_pry context
+ end
+
+ def at_breakpoint(context, breakpoint)
+ # TODO
+ end
+
+ def at_catchpoint(context, exception)
+ # TODO
+ end
+
+
+ private
+
+ def start_pry(context)
+ Pry.start(context.frame_binding(0), @pry_start_options)
+ end
+ end
+end
@@ -0,0 +1,19 @@
+require 'pry'
+require 'pry-debugger/processor'
+
+class << Pry
+ alias_method :start_existing, :start
+
+ def start(target = TOPLEVEL_BINDING, options = {})
+ if target.is_a?(Binding) && PryDebugger.check_file_context(target)
+ # Wrap the processer around the usual Pry.start to catch navigation
+ # commands.
+ PryDebugger::Processor.new(options).run do
+ start_existing(target, options)
+ end
+ else
+ # No need for the tracer unless we have a file context to step through
+ start_existing(target, options)
+ end
+ end
+end
@@ -0,0 +1,3 @@
+module PryDebugger
+ VERSION = '0.0.1'
+end
@@ -0,0 +1,24 @@
+# -*- encoding: utf-8 -*-
+
+require File.expand_path('../lib/pry-debugger/version', __FILE__)
+
+Gem::Specification.new do |gem|
+ gem.name = 'pry-debugger'
+ gem.version = PryDebugger::VERSION
+ gem.author = 'Gopal Patel'
+ gem.email = 'nixme@stillhope.com'
+ gem.license = 'MIT'
+ gem.homepage = 'https://github.com/nixme/pry-debugger'
+ gem.summary = 'Fast debugging with Pry.'
+ gem.description = "Combine 'pry' with 'debugger'. Adds 'step', 'next', and 'continue' commands to control execution."
+
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
+ gem.files = `git ls-files`.split("\n")
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
+ gem.require_paths = ["lib"]
+
+ # Dependencies
+ gem.required_ruby_version = '>= 1.9.2'
+ gem.add_runtime_dependency 'pry', '~> 0.9.9'
+ gem.add_runtime_dependency 'debugger', '~> 1.1.3'
+end

0 comments on commit 331e662

Please sign in to comment.