Question

How to Find Where a Method Is Defined at Runtime in Ruby

rubyruby-on-railsruntimemethodsdefinition

Question

In Ruby, is there a way at runtime to determine where a method was defined, including the file path and line number?

For example, imagine a Rails application where a gem overrides a method on String, and that override only causes a failure in a specific runtime environment. In that situation, simply knowing that the method belongs to String is not enough—I need to know which file actually defined the active method implementation.

I am looking for something conceptually like this:

whereami(:foo) # => "/path/to/file.rb:45"

The source may come from Ruby itself, my application, Rails, or an installed gem, so searching the project for def foo is not reliable. If multiple methods with the same name exist, I want to know which one Ruby is actually calling at runtime.

Short Answer

By the end of this page, you will understand how Ruby can reveal where a method came from at runtime, including its source file and line number when available. You will also learn the difference between instance methods and singleton methods, how overridden methods affect lookup, and which tools help when source_location is not enough.

Concept

Ruby treats methods as real runtime objects. That means you can often inspect a method after Ruby has loaded it and ask questions like:

  • Which object owns this method?
  • Which class or module defined it?
  • What file and line number did it come from?

The key idea is that Ruby method lookup happens dynamically. A method such as String#foo may have been:

  • defined in the original class
  • added by reopening the class later
  • mixed in from a module
  • overridden by a gem
  • defined on a single object only

Because of that, the active method implementation is not always obvious from reading source files. What matters is the method Ruby will actually call at runtime.

In modern Ruby, the most direct tool is source_location, available on Method and UnboundMethod objects. It returns:

  • an array like ['/path/to/file.rb', 45] for Ruby-defined methods
  • nil for many methods implemented in C or built into Ruby

This matters in real programming because debugging monkey patches, Rails autoloading issues, gem conflicts, and environment-specific bugs often depends on finding the exact method implementation Ruby is using.

Mental Model

Think of Ruby method lookup like following directions through a stack of sticky notes.

  • A class starts with its own methods.
  • Gems or your app can add new sticky notes later by reopening the class.
  • Modules can insert more sticky notes into the lookup chain.
  • Ruby reads from the top of that stack when deciding which method to run.

source_location is like asking Ruby: "Which sticky note are you currently reading, and where was it written?"

That is why checking the active runtime method is more useful than searching for every def foo in a codebase.

Take Quiz

Syntax and Examples

The basic pattern is to get a Method or UnboundMethod object, then call source_location.

Inspect an instance method on a specific object

text = "hello"
method_obj = text.method(:upcase)

p method_obj.owner
p method_obj.source_location

Possible output:

String
nil

nil means the method may be implemented in C rather than Ruby source.

Inspect a Ruby-defined method

class String
  def loud_greeting
    "HEY #{self.upcase}!"
  end
end

text = "world"
method_obj = text.method(:loud_greeting)

p method_obj.owner
p method_obj.source_location

Possible output:

String
["/my/app/models/extensions/string_patch.rb", 2]

Inspect an instance method from a class directly

unbound = String.instance_method(:loud_greeting)
p unbound.owner
p unbound.source_location

This is useful when you want to inspect the method definition without needing an instance.

Inspect a class method

class User
  def self.build_guest
    new
  end
end

p User.method(:build_guest).source_location

Helpful debugging pattern

obj = "test"
name = :some_method

if obj.respond_to?(name)
  m = obj.method(name)
  puts "Owner: #{m.owner}"
  p m.source_location
else
  puts "Method not found"
end

This lets you inspect the exact method an object will call at runtime.

Step by Step Execution

Consider this example:

module ExtraStringMethods
  def shout
    "#{upcase}!"
  end
end

class String
  include ExtraStringMethods
end

s = "hello"
m = s.method(:shout)

p m.owner
p m.source_location
puts m.call

Step by step:

  1. ExtraStringMethods defines shout.
  2. String includes that module.
  3. s = "hello" creates a String object.
  4. s.method(:shout) asks Ruby for the actual method object that s will use.
  5. m.owner shows where Ruby found the method, likely ExtraStringMethods.
  6. m.source_location returns the file and line where shout was defined.
  7. m.call runs the method and prints HELLO!.

Example output might be:

ExtraStringMethods
["/my/app/lib/extra_string_methods.rb", 2]
HELLO!

This is important because the method is available on String, but it was not originally defined in String itself. It came from an included module.

Real World Use Cases

Here are common situations where runtime method location is useful:

Debugging monkey patches

A gem reopens String, Array, or another core class and changes behavior. You can inspect the active method to find the patch file.

Investigating Rails load-order issues

In Rails apps, environment-specific loading can cause one method definition to override another. Checking the runtime method tells you which version won.

Finding gem conflicts

Two gems may define the same method name. source_location helps identify which gem is currently providing the method.

Understanding metaprogramming

Frameworks often create methods dynamically. Inspecting methods at runtime helps confirm what actually exists.

Production debugging

When behavior differs between development, test, and production, runtime inspection can reveal different code paths or loaded extensions.

Take Quiz

Real Codebase Usage

In real Ruby projects, developers usually combine source_location with a few other inspection tools.

Pattern: print owner and source together

m = some_object.method(:foo)
puts "owner: #{m.owner}"
p m.source_location

Why this helps:

  • owner tells you which class or module supplied the method.
  • source_location tells you where it was written.

Pattern: guard against missing methods

if some_object.respond_to?(:foo)
  m = some_object.method(:foo)
  p m.source_location
end

This avoids raising NameError when the method does not exist.

Pattern: inspect method lookup chain

If the result is surprising, check ancestors:

p some_object.class.ancestors

This shows modules and parent classes involved in lookup.

Pattern: inspect class vs instance methods correctly

String.instance_method(:upcase)
String.method(:new)

Developers often use the wrong one when debugging.

Pattern: use in logs or temporary debug scripts

In a Rails console or temporary debug task:

obj = "abc"
m = obj.method(:some_overridden_method)
Rails.logger.debug("#{m.owner} #{m.source_location.inspect}")

This is especially useful for environment-specific issues.

Common Mistakes

Mistake 1: Calling source_location on the result instead of the method

Broken code:

"abc".upcase.source_location

Why it fails:

  • "abc".upcase returns a string result, not a method object.

Correct code:

"abc".method(:upcase).source_location

Mistake 2: Confusing class methods with instance methods

Broken code:

String.method(:upcase).source_location

Why it is wrong:

  • upcase is an instance method on String, not a class method.

Correct code:

String.instance_method(:upcase).source_location
# or
"abc".method(:upcase).source_location

Mistake 3: Expecting every method to have a file and line number

p "abc".method(:upcase).source_location
# => nil

This is normal for many built-in methods implemented in C.

Mistake 4: Assuming owner is the same as the receiver's class

module M
  def foo
    1
  end
end

class A
  include M
end

p A.new.method(:foo).owner
# => M

The object is an A, but the method owner is M.

Mistake 5: Ignoring dynamic method handling

Methods handled through method_missing may not have a normal definition to inspect. In those cases, inspect method_missing itself and the object's class behavior.

obj.method(:unknown_name) # may raise NameError

If a class relies on method_missing, you may need to inspect:

obj.method(:method_missing).source_location

Comparisons

ToolWhat it tells youBest use
method(:name)Gets the bound method for a specific objectFind what this object will call
instance_method(:name)Gets an unbound instance method from a classInspect class instance methods without an object
ownerClass or module that owns the methodSee whether a module or patch supplied it
source_locationFile and line number for Ruby-defined methodsFind the actual source file
ancestorsMethod lookup chain for a classUnderstand why one implementation wins
grep 'def foo'Text matches in filesQuick search, but not reliable for runtime truth

method vs instance_method

"abc".method(:upcase)          # bound to one object
String.instance_method(:upcase) # from the class

Use method when you care about what a particular object will run.

Use instance_method when you want to inspect the class definition itself.

owner vs source_location

  • owner answers: "Which class or module provides this method?"
  • source_location answers: "Where in source code was it defined?"

For debugging overrides, you often want both.

Take Quiz

Cheat Sheet

# Instance method on an object
m = obj.method(:foo)
m.owner
m.source_location   # => ["/path/file.rb", 12] or nil

# Instance method from a class
um = MyClass.instance_method(:foo)
um.owner
um.source_location

# Class method
m = MyClass.method(:bar)
m.owner
m.source_location

# Check whether method exists first
obj.respond_to?(:foo)

# See lookup chain
obj.class.ancestors

Rules to remember:

  • Use obj.method(:name) for methods called on an object.
  • Use Class.instance_method(:name) for instance methods defined on a class.
  • Use Class.method(:name) for class methods.
  • source_location returns [file, line] for Ruby methods.
  • source_location often returns nil for C-implemented methods.
  • owner may be a module, not the object's class.
  • For overridden methods, inspect the active method at runtime, not just source files.

FAQ

How do I find the file where a Ruby method is defined?

Use obj.method(:name).source_location for an instance method or Class.method(:name).source_location for a class method.

Why does source_location return nil in Ruby?

It usually means the method is implemented in C or otherwise does not have Ruby source location information.

How can I tell which gem overrode a Ruby method?

Inspect the active method at runtime with source_location and owner. The file path often points into the gem directory.

What is the difference between owner and source_location?

owner tells you the class or module providing the method. source_location tells you the file and line where it was defined.

Can I inspect instance methods without creating an object?

Yes. Use MyClass.instance_method(:method_name).

How do I debug a monkey-patched core class in Ruby?

Get the current method object from a real instance, then inspect owner, source_location, and the class ancestors chain.

Does this work for methods created dynamically?

Sometimes. If Ruby created a real method, you can often inspect it. If behavior relies on method_missing, there may not be a normal method definition to locate.

Take Quiz

Mini Project

Description

Build a small Ruby debugging helper that reports where a method comes from at runtime. This mirrors a real debugging task in Rails or gem-heavy applications where a method may be overridden by application code, a module, or a third-party library.

Goal

Create a helper that prints a method's owner and source location for both instance methods and class methods.

Requirements

  • Create a Ruby class or module with at least one custom method.
  • Add a second method through a mixin or reopened class.
  • Write a helper that accepts an object and method name.
  • Print whether the method exists, its owner, and its source location.
  • Demonstrate the helper on both a normal object method and a class method.
Take Quiz

Keep learning

Related questions

View more