Class: Pry::CodeObject

Inherits:
Object show all
Includes:
Helpers::CommandHelpers
Defined in:
lib/pry/code_object.rb

Overview

This class is responsible for taking a string (identifying a command/class/method/etc) and returning the relevant type of object. For example, if the user looks up "show-source" then a Pry::Command will be returned. Alternatively, if the user passes in "Pry#repl" then a Pry::Method object will be returned.

The CodeObject.lookup method is responsible for 1. figuring out what kind of object the user wants (applying precedence rules in doing so -- i.e methods get precedence over commands with the same name) and 2. Returning the appropriate object. If the user fails to provide a string identifer for the object (i.e they pass in nil or "") then the object looked up will be the 'current method' or 'current class' associated with the Binding.

TODO: This class is a clusterfuck. We need a much more robust concept of what a "Code Object" really is. Currently commands/classes/candidates/methods and so on just share a very ill-defined interface.

Defined Under Namespace

Modules: Helpers

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Helpers::CommandHelpers

#absolute_index_number, absolute_index_number, #absolute_index_range, absolute_index_range, #command_error, command_error, #get_method_or_raise, get_method_or_raise, #internal_binding?, internal_binding?, #one_index_number, one_index_number, #one_index_range, one_index_range, #one_index_range_or_number, one_index_range_or_number, #restrict_to_lines, restrict_to_lines, #set_file_and_dir_locals, set_file_and_dir_locals, #temp_file, temp_file, #unindent, unindent

Methods included from Helpers::OptionsHelpers

#method_object, method_object, #method_options, method_options

Constructor Details

#initialize(str, _pry_, options = {}) ⇒ CodeObject

Returns a new instance of CodeObject



58
59
60
61
62
63
64
65
66
67
# File 'lib/pry/code_object.rb', line 58

def initialize(str, _pry_, options={})
  options = {
    :super => 0,
  }.merge!(options)

  @str = str
  @_pry_ = _pry_
  @target = _pry_.current_context
  @super_level = options[:super]
end

Instance Attribute Details

#_pry_Object

Returns the value of attribute pry



55
56
57
# File 'lib/pry/code_object.rb', line 55

def _pry_
  @_pry_
end

#strObject

Returns the value of attribute str



53
54
55
# File 'lib/pry/code_object.rb', line 53

def str
  @str
end

#super_levelObject

Returns the value of attribute super_level



56
57
58
# File 'lib/pry/code_object.rb', line 56

def super_level
  @super_level
end

#targetObject

Returns the value of attribute target



54
55
56
# File 'lib/pry/code_object.rb', line 54

def target
  @target
end

Class Method Details

.lookup(str, _pry_, options = {}) ⇒ Object



45
46
47
48
49
50
# File 'lib/pry/code_object.rb', line 45

def lookup(str, _pry_, options={})
  co = new(str, _pry_, options)

  co.default_lookup || co.method_or_class_lookup ||
    co.command_lookup || co.empty_lookup
end

Instance Method Details

#command_lookupObject



69
70
71
72
73
# File 'lib/pry/code_object.rb', line 69

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

#default_lookupObject

lookup variables and constants and self that are not modules



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/pry/code_object.rb', line 93

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

#empty_lookupObject

when no paramter is given (i.e CodeObject.lookup(nil)), then we lookup the 'current object' from the binding.



77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/pry/code_object.rb', line 77

def empty_lookup
  return nil if str && !str.empty?

  obj = 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

  # respect the super level (i.e user might have specified a
  # --super flag to show-source)
  lookup_super(obj, super_level)
end

#looks_like_an_instance_method?(str) ⇒ Boolean (private)

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#methodstring will see the#as a comment and only evaluate theKlass` part.

Parameters:

  • str (String)

Returns:

  • (Boolean)

    Whether the string looks like an instance method.



138
139
140
# File 'lib/pry/code_object.rb', line 138

def looks_like_an_instance_method?(str)
  str =~ /\S#\S/
end

#lookup_super(obj, super_level) ⇒ Object (private)

grab the nth (super_level) super of `obj

Parameters:

  • obj (Object)
  • super_level (Fixnum)

    How far up the super chain to ascend.



161
162
163
164
165
166
167
168
169
170
# File 'lib/pry/code_object.rb', line 161

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

#method_or_class_lookupObject



114
115
116
117
118
119
120
121
122
123
# File 'lib/pry/code_object.rb', line 114

def method_or_class_lookup
  obj = case str
        when /\S+\(\)\z/
          Pry::Method.from_str(str.sub(/\(\)\z/, ''),target) || Pry::WrappedModule.from_str(str, target)
        else
          Pry::WrappedModule.from_str(str,target) || Pry::Method.from_str(str, target)
        end

  lookup_super(obj, super_level)
end

#safe_to_evaluate?(str) ⇒ Boolean (private)

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

Parameters:

  • str (String)

    The string to lookup

Returns:

  • (Boolean)


148
149
150
151
152
# File 'lib/pry/code_object.rb', line 148

def safe_to_evaluate?(str)
  return true if str.strip == "self"
  kind = target.eval("defined?(#{str})")
  kind =~ /variable|constant/
end

#sourcable_object?(obj) ⇒ Boolean (private)

Returns:

  • (Boolean)


127
128
129
# File 'lib/pry/code_object.rb', line 127

def sourcable_object?(obj)
  [::Proc, ::Method, ::UnboundMethod].any? { |o| obj.is_a?(o) }
end

#target_selfObject (private)



154
155
156
# File 'lib/pry/code_object.rb', line 154

def target_self
  target.eval('self')
end