Skip to content

Commit

Permalink
Initial attempt at basic 'step' and 'next' commands
Browse files Browse the repository at this point in the history
Based on set_trace_func and similar logic to stdlib's debug.rb.
  • Loading branch information
nixme committed Nov 29, 2011
0 parents commit 0488937
Show file tree
Hide file tree
Showing 10 changed files with 206 additions and 0 deletions.
17 changes: 17 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -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
4 changes: 4 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
source 'http://rubygems.org'

# Specify your gem's dependencies in pry-nav.gemspec
gemspec
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
pry-nav
=======

_Simple execution control in Pry_

Adds **step** and **next** commands to your [Pry][pry]
console. Makes for a simple but ghetto debugger.

Note: In order to get the correct flow control, `Pry.start` is overriden. Use at
your own risk.


## Acknowledgments

- Ruby stdlib [debug.rb][debug.rb]
- [@Mon-Ouie][Mon-Ouie]'s [pry_debug][pry_debug]


## TODO

- Thread safety
- Compatibility with [pry-remote][pry-remote]


[pry]: http://pry.github.com
[debug.rb]: https://github.com/ruby/ruby/blob/trunk/lib/debug.rb
[Mon-Ouie]: https://github.com/Mon-Ouie
[pry_debug]: https://github.com/Mon-Ouie/pry_debug
[pry-remote]: https://github.com/Mon-Ouie/pry-remote
2 changes: 2 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env rake
require "bundler/gem_tasks"
4 changes: 4 additions & 0 deletions lib/pry-nav.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
require 'pry-nav/version'
require 'pry-nav/pry_ext'
require 'pry-nav/commands'
require 'pry-nav/tracer'
28 changes: 28 additions & 0 deletions lib/pry-nav/commands.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
require 'pry'

module PryNav
Commands = Pry::CommandSet.new do
command 'step', 'Step execution into the next line or method.' do |steps|
breakout_navigation :step, steps
end

command 'next', 'Execute the next line within the same stack frame.' do |lines|
breakout_navigation :next, lines
end

alias_command 'n', 'next'
alias_command 's', 'step'

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
end
end
end

Pry.commands.import PryNav::Commands
11 changes: 11 additions & 0 deletions lib/pry-nav/pry_ext.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
require 'pry'

class << Pry
alias_method :start_existing, :start

def start(target = TOPLEVEL_BINDING, options = {})
PryNav::Tracer.new(options) do
start_existing(target, options)
end
end
end
85 changes: 85 additions & 0 deletions lib/pry-nav/tracer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
require 'pry'

module PryNav
class Tracer
FILE = File.expand_path(__FILE__)

def initialize(pry_start_options = {}, &block)
@step_in_lines = -1 # Break after this many lines
@frames_when_stepping = nil # Only break at this frame level
@frames = [] # Traced stack frames
@pry_start_options = pry_start_options # Options to use for Pry.start

run &block
end

def run(&block)
start # Set the trace function

return_value = nil
command = catch(:breakout_nav) do # Coordinate with PryNav::Commands
return_value = yield
{} # Nothing thrown == no navigational command
end

process_command command

return_value
end

def start
set_trace_func method(:tracer).to_proc
end

def stop
set_trace_func nil
end

def process_command(command = {})
times = (command[:times] || 1).to_i
times = 1 if times <= 0

case command[:action]
when :step
@step_in_lines = times
@frames_when_stepping = nil
when :next
@step_in_lines = times
@frames_when_stepping = @frames.size
else
stop
end
end


private

def tracer(event, file, line, id, binding, klass)
# Ignore traces inside pry-nav code
return if (file && File.expand_path(file) == FILE)

case event
when 'line'
# Are we stepping? Or continuing by line ('next') and we're at the right
# frame? Then decrement our line counter cause this line counts.
if !@frames_when_stepping || @frames.size == @frames_when_stepping
@step_in_lines -= 1
@step_in_lines = -1 if @step_in_lines < 0

# Did we go up a frame and not break for a 'next' yet?
elsif @frames.size < @frames_when_stepping
@step_in_lines = 0 # Break right away
end

# Break on this line?
Pry.start(binding, @pry_start_options) if @step_in_lines == 0

when 'call', 'class'
@frames.unshift [binding, file, line, id] # Track entering a frame

when 'return', 'end'
@frames.shift # Track leaving a stack frame
end
end
end
end
3 changes: 3 additions & 0 deletions lib/pry-nav/version.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module PryNav
VERSION = '0.0.1'
end
23 changes: 23 additions & 0 deletions pry-nav.gemspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# -*- encoding: utf-8 -*-

require File.expand_path('../lib/pry-nav/version', __FILE__)

Gem::Specification.new do |gem|
gem.name = 'pry-nav'
gem.version = PryNav::VERSION
gem.author = 'Gopal Patel'
gem.email = 'nixme@stillhope.com'
gem.license = 'MIT'
gem.homepage = 'https://github.com/nixme/pry-nav'
gem.summary = 'Simple execution navigation for Pry.'
gem.description = "Turn Pry into a primitive debugger. Adds 'step' and 'next' 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.7.4'
end

0 comments on commit 0488937

Please sign in to comment.