Skip to content

Commit a4c655e

Browse files
committed
[DOC] Update refinement documentation
This removes the discussion of included modules in refinements, since support for that was removed in Ruby 3.2. This switches the method lookup description to be ancestor-based instead of class-based, so it better reflects how the process actually works. Also discuss how super inside a refined module method is not allowed if the method was called via super from a refinement method.
1 parent c1f48f4 commit a4c655e

1 file changed

Lines changed: 42 additions & 24 deletions

File tree

doc/syntax/refinements.rdoc

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -210,40 +210,58 @@ all refinements from the same module are active when a refined method
210210

211211
== Method Lookup
212212

213-
When looking up a method for an instance of class +C+ Ruby checks:
213+
Method lookup in Ruby is based on the ancestor chain. You can see the
214+
ancestor chain for any object in Ruby by doing:
214215

215-
* The refinements of +C+, in reverse order of activation
216-
* The prepended modules of +C+
217-
* +C+
218-
* The included modules of +C+
216+
object.singleton_class.ancestors
217+
# or, if the object does not support a singleton class:
218+
object.class.ancestors
219219

220-
If no method was found at any point this repeats with the superclass of +C+.
220+
The ancestor chain is constructed as follows:
221221

222-
Note that methods in a subclass have priority over refinements in a
223-
superclass. For example, if the method <code>/</code> is defined in a
224-
refinement for Numeric <code>1 / 2</code> invokes the original Integer#/
225-
because Integer is a subclass of Numeric and is searched before the refinements
226-
for the superclass Numeric. Since the method <code>/</code> is also present
227-
in child +Integer+, the method lookup does not move up to the superclass.
222+
* Subclasses are before superclasses in the ancestor chain
223+
* Prepended modules are before the class they prepend in the ancestor
224+
chain, in reverse order in which they were prepended.
225+
* Included modules are after the class they are included in in the
226+
ancestor chain, in reverse order in which they were included.
227+
228+
When looking up a method for an object, Ruby goes through each ancestor:
229+
230+
* If the class/module has been refined, Ruby will consider the refinements
231+
activated at the point the method was called, in reverse order of
232+
activation.
233+
* Otherwise, Ruby will check the methods of the class/module itself.
234+
235+
If no method was found at either point this repeats with the next
236+
ancestor.
228237

229-
However, if a method +foo+ is defined on Numeric in a refinement, <code>1.foo</code>
238+
Note that methods in a earlier ancestor have priority over refinements in a
239+
later ancestor. For example, if the method <code>/</code> is defined in a
240+
refinement for Numeric <code>1 / 2</code> invokes the original Integer#/
241+
because Integer is a comes before Numeric in the ancestor chain. However,
242+
if a method +foo+ is defined on Numeric in a refinement, <code>1.foo</code>
230243
invokes that method since +foo+ does not exist on Integer.
231244

232245
== +super+
233246

234-
When +super+ is invoked method lookup checks:
247+
When +super+ is invoked, method lookup starts:
248+
249+
* If the method is in a refinement, at the refined class or module
250+
* Otherwise, at the next ancestor
251+
252+
Method lookup then proceeds as described in the Method Lookup section
253+
above.
235254

236-
* The included modules of the current class. Note that the current class may
237-
be a refinement.
238-
* If the current class is a refinement, the method lookup proceeds as in the
239-
Method Lookup section above.
240-
* If the current class has a direct superclass, the method proceeds as in the
241-
Method Lookup section above using the superclass.
255+
Refinements activated at the call site of a refinement method do not
256+
affect +super+ inside that method. Only refinements activated at the
257+
point +super+ was called affect method lookup for that +super+ call.
258+
You cannot use refinements to insert into the middle of a method
259+
lookup chain, only to insert at the start of a method lookup chain,
260+
unless you control the +super+ call sites.
242261

243-
Note that +super+ in a method of a refinement invokes the method in the
244-
refined class even if there is another refinement which has been activated in
245-
the same context. This is only true for +super+ in a method of a refinement, it
246-
does not apply to +super+ in a method in a module that is included in a refinement.
262+
Note that if you refine a module, the refinement method can call +super+
263+
to call the method in the module, but the method in the module cannot
264+
call +super+ to continue the method lookup process to further ancestors.
247265

248266
== Methods Introspection
249267

0 commit comments

Comments
 (0)