WhyChain

A tiny gem to inspect Ruby method dispatch at runtime.

WhyChain helps you see:

  • method lookup chain (ancestors)
  • method owner resolution
  • where super would resolve next

Built for learning and debugging Ruby internals. Not a production framework.

You can inspect this manually in Ruby console, but WhyChain gives you a consistent, teachable trace in one call.

Installation

Add the gem to your Gemfile:

gem "why_chain"

Then run:

bundle install

Quick start

trace = WhyChain.trace(object, :method_name)
pp trace.to_h

trace is a WhyChain::DispatchTrace object with readers:

  • lookup_chain
  • owner
  • next_super_owner

As hash:

trace.to_h
# {
  lookup_chain: [...],
  owner: SomeClassOrModule,
  next_super_owner: AnotherClassOrModule
# }

Usage examples

1) prepend vs include in runtime lookup

module P
  def foo = :p
end

module I
  def foo = :i
end

class A
  def foo = :a
end

class B < A
  include I
  prepend P
end

trace = WhyChain.trace(B.new, :foo)
pp trace.to_h
# {
#   lookup_chain: [P, B, I, A, Object, Kernel, BasicObject],
#   owner: P,
#   next_super_owner: I
# }

2) Singleton method takes precedence

obj = Object.new
def obj.single_foo = :singleton

trace = WhyChain.trace(obj, :single_foo)
pp trace.to_h
# {
#   lookup_chain: [#<Class:#<Object:...>>, Object, Kernel, BasicObject],
#   owner: #<Class:#<Object:...>>,
#   next_super_owner: nil
# }

3) Missing method fails fast

WhyChain.trace(Object.new, :not_existing_method)
# raises NameError

Note: some entries in lookup_chain can appear as anonymous classes/modules (for example singleton classes). This is expected and reflects Ruby runtime internals.

Development

Run tests:

bundle exec rspec

Run lint:

bundle exec rubocop

Contributing

Bug reports and pull requests are welcome on GitHub: https://github.com/alessio-salati/why_chain

License

The gem is available as open source under the terms of the MIT License.