Backport #8284

Expected behavior of Module#public_class_method

Added by Jack Nagel about 1 year ago. Updated 11 months ago.

[ruby-core:54404]
Status:Assigned
Priority:Normal
Assignee:Usaku NAKAMURA

Description

It was pointed out by Myron Marston (here: https://gist.github.com/myronmarston/5401829) that calling publicclassmethod on an anonymous module makes the named method public on Object, etc.

Object.definemethod => NoMethodError
Module.new.public
classmethod(:definemethod)
Object.define_method => ArgumentError

Also of note, the same is not true when calling it on a class:

Object.definemethod => NoMethodError
Class.new.public
classmethod(:definemethod)
Object.define_method => NoMethodError

which seems inconsistent given:

Module.new.singletonclass.ancestors => [Module, Object, Kernel, BasicObject]
Class.new.singleton
class.ancestors => [Class, Module, Object, Kernel, BasicObject]

Is this a bug or expected behavior? If the latter, what is the correct explanation?

History

#1 Updated by Nobuyoshi Nakada 12 months ago

  • Status changed from Open to Closed
  • % Done changed from 0 to 100

This issue was solved with changeset r40346.
Jack, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.


vm_method.c: fix visibility on anonymous module

  • vmmethod.c (rbmodpublicmethod): fix visibility on anonymous module. set visibility of singleton method, not method in base class. [Bug #8284]

#2 Updated by Nobuyoshi Nakada 12 months ago

  • Tracker changed from Bug to Backport
  • Project changed from ruby-trunk to Backport200
  • Status changed from Closed to Assigned
  • Assignee set to Tomoyuki Chikanaga

This is a very very longstanding, 16 years old bug, since 1.0.

#3 Updated by Andri Möll 12 months ago

Well, it was actually reported by me to the RSpec project (https://github.com/rspec/rspec-core/pull/873) and the example I gave there involved a regular, not an anonymous module. The patch you made, nobu, tests only with an anonymous module, but does the fix also solve the visibility leakage for non anonymous modules?

With Ruby v1.9.3p385:

Object.definemethod
NoMethodError: private method define_method' called for Object:Class
from (irb):1
from /usr/local/bin/irb:12:in
'
module Foo
public
classmethod :definemethod
end
=> Foo
Object.define_method
ArgumentError: wrong number of arguments (0 for 1)
from (irb):3:in define_method'
from (irb):3
from /usr/local/bin/irb:12:in
'

#4 Updated by Jack Nagel 12 months ago

It does:

irb(main):001:0> RUBYDESCRIPTION
=> "ruby 2.1.0dev (2013-04-19 trunk 40359) [i386-darwin10.8.0]"
irb(main):002:0> Object.define
method
NoMethodError: private method define_method' called for Object:Class
from (irb):2
from /Users/jacknagel/.rubies/ruby-2.1.0-dev/bin/irb:12:in
'
irb(main):003:0> module Foo; publicclassmethod :definemethod; end
=> Foo
irb(main):004:0> Object.define
method
NoMethodError: private method define_method' called for Object:Class
from (irb):4
from /Users/jacknagel/.rubies/ruby-2.1.0-dev/bin/irb:12:in
'

#5 Updated by Jack Nagel 12 months ago

As an aside, I see that this is now marked Backport 200, but it would be great if it was backported to 1.9.3 as well.

#6 Updated by Marc-Andre Lafortune 12 months ago

jacknagel (Jack Nagel) wrote:

As an aside, I see that this is now marked Backport 200, but it would be great if it was backported to 1.9.3 as well.

I don't know if it will be, but in any case there is always singleton_class.send :public, :define_method instead or equivalent.

It's a bit more clear, IMO, as using "publicclassmethod" on a Module is a bit strange... Modules don't really have "class methods".

FWIW, there are no specs in RubySpec about "publicclassmethod" on a Module.

#7 Updated by Andri Möll 12 months ago

jacknagel (Jack Nagel) wrote:

It does:

That's good. Now there's only a test missing for that. :)

#8 Updated by Tomoyuki Chikanaga 12 months ago

I'll backport r40346 and r40371, and then move this ticket to Backport93.

#9 Updated by Tomoyuki Chikanaga 12 months ago

  • Status changed from Assigned to Closed

This issue was solved with changeset r40427.
Jack, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.


merge revision(s) 40346: [Backport #8284]

* vm_method.c (rb_mod_public_method): fix visibility on anonymous
  module. set visibility of singleton method, not method in base
  class.   [Bug #8284]

#10 Updated by Tomoyuki Chikanaga 12 months ago

  • Project changed from Backport200 to Backport93
  • Status changed from Closed to Assigned
  • Assignee changed from Tomoyuki Chikanaga to Usaku NAKAMURA

#11 Updated by Usaku NAKAMURA 11 months ago

Something is missing to backport the patch to ruby19_3.
I'll check it later.

Also available in: Atom PDF