Bug #4994
closedDelegateClass don't find extern global public method in 1.9.2
Description
How to reproduce:
require 'delegate' require 'pp' def test_that?(str) str.size > 0 end class String2 < DelegateClass(String) def initialize(*param) @s = String.new(*param) super(@s) end def dummy test_that?(@s) end end s2 = String2.new("pipo") pp s2.dummy
The code above works under 1.9.1 and 1.8 but not under 1.9.2
- ruby1.9.1 -v => ruby 1.9.1p378 (2010-01-10 revision 26273) [x86_64-linux]
- ruby1.8 -v => ruby 1.8.7 (2010-01-10 patchlevel 249) [x86_64-linux]
- ruby -v => ruby 1.9.2p180 (2011-02-18 revision 30909) [x86_64-linux]
error message:
!ruby draft/tdelegate.rb draft/tdelegate.rb:15:in `dummy': undefined method `test_that?' for "pipo":String2 (NoMethodError) from draft/tdelegate.rb:21:in `' shell returned 1
Updated by nobu (Nobuyoshi Nakada) over 13 years ago
- Status changed from Open to Rejected
It's a spec change for [ruby-dev:39154].
- Delegator now tries to forward all methods as possible,
- but not for private methods, and
- test_that? is a private method.
Probably, it would need a way to tell how the method is called in method_missing.
Updated by sylvain303 (Sylvain Viart) over 13 years ago
Sorry, but links are in Japanese.
I can read the code, but not why the DelegateClass shouldn't search the toplevel method, any more?
Could you translate or post a link to an English doc?
For the correction you suggest, I've wrote this code:
I don't like this usage as a Delegation. May be I missed something.
Edited: Wrong solution, for this method_missing() see comment after
require 'delegate' require 'pp' def test_that?(str) str.size > 0 end class String2 < DelegateClass(String) def initialize(*param) @s = String.new(*param) super(@s) end def dummy test_that?(@s) # this method is really missing bla() end def method_missing(m, *args, &block) begin Object.send(m, *args, &block) rescue NameError =>e # doesn't work with NoMethodError, it loops raise "no method found: '#{m}'" end end end s2 = String2.new("pipo") # test Delegated method pp s2.size # call with method_missing() pp s2.dummy
output (ruby -v ruby 1.9.2p180 (2011-02-18 revision 30909) [x86_64-linux])
:!ruby draft/tdelegate.rb 4 draft/tdelegate.rb:24:in `rescue in method_missing': no method found: 'bla' (RuntimeError) from draft/tdelegate.rb:20:in `method_missing' from draft/tdelegate.rb:16:in `dummy' from draft/tdelegate.rb:32:in `'
Updated by sylvain303 (Sylvain Viart) over 13 years ago
The Issue topic could be rewritten: "DelegateClass don't lookup toplevel method in 1.9.2"
Reading and patching the delegate.rb:http://redmine.ruby-lang.org/projects/ruby-19/repository/entry/lib/delegate.rb I've found that it's related to BasicObject's behavior. DelegateClass somewhat inherit from BasicObject, not Object.
This issue follow the same pattern as #3768.
The documentation should be updated how to fix that (toplevel method resolution).
But may be, I'm still miss something about the new Spec about DelegateClass.
Updated by sylvain303 (Sylvain Viart) over 13 years ago
Fixed DelegateClass with method_missing(), somewhat ugly right?
require 'delegate' def hello :hello end class MyInt < DelegateClass(Integer) def initialize(value) @i = value super(@i) # I want some toplevel here @hello = hello() end def method_missing(m, *args, &block) if __getobj__.respond_to?(m) __getobj__.__send__(m, *args, &block) else Object.send(m, *args, &block) end end end ii = MyInt.new(2) puts p"should call Integer#to_si: #{ii}" puts "ii.class=#{ii.class}"
output ruby 1.9.2p180 (2011-02-18 revision 30909) [x86_64-linux]
should call Integer#to_si: 2 ii.class=MyInt