Module: ObjectShadow::MethodIntrospection

Included in:
ObjectShadow
Defined in:
lib/object_shadow/method_introspection.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.get_method(object, target, method_name, unbind) ⇒ Object



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/object_shadow/method_introspection.rb', line 184

def get_method(object, target, method_name, unbind)
  case target
  when :self
    if unbind
      object.method(method_name).unbind()
    else
      object.method(method_name)
    end
  when :class
    if unbind
      object.class.method(method_name).unbind()
    else
      object.class.method(method_name)
    end
  when :instances
    object.instance_method(method_name)
  else
    Kernel.raise ArgumentError, "(ObjectShadow) target: must be one of [:self, :class, :instances]"
  end
rescue NameError
  nil
end

.lookup_chain_for(object, target, inherit, optimize = false) ⇒ Object



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/object_shadow/method_introspection.rb', line 153

def lookup_chain_for(object, target, inherit, optimize = false)
  validate_arguments! object, target, inherit
  singleton, klass, chain = get_singleton_klass_and_chain(object, target)

  case inherit
  when :singleton
    singleton
  when :self, false
    singleton + klass
  when :exclude_class
    singleton + chain[0...(chain.index(Class) || chain.index(Module) || chain.index(Object))]
  when :exclude_object
    singleton + chain[0...chain.index(Object)]
  when Module
    singleton + chain[0..chain.index(inherit)]
  when :all, true
    if optimize # full chain build by Ruby using (all=true) param in list
      singleton + klass
    else
      singleton + chain
    end
  end
end

.simple_lookup_chain_for(object, target) ⇒ Object



177
178
179
180
181
182
# File 'lib/object_shadow/method_introspection.rb', line 177

def simple_lookup_chain_for(object, target)
  validate_arguments! object, target
  singleton, klass, = get_singleton_klass_and_chain(object, target)

  singleton + klass
end

Instance Method Details

#method(method_name, target: :self, unbind: false, all: false) ⇒ Object

Returns the objectified reference to a method

  • target: must be one of [:self, :class, :instances]

Pass unbind: true if you always want UnboundMethod objects

Pass all: true to not only get the method that would be called, but an Array with every occurrence of this method along the inheritance chain



130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/object_shadow/method_introspection.rb', line 130

def method(method_name, target: :self, unbind: false, all: false)
  if all
    MethodIntrospection.lookup_chain_for(object, target, :all).map{ |lookup_class|
      if  lookup_class.instance_methods(false).include?(method_name) ||
          lookup_class.private_instance_methods(false).include?(method_name)
        lookup_class.instance_method(method_name)
      end
    }.compact
  else
    MethodIntrospection.get_method(object, target, method_name, unbind)
  end
end

#method?(method_name, target: :self) ⇒ Boolean

Returns true if a method of this name is defined First parameter is the name of the method in question

  • target: must be one of [:self, :class, :instances]

Returns:

  • (Boolean)


76
77
78
79
80
81
82
83
84
85
86
# File 'lib/object_shadow/method_introspection.rb', line 76

def method?(method_name, target: :self)
  MethodIntrospection.simple_lookup_chain_for(object, target).any?{ |lookup_class|
    if RUBY_VERSION >= "2.6.0"
      lookup_class.method_defined?(method_name, true) ||
      lookup_class.private_method_defined?(method_name, true)
    else
      lookup_class.method_defined?(method_name) ||
      lookup_class.private_method_defined?(method_name)
    end
  }
end

#method_lookup_chain(target: :self, inherit: :exclude_class) ⇒ Object

Returns the lookup/ancestor chain for an object

  • target: must be one of [:self, :class, :instances]

Takes the same inherit options like #methods



148
149
150
# File 'lib/object_shadow/method_introspection.rb', line 148

def method_lookup_chain(target: :self, inherit: :exclude_class)
  MethodIntrospection.lookup_chain_for(object, target, inherit)
end

#method_scope(method_name, target: :self) ⇒ Object

Returns the scope of method name given

  • target: must be one of [:self, :class, :instances]

Possible return values: [:public, :protected, :private, nil]



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/object_shadow/method_introspection.rb', line 94

def method_scope(method_name, target: :self)
  MethodIntrospection.simple_lookup_chain_for(object, target).map{ |lookup_class|
    if RUBY_VERSION >= "2.6.0"
      case
      when lookup_class.public_method_defined?(method_name, true)
        :public
      when lookup_class.protected_method_defined?(method_name, true)
        :protected
      when lookup_class.private_method_defined?(method_name, true)
        :private
      else
        nil
      end
    else
      case
      when lookup_class.public_method_defined?(method_name)
        :public
      when lookup_class.protected_method_defined?(method_name)
        :protected
      when lookup_class.private_method_defined?(method_name)
        :private
      else
        nil
      end
    end
  }.compact.first
end

#methods(target: :self, scope: :public, inherit: :exclude_class) ⇒ Object

#shadow#methods returns a sorted list of methods related to the object in question. It lets you specify the kind of methods you want to retrieve by the following keyword parameters:

target: (default :self)

  • :self - This returns the list of methods available to call

    on the current object, including singleton methods
    If the object is a class/module, this means that it
    will return class methods
    
  • :class - This will refer to the object’s class (via the ‘class`) method

    and return its methods, usually to be called from an instance
    If called for a class or module, it will return `Class`' methods
    
  • :instances - This will list all methods which instances of the class (or the class

    that includes the module, in case of a module) in question will have
    Raises an ArgumentError when called on with a non-`Module`
    

scope: (default :public)

  • :public - Restrict to to methods of public visibility

  • :protected - Restrict to to methods of protected visibility

  • :private - Restrict to to methods of private visibility

  • :all - Restrict to to methods of public visibility

inherit: (default :exclude_object)

  • :singleton - Show only methods directly defined in the object’s singleton class

  • :self - Show singleton methods and methods directly defined in the object’s class,

    but do not traverse the inheritance chain
    
  • :exclude_class - Stop inheritance chain just before Class or Module. For

    non-modules it fallbacks to :exclude_object
    
  • :exclude_object - Stop inheritance chain just before Object

  • :all - Show methods from the whole inheritance chain



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/object_shadow/method_introspection.rb', line 50

def methods(target: :self, scope: :public, inherit: :exclude_class)
  MethodIntrospection.lookup_chain_for(object, target, inherit, true).flat_map { |lookup_class|
    full_inheritance_lookup = inherit == :all || inherit == true

    case scope
    when :public
      lookup_class.public_instance_methods(full_inheritance_lookup)
    when :protected
      lookup_class.protected_instance_methods(full_inheritance_lookup)
    when :private
      lookup_class.private_instance_methods(full_inheritance_lookup)
    when :all
      lookup_class.instance_methods(full_inheritance_lookup) +
      lookup_class.private_instance_methods(full_inheritance_lookup)
    else
      Kernel.raise ArgumentError, \
        "(ObjectShadow) Method scope: must be one of [:public, :protected, :private, :all]"
    end
  }.uniq.sort
end