From: merch-redmine@... Date: 2021-04-05T23:06:23+00:00 Subject: [ruby-core:103245] [Ruby master Bug#17519] set_visibility fails when a prepended module and a refinement both exist Issue #17519 has been updated by jeremyevans0 (Jeremy Evans). fledman (David Feldman) wrote in #note-10: > this fix seems to have introduced a new but similar bug: https://github.com/ruby/ruby/pull/4200#issuecomment-813671308 I can confirm the issue. Here's a pull request that fixes it: https://github.com/ruby/ruby/pull/4357 ---------------------------------------- Bug #17519: set_visibility fails when a prepended module and a refinement both exist https://bugs.ruby-lang.org/issues/17519#change-91325 * Author: fledman (David Feldman) * Status: Closed * Priority: Normal * ruby -v: ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin19] * Backport: 2.5: UNKNOWN, 2.6: REQUIRED, 2.7: DONE, 3.0: DONE ---------------------------------------- the set_visibility functions (aka public/private/protected) fail with NameError when: * called on a specific object's singleton class * for a specific method * and both of the following are true * any module has been prepended to the object's class * a refinement exists for the specific method note that the refinement does not need to ever be used I have reproduced this on 3.0.0, 2.7.2, and 2.6.6 (those were the only 3 version I tested) ``` ruby def test_visibility(function) h1 = {x:1, y:1} h2 = {x:2, y:2} h1.singleton_class.send(:private, function) h2.singleton_class.send(:public, function) begin puts h1.public_send(function, :x) rescue NoMethodError => err puts "hit NoMethodError as expected: #{err.inspect}" end puts h2.public_send(function, :x) end ``` succeeds without any prepended modules or refinements: ```ruby irb> test_visibility :except hit NoMethodError as expected: #1, :y=>1}:Hash> {:y=>2} => nil ``` succeeds with only a prepended module: ```ruby irb> module Nothing; end; Hash.prepend(Nothing); Hash.ancestors => [Nothing, Hash, Enumerable, Object, PP::ObjectMixin, Kernel, BasicObject] irb> test_visibility :except hit NoMethodError as expected: #1, :y=>1}:Hash> {:y=>2} => nil ``` succeeds with only a refinement: ```ruby irb> module NeverUsed refine Hash do def except(*keys) {never: 'used'} end end end => # irb> test_visibility :except hit NoMethodError as expected: #1, :y=>1}:Hash> {:y=>2} => nil ``` fails with both a refinement and a prepended module: ```ruby irb> module Nothing; end; Hash.prepend(Nothing); Hash.ancestors => [Nothing, Hash, Enumerable, Object, PP::ObjectMixin, Kernel, BasicObject] irb> module NeverUsed refine Hash do def except(*keys) {never: 'used'} end end end => # irb> test_visibility :except Traceback (most recent call last): 6: from .rubies/ruby-3.0.0/bin/irb:23:in `
' 5: from .rubies/ruby-3.0.0/bin/irb:23:in `load' 4: from .rubies/ruby-3.0.0/lib/ruby/gems/3.0.0/gems/irb-1.3.0/exe/irb:11:in `' 3: from (irb):25:in `
' 2: from (irb):5:in `test_visibility' 1: from (irb):5:in `private' NameError (undefined method `except' for class `#>') Did you mean? exec # non-refined method still works irb> test_visibility :fetch hit NoMethodError as expected: #1, :y=>1}:Hash> 2 => nil ``` -- https://bugs.ruby-lang.org/ Unsubscribe: