1
0
Fork 0
mirror of https://github.com/pry/pry.git synced 2022-11-09 12:35:05 -05:00

bunch of random refactorings to different commands

This commit is contained in:
John Mair 2013-01-02 02:06:51 +01:00
parent dcdea09e9e
commit 4d384737a7
4 changed files with 94 additions and 43 deletions

View file

@ -67,12 +67,12 @@ class Pry
# lookup variables and constants that are not modules # lookup variables and constants that are not modules
def default_lookup def default_lookup
if str !~ /\S#\S/ && target.eval("defined? #{str} ") =~ /variable|constant/ if variable_or_constant?(str)
obj = target.eval(str) obj = target.eval(str)
# restrict to only objects we KNOW for sure support the full API # restrict to only objects we KNOW for sure support the full API
# Do NOT support just any object that responds to source_location # Do NOT support just any object that responds to source_location
if [::Proc, ::Method, ::UnboundMethod].any? { |o| obj.is_a?(o) } if sourcable_object?(obj)
Pry::Method(obj) Pry::Method(obj)
elsif !obj.is_a?(Module) elsif !obj.is_a?(Module)
Pry::WrappedModule(obj.class) Pry::WrappedModule(obj.class)
@ -98,17 +98,39 @@ class Pry
Pry::Method.from_str(str,target) || Pry::WrappedModule.from_str(str, target) Pry::Method.from_str(str,target) || Pry::WrappedModule.from_str(str, target)
end end
sup = obj.super(super_level) if obj lookup_super(obj, super_level)
if obj && !sup end
private
def sourcable_object?(obj)
[::Proc, ::Method, ::UnboundMethod].any? { |o| obj.is_a?(o) }
end
# Whether `str` represents a variable (or constant) when looked up
# in the context of the `target` binding. This is used to
# distinguish it from methods or expressions.
# @param [String] str The string to lookup
def variable_or_constant?(str)
str !~ /\S#\S/ && target.eval("defined? #{str} ") =~ /variable|constant/
end
def target_self
target.eval('self')
end
# grab the nth (`super_level`) super of `obj
# @param [Object] obj
# @param [Fixnum] super_level How far up the super chain to ascend.
def lookup_super(obj, super_level)
return nil if !obj
sup = obj.super(super_level)
if !sup
raise Pry::CommandError, "No superclass found for #{obj.wrapped}" raise Pry::CommandError, "No superclass found for #{obj.wrapped}"
else else
sup sup
end end
end end
private
def target_self
target.eval('self')
end
end end
end end

View file

@ -1,36 +1,37 @@
require 'forwardable'
class Pry class Pry
class Command::Edit class Command::Edit
class MethodPatcher class MethodPatcher
attr_accessor :method_object extend Forwardable
attr_accessor :target
attr_accessor :_pry_ def_delegators :@edit_context, :code_object, :target, :_pry_
def initialize(edit_context) def initialize(edit_context)
@method_object = edit_context.code_object @edit_context = edit_context
@target = edit_context.target
@_pry_ = edit_context._pry_
end end
# perform the patch # perform the patch
def perform_patch def perform_patch
source = wrap_for_nesting(wrap_for_owner(Pry::Editor.edit_tempfile_with_content(adjusted_lines))) if code_object.alias?
if method_object.alias?
with_method_transaction do with_method_transaction do
_pry_.evaluate_ruby source _pry_.evaluate_ruby patched_code
Pry.binding_for(method_object.owner).eval("alias #{method_object.name} #{method_object.original_name}")
end end
else else
_pry_.evaluate_ruby source _pry_.evaluate_ruby patched_code
end end
end end
private private
def patched_code
@patched_code ||= wrap(Pry::Editor.edit_tempfile_with_content(adjusted_lines))
end
# The method code adjusted so that the first line is rewritten # The method code adjusted so that the first line is rewritten
# so that def self.foo --> def foo # so that def self.foo --> def foo
def adjusted_lines def adjusted_lines
lines = method_object.source.lines.to_a lines = code_object.source.lines.to_a
lines[0] = definition_line_for_owner(lines.first) lines[0] = definition_line_for_owner(lines.first)
lines lines
end end
@ -45,12 +46,13 @@ class Pry
# @param [String] meth_name The method name before aliasing # @param [String] meth_name The method name before aliasing
# @param [Module] target The owner of the method # @param [Module] target The owner of the method
def with_method_transaction def with_method_transaction
target = Pry.binding_for(method_object.owner) target = owner_binding
temp_name = "__pry_#{method_object.original_name}__" temp_name = "__pry_#{code_object.original_name}__"
target.eval("alias #{temp_name} #{method_object.original_name}") target.eval("alias #{temp_name} #{code_object.original_name}")
yield yield
target.eval("alias #{method_object.original_name} #{temp_name}") target.eval("alias #{code_object.name} #{code_object.original_name}")
target.eval("alias #{code_object.original_name} #{temp_name}")
ensure ensure
target.eval("undef #{temp_name}") rescue nil target.eval("undef #{temp_name}") rescue nil
end end
@ -68,13 +70,26 @@ class Pry
# @param String The original definition line. e.g. def self.foo(bar, baz=1) # @param String The original definition line. e.g. def self.foo(bar, baz=1)
# @return String The new definition line. e.g. def foo(bar, baz=1) # @return String The new definition line. e.g. def foo(bar, baz=1)
def definition_line_for_owner(line) def definition_line_for_owner(line)
if line =~ /^def (?:.*?\.)?#{Regexp.escape(method_object.original_name)}(?=[\(\s;]|$)/ if line =~ /^def (?:.*?\.)?#{Regexp.escape(code_object.original_name)}(?=[\(\s;]|$)/
"def #{method_object.original_name}#{$'}" "def #{code_object.original_name}#{$'}"
else else
raise CommandError, "Could not find original `def #{method_object.original_name}` line to patch." raise CommandError, "Could not find original `def #{code_object.original_name}` line to patch."
end end
end end
# Provide a binding for the `code_object`'s owner context.
# @return [Binding]
def owner_binding
Pry.binding_for(code_object.owner)
end
# Apply wrap_for_owner and wrap_for_nesting successively to `source`
# @param [String] source
# @return [String] The wrapped source.
def wrap(source)
wrap_for_nesting(wrap_for_owner(source))
end
# Update the source code so that when it has the right owner when eval'd. # Update the source code so that when it has the right owner when eval'd.
# #
# This (combined with definition_line_for_owner) is backup for the case that # This (combined with definition_line_for_owner) is backup for the case that
@ -84,7 +99,7 @@ class Pry
# @param [String] source The source to wrap # @param [String] source The source to wrap
# @return [String] # @return [String]
def wrap_for_owner(source) def wrap_for_owner(source)
Thread.current[:__pry_owner__] = method_object.owner Thread.current[:__pry_owner__] = code_object.owner
source = "Thread.current[:__pry_owner__].class_eval do\n#{source}\nend" source = "Thread.current[:__pry_owner__].class_eval do\n#{source}\nend"
end end
@ -101,7 +116,7 @@ class Pry
# @param [String] source The source to wrap. # @param [String] source The source to wrap.
# @return [String] # @return [String]
def wrap_for_nesting(source) def wrap_for_nesting(source)
nesting = Pry::Code.from_file(method_object.source_file).nesting_at(method_object.source_line) nesting = Pry::Code.from_file(code_object.source_file).nesting_at(code_object.source_line)
(nesting + [source] + nesting.map{ "end" } + [""]).join("\n") (nesting + [source] + nesting.map{ "end" } + [""]).join("\n")
rescue Pry::Indent::UnparseableNestingError => e rescue Pry::Indent::UnparseableNestingError => e

View file

@ -44,19 +44,11 @@ class Pry
"#{@file} @ line #{@line} #{@method && @method.name_with_owner}" "#{@file} @ line #{@line} #{@method && @method.name_with_owner}"
end end
def nothing_to_do?
opts.quiet? && (internal_binding?(target) || !code?)
end
def process def process
if nothing_to_do? if nothing_to_do?
return return
elsif internal_binding?(target) elsif internal_binding?(target)
if target_self == TOPLEVEL_BINDING.eval("self") handle_internal_binding
output.puts "At the top level."
else
output.puts "Inside #{Pry.view_clip(target_self)}."
end
return return
end end
@ -69,6 +61,22 @@ class Pry
private private
def nothing_to_do?
opts.quiet? && (internal_binding?(target) || !code?)
end
def top_level?
target_self == TOPLEVEL_BINDING.eval("self")
end
def handle_internal_binding
if top_level?
output.puts "At the top level."
else
output.puts "Inside #{Pry.view_clip(target_self)}."
end
end
def show_method? def show_method?
args.empty? && @method && @method.source? && @method.source_range.count < 20 && args.empty? && @method && @method.source? && @method.source_range.count < 20 &&
# These checks are needed in case of an eval with a binding and file/line # These checks are needed in case of an eval with a binding and file/line

View file

@ -32,10 +32,16 @@ class Pry
if opts.verbose? if opts.verbose?
output.puts Pry::Code.new(_pry_.last_exception.backtrace, 0, :text).with_line_numbers.to_s output.puts Pry::Code.new(_pry_.last_exception.backtrace, 0, :text).with_line_numbers.to_s
else else
output.puts Pry::Code.new(_pry_.last_exception.backtrace.first([captures[0].size, 0.5].max * 10), 0, :text).with_line_numbers.to_s output.puts Pry::Code.new(_pry_.last_exception.backtrace.first(size_of_backtrace), 0, :text).with_line_numbers.to_s
end
end end
end end
Pry::Commands.add_command(Pry::Command::Wtf) private
def size_of_backtrace
[captures[0].size, 0.5].max * 10
end
end
Pry::Commands.add_command(Pry::Command::Wtf)
end end