Project

General

Profile

Actions

Bug #4994

closed

DelegateClass don't find extern global public method in 1.9.2

Added by sylvain303 (Sylvain Viart) almost 11 years ago. Updated almost 11 years ago.

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

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) almost 11 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) almost 11 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) almost 11 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) almost 11 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
Actions

Also available in: Atom PDF