In strictly lexically/statically scoped languages like C++ or Java, identifiers are resolved by simply checking the current scope, ascending one scope higher and repeating until the base most scope is reached. For example: if your example were C++, LEGS would be searched for first in the calling class Bird/Oyster, then Animal, then My Animal.
Ruby has a kind of dynamic scoping. Each object, even if it resides in the same 'place' can have its own scope lookup order depending on how it was defined or create at runtime. You can think of each method as having a stack of scopes to search, and how it was defined pushes new scopes onto that stack.
Because of the way Bird is defined it gets (BaseScope is not its real name, you did not provide enough code to provide this) BaseScope::MyAnimals::Bird
, BaseScope::MyAnimals::Animal
, BaseScope::MyAnimals
and BaseScope
to search through for resolving names.
While The first Oyster only gets BaseScope::MyAnimals::Oyster
, BaseScope::MyAnimals::Animal
and BaseScope
.
The Oyster without inheritance gets even less, just BaseScope::MyAnimals::Oyster
and BaseScope
.
Each use of the class keyword and inheritance in this example pushes another scope to check onto the stack of scopes for its contents to search. So using class MyAnimals::Oyster
only pushed one entry onto this stack.
Edit
For simplicity I left out the method legs_in_oyster. It is a scope that could be searched. It's trivial definition is self explanatory and including it would add much useless text to this answer.
I also left out the global scope for simplicity. I know Koans has at least one scope at or between BaseScope and the global scope.