From: merch-redmine@... Date: 2021-03-16T19:25:05+00:00 Subject: [ruby-core:102889] [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). Backport changed from 2.5: UNKNOWN, 2.6: UNKNOWN, 2.7: UNKNOWN, 3.0: UNKNOWN to 2.5: UNKNOWN, 2.6: REQUIRED, 2.7: REQUIRED, 3.0: REQUIRED fledman (David Feldman) wrote in #note-6: > do you plan to backport the fix to any of the supported 2.x versions? The choice of which patches to backport is up to the branch maintainer. I've marked this for backporting, but it is their decision. ---------------------------------------- Bug #17519: set_visibility fails when a prepended module and a refinement both exist https://bugs.ruby-lang.org/issues/17519#change-90950 * 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: REQUIRED, 3.0: REQUIRED ---------------------------------------- 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: