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:
John Mair 2010-12-26 02:59:37 +13:00
parent f11806d2da
commit 6b3a6871fc
5 changed files with 238 additions and 213 deletions

View File

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

View File

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

17
lib/pry/prompts.rb Normal file
View File

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

40
lib/pry/pry_class.rb Normal file
View File

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

150
lib/pry/pry_instance.rb Normal file
View File

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