2010-12-08 13:49:28 +00:00
|
|
|
# (C) John Mair (banisterfiend) 2010
|
|
|
|
# MIT License
|
|
|
|
|
|
|
|
direc = File.dirname(__FILE__)
|
|
|
|
|
2010-12-18 11:21:58 +00:00
|
|
|
require "method_source"
|
2010-12-08 13:49:28 +00:00
|
|
|
require "#{direc}/pry/version"
|
2010-12-09 00:59:30 +00:00
|
|
|
require "#{direc}/pry/input"
|
|
|
|
require "#{direc}/pry/output"
|
2010-12-25 12:05:48 +00:00
|
|
|
require "#{direc}/pry/commands"
|
2010-12-07 08:11:35 +00:00
|
|
|
|
2010-12-13 12:33:05 +00:00
|
|
|
class Pry
|
2010-12-24 08:30:51 +00:00
|
|
|
def self.start(target=TOPLEVEL_BINDING, options={})
|
|
|
|
options = {
|
|
|
|
:input => Pry.input,
|
|
|
|
:output => Pry.output
|
|
|
|
}.merge!(options)
|
|
|
|
|
|
|
|
new(options[:input], options[:output]).repl(target)
|
2010-12-14 10:54:26 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def self.view(obj)
|
|
|
|
case obj
|
2010-12-17 04:56:50 +00:00
|
|
|
when String, Array, Hash, Symbol, nil
|
2010-12-14 10:54:26 +00:00
|
|
|
obj.inspect
|
|
|
|
else
|
|
|
|
obj.to_s
|
|
|
|
end
|
|
|
|
end
|
2010-12-17 11:01:34 +00:00
|
|
|
|
2010-12-21 14:03:52 +00:00
|
|
|
def self.reset_defaults
|
|
|
|
self.input = Input.new
|
|
|
|
self.output = Output.new
|
2010-12-25 12:05:48 +00:00
|
|
|
self.commands = Commands.new(self.output)
|
2010-12-21 14:03:52 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2010-12-09 00:59:30 +00:00
|
|
|
# class accessors
|
2010-12-08 11:39:06 +00:00
|
|
|
class << self
|
2010-12-09 00:59:30 +00:00
|
|
|
attr_reader :nesting
|
2010-12-13 12:33:05 +00:00
|
|
|
attr_accessor :last_result
|
2010-12-17 11:01:34 +00:00
|
|
|
attr_accessor :default_prompt, :wait_prompt
|
2010-12-21 14:03:52 +00:00
|
|
|
attr_accessor :input, :output
|
2010-12-25 12:05:48 +00:00
|
|
|
attr_accessor :commands
|
2010-12-17 11:01:34 +00:00
|
|
|
end
|
|
|
|
|
2010-12-21 14:03:52 +00:00
|
|
|
self.reset_defaults
|
|
|
|
|
|
|
|
@nesting = []
|
|
|
|
|
|
|
|
def @nesting.level
|
|
|
|
last.is_a?(Array) ? last.first : nil
|
2010-12-08 11:39:06 +00:00
|
|
|
end
|
2010-12-13 12:33:05 +00:00
|
|
|
|
2010-12-14 10:54:26 +00:00
|
|
|
attr_accessor :input, :output
|
2010-12-17 11:01:34 +00:00
|
|
|
attr_accessor :default_prompt, :wait_prompt
|
2010-12-25 12:05:48 +00:00
|
|
|
attr_accessor :commands
|
2010-12-17 11:01:34 +00:00
|
|
|
attr_reader :last_result
|
2010-12-08 11:39:06 +00:00
|
|
|
|
2010-12-21 14:03:52 +00:00
|
|
|
def initialize(input = Pry.input, output = Pry.output)
|
2010-12-14 10:54:26 +00:00
|
|
|
@input = input
|
|
|
|
@output = output
|
2010-12-12 00:35:07 +00:00
|
|
|
|
2010-12-17 11:01:34 +00:00
|
|
|
@default_prompt = Pry.default_prompt
|
|
|
|
@wait_prompt = Pry.wait_prompt
|
2010-12-25 12:05:48 +00:00
|
|
|
@commands = Commands.new(output)
|
2010-12-09 00:59:30 +00:00
|
|
|
end
|
2010-12-13 12:33:05 +00:00
|
|
|
|
|
|
|
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
|
2010-12-13 12:33:05 +00:00
|
|
|
def repl(target=TOPLEVEL_BINDING)
|
2010-12-08 15:39:42 +00:00
|
|
|
target = binding_for(target)
|
2010-12-08 13:49:28 +00:00
|
|
|
target_self = target.eval('self')
|
2010-12-09 00:59:30 +00:00
|
|
|
output.session_start(target_self)
|
2010-12-08 11:39:06 +00:00
|
|
|
|
2010-12-13 12:33:05 +00:00
|
|
|
nesting_level = nesting.size
|
2010-12-09 00:59:30 +00:00
|
|
|
|
|
|
|
# Make sure _ exists
|
|
|
|
target.eval("_ = Pry.last_result")
|
|
|
|
|
2010-12-11 21:53:14 +00:00
|
|
|
break_level = catch(:breakout) do
|
2010-12-13 12:33:05 +00:00
|
|
|
nesting << [nesting.size, target_self]
|
2010-12-09 00:59:30 +00:00
|
|
|
loop do
|
2010-12-13 12:33:05 +00:00
|
|
|
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
|
|
|
|
2010-12-13 12:33:05 +00:00
|
|
|
nesting.pop
|
2010-12-09 00:59:30 +00:00
|
|
|
output.session_end(target_self)
|
2010-12-08 13:49:28 +00:00
|
|
|
|
2010-12-09 00:59:30 +00:00
|
|
|
# we only enter here if :breakout has been thrown
|
2010-12-13 12:33:05 +00:00
|
|
|
if nesting_level != break_level
|
2010-12-11 21:53:14 +00:00
|
|
|
throw :breakout, break_level
|
2010-12-09 00:59:30 +00:00
|
|
|
end
|
|
|
|
|
2010-12-08 13:49:28 +00:00
|
|
|
target_self
|
2010-12-08 00:19:55 +00:00
|
|
|
end
|
2010-12-09 00:59:30 +00:00
|
|
|
|
2010-12-08 07:30:38 +00:00
|
|
|
# print
|
2010-12-13 12:33:05 +00:00
|
|
|
def rep(target=TOPLEVEL_BINDING)
|
2010-12-08 15:39:42 +00:00
|
|
|
target = binding_for(target)
|
2010-12-09 00:59:30 +00:00
|
|
|
output.print re(target)
|
2010-12-08 07:30:38 +00:00
|
|
|
end
|
2010-12-08 00:19:55 +00:00
|
|
|
|
2010-12-08 07:30:38 +00:00
|
|
|
# eval
|
2010-12-13 12:33:05 +00:00
|
|
|
def re(target=TOPLEVEL_BINDING)
|
2010-12-08 15:39:42 +00:00
|
|
|
target = binding_for(target)
|
2010-12-13 12:33:05 +00:00
|
|
|
Pry.last_result = target.eval r(target)
|
2010-12-09 00:59:30 +00:00
|
|
|
target.eval("_ = Pry.last_result")
|
2010-12-15 04:56:06 +00:00
|
|
|
rescue SystemExit => e
|
|
|
|
exit
|
2010-12-14 10:54:26 +00:00
|
|
|
rescue Exception => e
|
2010-12-08 07:30:38 +00:00
|
|
|
e
|
|
|
|
end
|
2010-12-08 00:19:55 +00:00
|
|
|
|
2010-12-08 07:30:38 +00:00
|
|
|
# read
|
2010-12-13 12:33:05 +00:00
|
|
|
def r(target=TOPLEVEL_BINDING)
|
2010-12-08 15:39:42 +00:00
|
|
|
target = binding_for(target)
|
2010-12-08 07:30:38 +00:00
|
|
|
eval_string = ""
|
|
|
|
loop do
|
2010-12-09 00:59:30 +00:00
|
|
|
val = input.read(prompt(eval_string, target, nesting.level))
|
2010-12-21 14:03:52 +00:00
|
|
|
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
|
|
|
|
|
2010-12-13 12:33:05 +00:00
|
|
|
def process_commands(val, eval_string, target)
|
2010-12-09 00:59:30 +00:00
|
|
|
def eval_string.clear() replace("") end
|
2010-12-25 12:05:48 +00:00
|
|
|
|
|
|
|
if action = commands.commands.find { |k, v| Array(k).any? { |a| a === val } }
|
|
|
|
|
|
|
|
options = {
|
|
|
|
:captures => $~ ? $~.captures : nil,
|
|
|
|
:eval_string => eval_string,
|
|
|
|
:target => target,
|
|
|
|
:val => val,
|
|
|
|
:nesting => nesting,
|
|
|
|
:output => output
|
|
|
|
}
|
|
|
|
|
|
|
|
action.last.call(options)
|
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
|
|
|
|
2010-12-13 12:33:05 +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?
|
2010-12-09 00:59:30 +00:00
|
|
|
default_prompt.call(target_self, nest)
|
2010-12-08 00:19:55 +00:00
|
|
|
else
|
2010-12-09 00:59:30 +00:00
|
|
|
wait_prompt.call(target_self, nest)
|
2010-12-08 00:19:55 +00:00
|
|
|
end
|
2010-12-07 08:11:35 +00:00
|
|
|
end
|
2010-12-08 00:19:55 +00:00
|
|
|
|
2010-12-17 04:56:50 +00:00
|
|
|
if RUBY_VERSION =~ /1.9/
|
|
|
|
require 'ripper'
|
|
|
|
|
|
|
|
def valid_expression?(code)
|
|
|
|
!!Ripper::SexpBuilder.new(code).parse
|
2010-12-14 10:54:26 +00:00
|
|
|
end
|
2010-12-17 04:56:50 +00:00
|
|
|
|
2010-12-08 07:30:38 +00:00
|
|
|
else
|
2010-12-18 11:21:58 +00:00
|
|
|
require 'ruby_parser'
|
2010-12-17 04:56:50 +00:00
|
|
|
|
|
|
|
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
|
2010-12-08 13:49:28 +00:00
|
|
|
|
2010-12-13 12:33:05 +00:00
|
|
|
def binding_for(target)
|
2010-12-08 15:39:42 +00:00
|
|
|
if target.is_a?(Binding)
|
|
|
|
target
|
|
|
|
else
|
2010-12-11 05:22:17 +00:00
|
|
|
if target == TOPLEVEL_BINDING.eval('self')
|
|
|
|
TOPLEVEL_BINDING
|
|
|
|
else
|
2010-12-24 13:22:08 +00:00
|
|
|
target.__binding__
|
2010-12-11 05:22:17 +00:00
|
|
|
end
|
2010-12-08 15:39:42 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2010-12-09 00:59:30 +00:00
|
|
|
module ObjectExtensions
|
2010-12-11 09:01:47 +00:00
|
|
|
def pry(target=self)
|
2010-12-17 11:01:34 +00:00
|
|
|
Pry.start(target)
|
2010-12-09 00:59:30 +00:00
|
|
|
end
|
2010-12-24 13:22:08 +00:00
|
|
|
|
|
|
|
def __binding__
|
|
|
|
if is_a?(Module)
|
|
|
|
return class_eval "binding"
|
|
|
|
end
|
|
|
|
|
|
|
|
unless respond_to? :__binding_impl__
|
|
|
|
self.class.class_eval <<-EXTRA
|
|
|
|
def __binding_impl__
|
|
|
|
binding
|
|
|
|
end
|
|
|
|
EXTRA
|
|
|
|
end
|
|
|
|
|
|
|
|
__binding_impl__
|
|
|
|
end
|
2010-12-08 13:49:28 +00:00
|
|
|
end
|
2010-12-09 00:59:30 +00:00
|
|
|
end
|
2010-12-08 13:49:28 +00:00
|
|
|
|
2010-12-09 00:59:30 +00:00
|
|
|
class Object
|
|
|
|
include Pry::ObjectExtensions
|
2010-12-08 00:19:55 +00:00
|
|
|
end
|