split Pry into 3 more files: pry_class (for class methods) pry_instance (instance methods) and core_extensions, for extensions to Object (e.g pry and __binding__ methods)
This commit is contained in:
parent
f11806d2da
commit
6b3a6871fc
216
lib/pry.rb
216
lib/pry.rb
|
@ -9,219 +9,9 @@ require "#{direc}/pry/input"
|
|||
require "#{direc}/pry/output"
|
||||
require "#{direc}/pry/commands"
|
||||
require "#{direc}/pry/prompts"
|
||||
require "#{direc}/pry/core_extensions"
|
||||
require "#{direc}/pry/pry_class"
|
||||
require "#{direc}/pry/pry_instance"
|
||||
|
||||
class Pry
|
||||
|
||||
# class accessors
|
||||
class << self
|
||||
attr_reader :nesting
|
||||
attr_accessor :last_result
|
||||
attr_accessor :input, :output
|
||||
attr_accessor :commands
|
||||
attr_accessor :default_prompt, :wait_prompt
|
||||
end
|
||||
|
||||
def self.start(target=TOPLEVEL_BINDING, options={})
|
||||
new(options).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.commands = COMMANDS
|
||||
self.default_prompt = DEFAULT_PROMPT
|
||||
self.wait_prompt = WAIT_PROMPT
|
||||
end
|
||||
|
||||
self.reset_defaults
|
||||
|
||||
@nesting = []
|
||||
|
||||
def @nesting.level
|
||||
last.is_a?(Array) ? last.first : nil
|
||||
end
|
||||
|
||||
attr_accessor :input, :output
|
||||
attr_accessor :commands
|
||||
attr_accessor :default_prompt, :wait_prompt
|
||||
attr_reader :last_result
|
||||
|
||||
def initialize(options={})
|
||||
|
||||
options = {
|
||||
:input => Pry.input,
|
||||
:output => Pry.output,
|
||||
:commands => Pry.commands,
|
||||
:default_prompt => Pry.default_prompt,
|
||||
:wait_prompt => Pry.wait_prompt
|
||||
}.merge!(options)
|
||||
|
||||
@input = options[:input]
|
||||
@output = options[:output]
|
||||
@commands = options[:commands]
|
||||
@default_prompt = options[:default_prompt]
|
||||
@wait_prompt = options[:wait_prompt]
|
||||
end
|
||||
|
||||
def nesting
|
||||
self.class.nesting
|
||||
end
|
||||
|
||||
def nesting=(v)
|
||||
self.class.nesting = v
|
||||
end
|
||||
|
||||
# loop
|
||||
def 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")
|
||||
|
||||
break_level = 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 != break_level
|
||||
throw :breakout, break_level
|
||||
end
|
||||
|
||||
target_self
|
||||
end
|
||||
|
||||
# print
|
||||
def rep(target=TOPLEVEL_BINDING)
|
||||
target = binding_for(target)
|
||||
output.print re(target)
|
||||
end
|
||||
|
||||
# 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
|
||||
e
|
||||
end
|
||||
|
||||
# read
|
||||
def r(target=TOPLEVEL_BINDING)
|
||||
target = binding_for(target)
|
||||
eval_string = ""
|
||||
loop do
|
||||
val = input.read(prompt(eval_string, target, nesting.level))
|
||||
eval_string << "#{val.chomp}\n"
|
||||
process_commands(val, eval_string, target)
|
||||
|
||||
break eval_string if valid_expression?(eval_string)
|
||||
end
|
||||
end
|
||||
|
||||
def process_commands(val, eval_string, target)
|
||||
def eval_string.clear() replace("") end
|
||||
|
||||
pattern, action = commands.find { |k, v| Array(k).any? { |a| a === val } }
|
||||
|
||||
if pattern
|
||||
options = {
|
||||
:captures => $~ ? $~.captures : nil,
|
||||
:eval_string => eval_string,
|
||||
:target => target,
|
||||
:val => val,
|
||||
:nesting => nesting,
|
||||
:output => output
|
||||
}
|
||||
|
||||
action.call(options)
|
||||
end
|
||||
end
|
||||
|
||||
def 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
|
||||
|
||||
if RUBY_VERSION =~ /1.9/
|
||||
require 'ripper'
|
||||
|
||||
def valid_expression?(code)
|
||||
!!Ripper::SexpBuilder.new(code).parse
|
||||
end
|
||||
|
||||
else
|
||||
require 'ruby_parser'
|
||||
|
||||
def valid_expression?(code)
|
||||
RubyParser.new.parse(code)
|
||||
rescue Racc::ParseError, SyntaxError
|
||||
false
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
def binding_for(target)
|
||||
if target.is_a?(Binding)
|
||||
target
|
||||
else
|
||||
if target == TOPLEVEL_BINDING.eval('self')
|
||||
TOPLEVEL_BINDING
|
||||
else
|
||||
target.__binding__
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module ObjectExtensions
|
||||
def pry(target=self, options={})
|
||||
Pry.start(target, options)
|
||||
end
|
||||
|
||||
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
|
||||
end
|
||||
end
|
||||
|
||||
class Object
|
||||
include Pry::ObjectExtensions
|
||||
end
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
class Pry
|
||||
module ObjectExtensions
|
||||
def pry(target=self, options={})
|
||||
Pry.start(target, options)
|
||||
end
|
||||
|
||||
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
|
||||
end
|
||||
end
|
||||
|
||||
# bring the extensions into Object
|
||||
class Object
|
||||
include Pry::ObjectExtensions
|
||||
end
|
|
@ -0,0 +1,17 @@
|
|||
class Pry
|
||||
DEFAULT_PROMPT = proc do |v, nest|
|
||||
if nest == 0
|
||||
"pry(#{Pry.view(v)})> "
|
||||
else
|
||||
"pry(#{Pry.view(v)}):#{Pry.view(nest)}> "
|
||||
end
|
||||
end
|
||||
|
||||
WAIT_PROMPT = proc do |v, nest|
|
||||
if nest == 0
|
||||
"pry(#{Pry.view(v)})* "
|
||||
else
|
||||
"pry(#{Pry.view(v)}):#{Pry.view(nest)}* "
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,40 @@
|
|||
class Pry
|
||||
|
||||
# class accessors
|
||||
class << self
|
||||
attr_reader :nesting
|
||||
attr_accessor :last_result
|
||||
attr_accessor :input, :output
|
||||
attr_accessor :commands
|
||||
attr_accessor :default_prompt, :wait_prompt
|
||||
end
|
||||
|
||||
def self.start(target=TOPLEVEL_BINDING, options={})
|
||||
new(options).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.commands = COMMANDS
|
||||
self.default_prompt = DEFAULT_PROMPT
|
||||
self.wait_prompt = WAIT_PROMPT
|
||||
end
|
||||
|
||||
self.reset_defaults
|
||||
|
||||
@nesting = []
|
||||
|
||||
def @nesting.level
|
||||
last.is_a?(Array) ? last.first : nil
|
||||
end
|
||||
end
|
|
@ -0,0 +1,150 @@
|
|||
class Pry
|
||||
|
||||
attr_accessor :input, :output
|
||||
attr_accessor :commands
|
||||
attr_accessor :default_prompt, :wait_prompt
|
||||
|
||||
def initialize(options={})
|
||||
|
||||
options = {
|
||||
:input => Pry.input,
|
||||
:output => Pry.output,
|
||||
:commands => Pry.commands,
|
||||
:default_prompt => Pry.default_prompt,
|
||||
:wait_prompt => Pry.wait_prompt
|
||||
}.merge!(options)
|
||||
|
||||
@input = options[:input]
|
||||
@output = options[:output]
|
||||
@commands = options[:commands]
|
||||
@default_prompt = options[:default_prompt]
|
||||
@wait_prompt = options[:wait_prompt]
|
||||
end
|
||||
|
||||
def nesting
|
||||
self.class.nesting
|
||||
end
|
||||
|
||||
def nesting=(v)
|
||||
self.class.nesting = v
|
||||
end
|
||||
|
||||
# loop
|
||||
def 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")
|
||||
|
||||
break_level = 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 != break_level
|
||||
throw :breakout, break_level
|
||||
end
|
||||
|
||||
target_self
|
||||
end
|
||||
|
||||
# print
|
||||
def rep(target=TOPLEVEL_BINDING)
|
||||
target = binding_for(target)
|
||||
output.print re(target)
|
||||
end
|
||||
|
||||
# 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
|
||||
e
|
||||
end
|
||||
|
||||
# read
|
||||
def r(target=TOPLEVEL_BINDING)
|
||||
target = binding_for(target)
|
||||
eval_string = ""
|
||||
loop do
|
||||
val = input.read(prompt(eval_string, target, nesting.level))
|
||||
eval_string << "#{val.chomp}\n"
|
||||
process_commands(val, eval_string, target)
|
||||
|
||||
break eval_string if valid_expression?(eval_string)
|
||||
end
|
||||
end
|
||||
|
||||
def process_commands(val, eval_string, target)
|
||||
def eval_string.clear() replace("") end
|
||||
|
||||
pattern, action = commands.find { |k, v| Array(k).any? { |a| a === val } }
|
||||
|
||||
if pattern
|
||||
options = {
|
||||
:captures => $~ ? $~.captures : nil,
|
||||
:eval_string => eval_string,
|
||||
:target => target,
|
||||
:val => val,
|
||||
:nesting => nesting,
|
||||
:output => output
|
||||
}
|
||||
|
||||
action.call(options)
|
||||
end
|
||||
end
|
||||
|
||||
def 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
|
||||
|
||||
if RUBY_VERSION =~ /1.9/
|
||||
require 'ripper'
|
||||
|
||||
def valid_expression?(code)
|
||||
!!Ripper::SexpBuilder.new(code).parse
|
||||
end
|
||||
|
||||
else
|
||||
require 'ruby_parser'
|
||||
|
||||
def valid_expression?(code)
|
||||
RubyParser.new.parse(code)
|
||||
rescue Racc::ParseError, SyntaxError
|
||||
false
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
def binding_for(target)
|
||||
if target.is_a?(Binding)
|
||||
target
|
||||
else
|
||||
if target == TOPLEVEL_BINDING.eval('self')
|
||||
TOPLEVEL_BINDING
|
||||
else
|
||||
target.__binding__
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue