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:
parent
dcdea09e9e
commit
4d384737a7
4 changed files with 94 additions and 43 deletions
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Reference in a new issue