Issue #13271 has been reported by Damien Robert.

----------------------------------------
Bug #13271: Clarifications on refinement spec
https://bugs.ruby-lang.org/issues/13271

* Author: Damien Robert
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: ruby 2.4.0p0 (2016-12-24 revision 57164) [x86_64-linux]
* Backport: 2.2: UNKNOWN, 2.3: UNKNOWN, 2.4: UNKNOWN
----------------------------------------
Consider the following code:

~~~
class Foo
  def foo
    "Foo#foo"
  end
  def bar
    "Foo#bar"
  end
end
class Bar < Foo
  def foo
    "Bar#foo -> "+super
  end
  def bar
    "Bar#bar -> "+super
  end
end

module R1
  def foo
    "R1#foo -> "+super
  end
  def bar
    "R1#bar -> "+super
  end
end
module R2
  def foo
    "R2#foo -> "+super
  end
  def bar
    "R2#bar -> "+super
  end
end

module M2
  refine Foo do
    include R2
    def foo
      "refinement:Foo@M2#foo -> "+super
    end
    def bar
      "refinement:Foo@M2#bar -> "+super
    end
  end
end

module M1
  include M2
  refine Foo do
    include R1
    def foo
      "refinement:Foo@M1#foo -> "+super
    end
  end
end

using M1
puts Foo.new.foo #refinement:Foo@M1#foo -> R1#foo -> Foo#foo
puts Foo.new.bar #R1#bar -> refinement:Foo@M2#bar -> R2#bar -> Foo#bar
puts Bar.new.foo #Bar#foo -> Foo#foo
puts Bar.new.bar #Bar#bar -> Foo#bar
~~~

I have several questions about the results.
1) As I was expecting, 'using M1' not only activate the refinements of M1 but also the refinements of the included module M2.
In other word it behaves as if I had specified 'using M2; using M1'. This is what I was expecting but from reading the spec
"(3) Activate refinements in the defined refinement table of (({mod}))" it looks like the spec only speak about the refined modules in M1.

2) As noted in the spec,  refinement:Foo@M1 should behave as if its superclass was Foo, so the fact that Foo.new.foo does not go through the refinements of M2 was expected.
   However I find the result of 'Foo.new.bar' strange: refinement:Foo@M1 does not contain the bar method, but its included module R1 does. So should not the result be
   R1#bar -> Foo#bar, whithout going through the refinements methods of M2?
   The spec states "(3) If (({C})) has included modules, for these modules {{M}} If a method with name (({N})) found in the method table of (({M})), return the method."
   But it does not stipulate what happen if we call super in one of these included method.

3) I am also surprised by the behaviour of Bar.new.foo and Bar.new.bar. According to the spec:
   "(7) If (({C})) has a direct superclass, search the method (({N})) as specified in ((<"Normal method lookup">)) from Step 4, where (({C})) is the superclass."
   and Step 4 start by looking at the activated refinements.
   
   So I was expecting the results to go through Foo's refinement, so that for instance 'Bar.new.foo' would be
   Bar#foo -> refinement:Foo@M1#foo -> R1#foo -> Foo#foo




-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>