The best explanation I can find is from the docs:
Refinements are lexical in scope. Refinements are only active within a scope after the call to using
. Any code before the using
statement will not have the refinement activated.
That means your refinement method must be invoked somewhere after the call to using
. The actual location of the method's invocation is what matters, not how the method was invoked or from where the method was invoked.
Here's what happens.
using
i.e. using MyClassRefinement
activates the my_method
refinement.
MyClass.new.my_method
is executed.
- A method lookup ensues from the exact point of invocation:
When looking up a method for an instance of class C
Ruby checks:
- If refinements are active for
C
, in the reverse order they were activated
- The prepended modules from the refinement for
C
- The refinement for
C
- The included modules from the refinement for
C
- The prepended modules of
C
C
- The included modules of
C
- Refinements are active, and
my_method
returns the code from the refinement "refined my_method()"
MyClass.new.another_method
is executed.
- The method lookup ensues from the exact point of invocation.
- Refinements are active at this point of invocation, but the
another_method
is not a refinement, so Ruby looks for another_method
in the class MyClass
and finds it.
- Inside of the class method
another_method
, the method my_method
is found and invoked.
- The method lookup ensues from the exact point of invocation.
- At the point of invocation there are no refinements active, because there have been no calls to
using
above the line (i.e. physically prior to) where my_method
is invoked. Ruby goes on to look for my_method
in the class MyClass
and finds it.
my_method
returns the code from the class method "original my_method()"
.
We can make a simple comparison. Let's say I have one isolated file.rb
with the following code:
puts puppy
puppy = 'waggle'
puppy
can't be used before it is defined. The variable is lexically scoped, and its use depends on the location of its definition in the isolated file.rb
.
Similarly, a refinement cannot be invoked until it has been activated via using
on a previous line (or somewhere physically previous within the source code file). The refinement is lexically scoped.
From Wikipedia
In languages with lexical scope (also called static scope), name resolution depends on the location in the source code and the lexical context, which is defined by where the named variable or function is defined...
Lexical resolution can be determined at compile time, and is also known as early binding, while dynamic resolution can in general only be determined at run time, and thus is known as late binding.
Your specific issue with refinements is discussed in the last section of this article. The author explains as well how the using
statement's physical location in the file determines whether or not a refinement is active.