Issue #19749 has been updated by jeremyevans0 (Jeremy Evans).
Eregon (Benoit Daloze) wrote in #note-3:
@jeremyevans0 That does not explain why the original
example defines the method as public (note I edited the description on Redmine, it was not
asking the right question).
will only consider current default scope
visibility to determine visibility:
And that visibility is private at the top-level. So why is the method defined as public
on CRuby?
Scope visibility is only used if the receiver of the method is the same as current scope,
which was not the case in the previous examples given.
`define_method` at top level does not define private methods. I think this is because the
receiver of the `define_method` is `main`, but the method is defined in `Object`, so the
scope visibility does not apply. I don't think this is a bug, see #9005.
However, I think there is a bug here, in that `define_method` will not change the existing
visibility of a method if `define_method` is called with the current method body:
```ruby
def bar; end
define_method(:bar, method(:bar))
Object.new.bar # NoMethodError
```
This is not related to top-level:
```ruby
class Foo
def bar; end
define_method(:bar, method(:bar))
new.bar # NoMethodError
end
```
Note that `define_method` does not copy the method body visibility if there is not an
existing method entry:
```ruby
def bar; end
define_method(:baz, method(:bar))
Object.new.baz # no error
```
It will override the method visibility if the method is already defined but does not have
the same implementation, but in that case it will not use the method body visibility:
```ruby
def bar; end
def baz; end
define_method(:baz, method(:bar))
Object.new.baz # no error
```
This also affects `define_singleton_method`:
```ruby
foo = Object.new
foo.singleton_class.class_exec do
private def bar; end
end
foo.define_singleton_method(:bar, foo.method(:bar))
foo.bar # NoMethodError
```
I think `define_method`/`define_singleton_method` should be changed to reset the method
visibility if the current method body is passed, either to the scope visibility if the
receiver is the same as the current scope, or to public otherwise.
----------------------------------------
Bug #19749: Confirm correct behaviour when attaching private method with `#define_method`
https://bugs.ruby-lang.org/issues/19749#change-103708
* Author: itarato (Peter Arato)
* Status: Open
* Priority: Normal
* ruby -v: 3.3.0
* Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN
----------------------------------------
This issue is a special case of
https://bugs.ruby-lang.org/issues/19745:
Should dynamically added private methods via `.singleton_class.send(:define_method,...` at
the top-level be accessible publicly?
See the following example:
```ruby
def bar; end
foo = Object.new
foo.singleton_class.define_method(:bar, method(:bar))
foo.bar # No error.
```
The script above runs fine on latest Ruby 3.3. Is this correct to ignore the fact that the
visibility in the caller context is the default top-level private visibility?
This came up during a TruffleRuby investigation
(
https://github.com/oracle/truffleruby/issues/3134) where the result for the same script
is: `private method 'bar' called for #<Object:0xc8> (NoMethodError)`
--
https://bugs.ruby-lang.org/