mirror of
https://github.com/pry/pry.git
synced 2022-11-09 12:35:05 -05:00
09685f360c
* removed exit_at alias for jump_to, now only jump_to is valid * updated documentation * added another format for pry method, can now use 5.pry or pry(5)
186 lines
4 KiB
Ruby
186 lines
4 KiB
Ruby
# (C) John Mair (banisterfiend) 2010
|
|
# MIT License
|
|
|
|
direc = File.dirname(__FILE__)
|
|
|
|
require 'ruby_parser'
|
|
require "#{direc}/pry/version"
|
|
require "#{direc}/pry/input"
|
|
require "#{direc}/pry/output"
|
|
|
|
module Pry
|
|
|
|
# class accessors
|
|
class << self
|
|
attr_reader :nesting
|
|
attr_reader :last_result
|
|
attr_accessor :default_prompt
|
|
attr_accessor :wait_prompt
|
|
attr_accessor :input
|
|
attr_accessor :output
|
|
end
|
|
|
|
@default_prompt = lambda do |v, nest|
|
|
if nest == 0
|
|
"pry(#{v.inspect})> "
|
|
else
|
|
"pry(#{v.inspect}):#{nest.inspect}> "
|
|
end
|
|
end
|
|
|
|
@wait_prompt = lambda do |v, nest|
|
|
if nest == 0
|
|
"pry(#{v.inspect})* "
|
|
else
|
|
"pry(#{v.inspect}):#{nest.inspect}* "
|
|
end
|
|
end
|
|
|
|
@output = Output.new
|
|
@input = Input.new
|
|
|
|
@nesting = []
|
|
|
|
def @nesting.level
|
|
last.is_a?(Array) ? last.first : nil
|
|
end
|
|
|
|
# loop
|
|
def self.repl(target=TOPLEVEL_BINDING)
|
|
target = binding_for(target)
|
|
target_self = target.eval('self')
|
|
output.session_start(target_self)
|
|
|
|
nesting_level = @nesting.size
|
|
|
|
# Make sure _ exists
|
|
target.eval("_ = Pry.last_result")
|
|
|
|
nesting_level_breakout = catch(:breakout) do
|
|
@nesting << [@nesting.size, target_self]
|
|
loop do
|
|
rep(target)
|
|
end
|
|
end
|
|
|
|
@nesting.pop
|
|
output.session_end(target_self)
|
|
|
|
# we only enter here if :breakout has been thrown
|
|
if nesting_level_breakout
|
|
throw :breakout, nesting_level_breakout if nesting_level != nesting_level_breakout
|
|
end
|
|
|
|
target_self
|
|
end
|
|
|
|
class << self
|
|
alias_method :into, :repl
|
|
alias_method :start, :repl
|
|
end
|
|
|
|
# print
|
|
def self.rep(target=TOPLEVEL_BINDING)
|
|
target = binding_for(target)
|
|
output.print re(target)
|
|
end
|
|
|
|
# eval
|
|
def self.re(target=TOPLEVEL_BINDING)
|
|
target = binding_for(target)
|
|
@last_result = target.eval r(target)
|
|
target.eval("_ = Pry.last_result")
|
|
rescue StandardError => e
|
|
e
|
|
end
|
|
|
|
# read
|
|
def self.r(target=TOPLEVEL_BINDING)
|
|
target = binding_for(target)
|
|
eval_string = ""
|
|
loop do
|
|
val = input.read(prompt(eval_string, target, nesting.level))
|
|
eval_string += "#{val}\n"
|
|
process_commands(val, eval_string, target)
|
|
|
|
break eval_string if valid_expression?(eval_string)
|
|
end
|
|
end
|
|
|
|
def self.process_commands(val, eval_string, target)
|
|
def eval_string.clear() replace("") end
|
|
|
|
case val
|
|
when "exit_program", "quit_program"
|
|
output.exit_program
|
|
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)
|
|
when "exit", "quit", "back"
|
|
output.exit
|
|
throw(:breakout, nesting.level)
|
|
when /jump_to\s*(\d*)/
|
|
nesting_level_breakout = ($~.captures).first.to_i
|
|
output.jump_to(nesting_level_breakout)
|
|
|
|
if nesting_level_breakout < 0 || nesting_level_breakout >= nesting.level
|
|
output.error_invalid_nest_level(nesting_level_breakout, nesting.level - 1)
|
|
eval_string.clear
|
|
else
|
|
throw(:breakout, nesting_level_breakout + 1)
|
|
end
|
|
end
|
|
end
|
|
|
|
def self.prompt(eval_string, target, nest)
|
|
target_self = target.eval('self')
|
|
|
|
if eval_string.empty?
|
|
default_prompt.call(target_self, nest)
|
|
else
|
|
wait_prompt.call(target_self, nest)
|
|
end
|
|
end
|
|
|
|
def self.valid_expression?(code)
|
|
RubyParser.new.parse(code)
|
|
rescue Racc::ParseError, SyntaxError
|
|
false
|
|
else
|
|
true
|
|
end
|
|
|
|
def self.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(Pry.binding_for(target))
|
|
end
|
|
end
|
|
end
|
|
|
|
class Object
|
|
include Pry::ObjectExtensions
|
|
end
|