Bug #4994

DelegateClass don't find extern global public method in 1.9.2

Added by Sylvain Viart almost 3 years ago. Updated almost 3 years ago.

[ruby-core:37864]
Status:Rejected
Priority:Normal
Assignee:-
Category:lib
Target version:1.9.2
ruby -v:ruby 1.9.2p180 (2011-02-18 revision 30909) [x86_64-linux] Backport:

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 methodtest_that?' for "pipo":String2 (NoMethodError)
from draft/tdelegate.rb:21:in `'

shell returned 1

History

#1 Updated by Nobuyoshi Nakada almost 3 years ago

  • Status changed from Open to Rejected

It's a spec change for .

  • 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.

#2 Updated by Sylvain Viart almost 3 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) [x8664-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
'

#3 Updated by Sylvain Viart almost 3 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.

#4 Updated by Sylvain Viart almost 3 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) [x8664-linux]

should call Integer#to
si: 2
ii.class=MyInt

Also available in: Atom PDF