1
0
Fork 0
mirror of https://github.com/pry/pry.git synced 2022-11-09 12:35:05 -05:00
pry--pry/lib/pry/code_object.rb
John Mair 470c938210 Pry::CodeObject, Pry::WrappedModule: introduce safe_to_evaluate? method
Unsure where to put safe_to_evaluate? method, so it's currently duplicated in
both the mentioned modules. If we can simply switch to a defined?(str) != "method" test
then we could put the method on Pry::Method.looks_like_a_method?(str, binding) and call it from both locations, avoiding duplication.

https://www.evernote.com/shard/s130/sh/4e839419-387e-43ab-81d5-06f87aa2cbac/2c640432e3ecccb2035c69c347f63af1
2013-01-06 00:16:44 +01:00

154 lines
4.3 KiB
Ruby

class Pry
class CodeObject
module Helpers
# we need this helper as some Pry::Method objects can wrap Procs
# @return [Boolean]
def real_method_object?
is_a?(::Method) || is_a?(::UnboundMethod)
end
def c_method?
real_method_object? && source_type == :c
end
def module_with_yard_docs?
is_a?(WrappedModule) && yard_docs?
end
def command?
is_a?(Module) && self <= Pry::Command
end
end
include Pry::Helpers::CommandHelpers
class << self
def lookup(str, target, _pry_, options={})
co = new(str, target, _pry_, options)
co.default_lookup || co.method_or_class_lookup ||
co.command_lookup || co.binding_lookup
end
end
attr_accessor :str
attr_accessor :target
attr_accessor :pry
attr_accessor :super_level
def initialize(str, target, _pry_, options={})
options = {
:super => 0
}.merge!(options)
@str = str
@target = target
@pry = _pry_
@super_level = options[:super]
end
def command_lookup
# TODO: just make it so find_command_by_match_or_listing doesn't
# raise?
pry.commands.find_command_by_match_or_listing(str) rescue nil
end
# extract the object from the binding
def binding_lookup
return nil if str && !str.empty?
if internal_binding?(target)
mod = target_self.is_a?(Module) ? target_self : target_self.class
Pry::WrappedModule(mod)
else
Pry::Method.from_binding(target)
end
end
# lookup variables and constants and `self` that are not modules
def default_lookup
# we skip instance methods as we want those to fall through to method_or_class_lookup()
if safe_to_evaluate?(str) && !looks_like_an_instance_method?(str)
obj = target.eval(str)
# restrict to only objects we KNOW for sure support the full API
# Do NOT support just any object that responds to source_location
if sourcable_object?(obj)
Pry::Method(obj)
elsif !obj.is_a?(Module)
Pry::WrappedModule(obj.class)
else
nil
end
end
rescue Pry::RescuableException
nil
end
def method_or_class_lookup
# we need this here because stupid Pry::Method.from_str() does a
# Pry::Method.from_binding when str is nil.
# Once we refactor Pry::Method.from_str() so it doesnt lookup
# from bindings, we can get rid of this check
return nil if str.to_s.empty?
obj = if str =~ /::(?:\S+)\Z/
Pry::WrappedModule.from_str(str,target) || Pry::Method.from_str(str, target)
else
Pry::Method.from_str(str,target) || Pry::WrappedModule.from_str(str, target)
end
lookup_super(obj, super_level)
end
private
def sourcable_object?(obj)
[::Proc, ::Method, ::UnboundMethod].any? { |o| obj.is_a?(o) }
end
# Returns true if `str` looks like a method, i.e Klass#method
# We need to consider this case because method lookups should fall
# through to the `method_or_class_lookup()` method but a
# defined?() on a "Klass#method` string will see the `#` as a
# comment and only evaluate the `Klass` part.
# @param [String] str
# @return [Boolean] Whether the string looks like an instance method.
def looks_like_an_instance_method?(str)
str =~ /\S#\S/
end
# We use this method to decide whether code is safe to eval. Method's are
# generally not, but everything else is.
# TODO: is just checking != "method" enough??
# TODO: see duplication of this method in Pry::WrappedModule
# @param [String] str The string to lookup
# @return [Boolean]
def safe_to_evaluate?(str)
return true if str.strip == "self"
kind = target.eval("defined?(#{str})")
kind =~ /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}"
else
sup
end
end
end
end