Suppose `D` inherits from `C`, `C` includes module `M`, and only `M` defines `report`. Calling `D.new.report` works: Ruby searches `D`, then `C`, then `M`, where it finds the method. The object does not store a copy of `report`; it follows a path through classes and modules that hold method definitions. The search stops at the first match. section 4.2.1 section 4.2
Listing 4.6 Demonstration of module inclusion and inheritance
module M
def report
puts "'report' method in module M"
end
end
class C
include M
end
class D < C
end
obj = D.new
obj.report
Run this small example, then add a `report` definition to `C` or `D` to see which definition wins. section 4.2.1
For an ordinary instance, the search order follows these rules:
- Search modules prepended to its class, most recently prepended first; then search the class itself. section 4.2.5
- Search modules included in the class, most recently included first. Repeat the prepend–class–include sequence for each superclass, continuing through `Object`, its `Kernel` mixin, and `BasicObject`. section 4.2.5
- Use the first matching definition. Defining a method again *within the same class or module* replaces its earlier definition; defining the same name at different points on the path leaves multiple definitions, of which the first is called. section 4.2.2
That order makes `include` and `prepend` importantly different. A class method takes precedence over a method in a module it includes; a prepended module takes precedence even over the class. When two included modules define the same name, the later inclusion is searched first. Including the same module twice in a class does not add it twice, but prepending an already included module can place it before the class as well. section 4.2.2 section 4.2.4
There is another stop before the object's ordinary class: its singleton class. A method defined for just that object lives there, and modules included in that singleton class are searched before the ordinary class. `extend` adds a module at this object-specific level. Consequently, an object can acquire an overriding method without changing other instances. section 4.2.5 section 13.1.3
Continue past the first match
If `C#report` overrides `M#report`, a call to `super` inside `C#report` invokes the next `report` on the path: `M#report`. This lets an override wrap or supplement existing behavior. Bare `super` forwards the current arguments; `super()` forwards none. The same pattern lets a subclass adjust its initialization while retaining its superclass's setup. section 4.2.6
To investigate a surprising result, inspect a class's `ancestors` for its class-and-module order, or inspect an individual object's `singleton_class.ancestors` to include its singleton level. `obj.method(:name)` identifies the selected definition; its `super_method` finds the next one, returning `nil` when none remains. `obj.methods` answers a different question: it lists callable methods but flattens away where they came from. If lookup finds no matching method, `method_missing` handles the unmatched message; a custom implementation can use `super` to pass unhandled names onward. section 13.1.3 section 4.2.7 section 7.7.1 section 4.3.1
