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



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

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



77
78
79
# File 'lib/pry/code_object.rb', line 77

def _pry_
  @_pry_
end

#strObject

Returns the value of attribute str



75
76
77
# File 'lib/pry/code_object.rb', line 75

def str
  @str
end

#super_levelObject

Returns the value of attribute super_level



78
79
80
# File 'lib/pry/code_object.rb', line 78

def super_level
  @super_level
end

#targetObject

Returns the value of attribute target



76
77
78
# File 'lib/pry/code_object.rb', line 76

def target
  @target
end

Class Method Details

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



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

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



91
92
93
94
95
# File 'lib/pry/code_object.rb', line 91

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



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/pry/code_object.rb', line 115

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.



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

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.



160
161
162
# File 'lib/pry/code_object.rb', line 160

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.



184
185
186
187
188
189
190
191
192
193
# File 'lib/pry/code_object.rb', line 184

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



136
137
138
139
140
141
142
143
144
145
# File 'lib/pry/code_object.rb', line 136

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)


170
171
172
173
174
175
# File 'lib/pry/code_object.rb', line 170

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

#sourcable_object?(obj) ⇒ Boolean (private)

Returns:

  • (Boolean)


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

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

#target_selfObject (private)



177
178
179
# File 'lib/pry/code_object.rb', line 177

def target_self
  target.eval('self')
end