pry--pry/lib/pry.rb

268 lines
5.8 KiB
Ruby
Raw Normal View History

# (C) John Mair (banisterfiend) 2010
# MIT License
direc = File.dirname(__FILE__)
require "method_source"
require "#{direc}/pry/version"
require "#{direc}/pry/input"
require "#{direc}/pry/output"
2010-12-07 08:11:35 +00:00
class Pry
def self.start(target=TOPLEVEL_BINDING)
new.repl(target)
end
def self.view(obj)
case obj
when String, Array, Hash, Symbol, nil
obj.inspect
else
obj.to_s
end
end
def self.reset_defaults
self.input = Input.new
self.output = Output.new
self.default_prompt = proc do |v, nest|
if nest == 0
"pry(#{Pry.view(v)})> "
else
"pry(#{Pry.view(v)}):#{Pry.view(nest)}> "
end
end
self.wait_prompt = proc do |v, nest|
if nest == 0
"pry(#{Pry.view(v)})* "
else
"pry(#{Pry.view(v)}):#{Pry.view(nest)}* "
end
end
end
# class accessors
2010-12-08 11:39:06 +00:00
class << self
attr_reader :nesting
attr_accessor :last_result
attr_accessor :default_prompt, :wait_prompt
attr_accessor :input, :output
end
self.reset_defaults
@nesting = []
def @nesting.level
last.is_a?(Array) ? last.first : nil
2010-12-08 11:39:06 +00:00
end
attr_accessor :input, :output
attr_accessor :default_prompt, :wait_prompt
attr_reader :last_result
2010-12-08 11:39:06 +00:00
def initialize(input = Pry.input, output = Pry.output)
@input = input
@output = output
2010-12-12 00:35:07 +00:00
@default_prompt = Pry.default_prompt
@wait_prompt = Pry.wait_prompt
end
def nesting
self.class.nesting
end
def nesting=(v)
self.class.nesting = v
end
2010-12-08 11:39:06 +00:00
2010-12-08 07:30:38 +00:00
# loop
def repl(target=TOPLEVEL_BINDING)
target = binding_for(target)
target_self = target.eval('self')
output.session_start(target_self)
2010-12-08 11:39:06 +00:00
nesting_level = nesting.size
# Make sure _ exists
target.eval("_ = Pry.last_result")
break_level = catch(:breakout) do
nesting << [nesting.size, target_self]
loop do
rep(target)
2010-12-08 07:30:38 +00:00
end
2010-12-07 08:11:35 +00:00
end
2010-12-08 11:39:06 +00:00
nesting.pop
output.session_end(target_self)
# we only enter here if :breakout has been thrown
if nesting_level != break_level
throw :breakout, break_level
end
target_self
end
2010-12-08 07:30:38 +00:00
# print
def rep(target=TOPLEVEL_BINDING)
target = binding_for(target)
output.print re(target)
2010-12-08 07:30:38 +00:00
end
2010-12-08 07:30:38 +00:00
# eval
def re(target=TOPLEVEL_BINDING)
target = binding_for(target)
Pry.last_result = target.eval r(target)
target.eval("_ = Pry.last_result")
rescue SystemExit => e
exit
rescue Exception => e
2010-12-08 07:30:38 +00:00
e
end
2010-12-08 07:30:38 +00:00
# read
def r(target=TOPLEVEL_BINDING)
target = binding_for(target)
2010-12-08 07:30:38 +00:00
eval_string = ""
loop do
val = input.read(prompt(eval_string, target, nesting.level))
eval_string << "#{val.chomp}\n"
2010-12-08 11:39:06 +00:00
process_commands(val, eval_string, target)
2010-12-08 07:30:38 +00:00
break eval_string if valid_expression?(eval_string)
end
end
def process_commands(val, eval_string, target)
def eval_string.clear() replace("") end
2010-12-08 07:30:38 +00:00
case val
when "exit_program", "quit_program"
output.exit_program
2010-12-08 07:30:38 +00:00
exit
when "!"
output.refresh
eval_string.clear
when "help"
output.show_help
eval_string.clear
when "nesting"
output.show_nesting(nesting)
eval_string.clear
when "status"
output.show_status(nesting, target)
eval_string.clear
when "exit_all"
throw(:breakout, 0)
2010-12-15 02:21:13 +00:00
when "exit", "quit", "back", /^cd\s*\.\./
output.exit
throw(:breakout, nesting.level)
2010-12-15 02:21:13 +00:00
when "ls"
output.ls(target)
eval_string.clear
when /^cat\s+(.+)/
var = $~.captures.first
output.cat(target, var)
eval_string.clear
2010-12-15 02:21:13 +00:00
when /^cd\s+(.+)/
obj = $~.captures.first
output.cd(obj)
2010-12-15 02:21:13 +00:00
target.eval("#{obj}.pry")
eval_string.clear
when /^show_doc\s*(.+)/
meth_name = ($~.captures).first
doc = target.eval("method(:#{meth_name})").comment
output.show_doc doc
eval_string.clear
when /^show_idoc\s*(.+)/
meth_name = ($~.captures).first
doc = target.eval("instance_method(:#{meth_name})").comment
output.show_doc doc
eval_string.clear
when /^show_method\s*(.+)/
meth_name = ($~.captures).first
code = target.eval("method(:#{meth_name})").source
output.show_method code
2010-12-15 02:21:13 +00:00
eval_string.clear
when /^show_instance_method\s*(.+)/, /^show_imethod\s*(.+)/
2010-12-15 02:21:13 +00:00
meth_name = ($~.captures).first
code = target.eval("instance_method(:#{meth_name})").source
output.show_method code
eval_string.clear
2010-12-15 02:21:13 +00:00
when /^jump_to\s*(\d*)/
break_level = ($~.captures).first.to_i
output.jump_to(break_level)
2010-12-12 10:31:04 +00:00
case break_level
when nesting.level
output.warn_already_at_level(nesting.level)
eval_string.clear
when (0...nesting.level)
throw(:breakout, break_level + 1)
else
output.err_invalid_nest_level(break_level,
nesting.level - 1)
eval_string.clear
end
2010-12-07 08:11:35 +00:00
end
2010-12-08 07:30:38 +00:00
end
2010-12-07 08:11:35 +00:00
def prompt(eval_string, target, nest)
2010-12-08 14:57:50 +00:00
target_self = target.eval('self')
2010-12-08 07:30:38 +00:00
if eval_string.empty?
default_prompt.call(target_self, nest)
else
wait_prompt.call(target_self, nest)
end
2010-12-07 08:11:35 +00:00
end
if RUBY_VERSION =~ /1.9/
require 'ripper'
def valid_expression?(code)
!!Ripper::SexpBuilder.new(code).parse
end
2010-12-08 07:30:38 +00:00
else
require 'ruby_parser'
def valid_expression?(code)
RubyParser.new.parse(code)
rescue Racc::ParseError, SyntaxError
false
else
true
end
2010-12-08 07:30:38 +00:00
end
def binding_for(target)
if target.is_a?(Binding)
target
else
if target == TOPLEVEL_BINDING.eval('self')
TOPLEVEL_BINDING
else
target.instance_eval { binding }
end
end
end
module ObjectExtensions
def pry(target=self)
Pry.start(target)
end
end
end
class Object
include Pry::ObjectExtensions
end