Bug #16982
closedDefine instance_methods and so on explicitly on classes generated by DelegateClass
Description
I found two problems with DelegateClass
.
The patch is available on GitHub. https://github.com/ruby/ruby/pull/3221
instance_methods
¶
First, instance_methods
method's result does not contain the names of methods that are added after the class is defined.
For example
require 'delegate'
class Parent
def parent_public; end
protected
def parent_protected; end
end
class Child < DelegateClass(Parent)
end
class Parent
def parent_public_added; end
protected
def parent_protected_added; end
end
# They're ok.
p Child.instance_methods.include? :parent_public # => true
p Child.instance_methods.include? :parent_protected # => true
# They're wrong. :parent_public_added and :parent_protected_added should be included, but they are not.
p Child.instance_methods.include? :parent_public_added # => false
p Child.instance_methods.include? :parent_protected_added # => false
So I think DelegateClass
should define instance_methods
method explicitly, like public_instance_methods
and protected_instance_methods
.
I've added instance_methods
in this commit https://github.com/ruby/ruby/pull/3221/commits/3f49e3ff094288e41b5629fd07aa8fa858abb196
instance_method
and public_instance_method
Second, instance_method
and public_instance_method
cannot get a method object for methods that are added after the class is defined.
And they cannot get a method object for :to_s
and so on because of https://github.com/ruby/ruby/blob/fbb32b1f483925987d225b4dc08efd197775bcae/lib/delegate.rb#L390.
For example:
require 'delegate'
class Parent
def parent() end
end
class Child < DelegateClass(Parent)
end
class Parent
def parent_added() end
end
p Child.instance_method(:parent) # returns an UnboundMethod
p Child.instance_method(:parent_added) # undefined method `parent_added' for class `Child' (NameError)
p Child.instance_method(:to_s) # undefined method `to_s' for class `Child' (NameError)
But actually a Child
instance has all these methods.
So I think instance_method
method should return a method object.
I actually got the error when I tried to use rbs prototype runtime
.
https://github.com/ruby/rbs/blob/150bc6e65838eab2be088a5cc456b6f4b04bc81c/lib/rbs/prototype/runtime.rb#L172
This code raises an error when it analyses a class that inherits a class generated by DelegateClass
method.
For example
# test.rb
require 'delegate'
class Parent
end
class Child < DelegateClass(Parent)
end
class Parent
def foo() end
end
$ rbs prototype runtime --require-relative test.rb Child
W, [2020-06-24T21:17:45.628527 #890363] WARN -- rbs: Skipping anonymous superclass #<Class:0x000056098f280750> of Child
/home/pocke/.rbenv/versions/trunk/lib/ruby/gems/2.8.0/gems/rbs-0.4.0/lib/rbs/prototype/runtime.rb:172:in `instance_method': undefined method `foo' for class `Child' (NameError)
from /home/pocke/.rbenv/versions/trunk/lib/ruby/gems/2.8.0/gems/rbs-0.4.0/lib/rbs/prototype/runtime.rb:172:in `target_method?'
from /home/pocke/.rbenv/versions/trunk/lib/ruby/gems/2.8.0/gems/rbs-0.4.0/lib/rbs/prototype/runtime.rb:210:in `block in generate_methods'
from /home/pocke/.rbenv/versions/trunk/lib/ruby/gems/2.8.0/gems/rbs-0.4.0/lib/rbs/prototype/runtime.rb:210:in `select'
from /home/pocke/.rbenv/versions/trunk/lib/ruby/gems/2.8.0/gems/rbs-0.4.0/lib/rbs/prototype/runtime.rb:210:in `generate_methods'
from /home/pocke/.rbenv/versions/trunk/lib/ruby/gems/2.8.0/gems/rbs-0.4.0/lib/rbs/prototype/runtime.rb:351:in `generate_class'
from /home/pocke/.rbenv/versions/trunk/lib/ruby/gems/2.8.0/gems/rbs-0.4.0/lib/rbs/prototype/runtime.rb:43:in `block in decls'
from /home/pocke/.rbenv/versions/trunk/lib/ruby/gems/2.8.0/gems/rbs-0.4.0/lib/rbs/prototype/runtime.rb:40:in `each'
from /home/pocke/.rbenv/versions/trunk/lib/ruby/gems/2.8.0/gems/rbs-0.4.0/lib/rbs/prototype/runtime.rb:40:in `decls'
from /home/pocke/.rbenv/versions/trunk/lib/ruby/gems/2.8.0/gems/rbs-0.4.0/lib/rbs/cli.rb:455:in `run_prototype'
from /home/pocke/.rbenv/versions/trunk/lib/ruby/gems/2.8.0/gems/rbs-0.4.0/lib/rbs/cli.rb:85:in `run'
from /home/pocke/.rbenv/versions/trunk/lib/ruby/gems/2.8.0/gems/rbs-0.4.0/exe/rbs:7:in `<top (required)>'
from /home/pocke/.rbenv/versions/trunk/bin/rbs:23:in `load'
from /home/pocke/.rbenv/versions/trunk/bin/rbs:23:in `<main>'
And I also got the same error when I applied the first patch to instance_methods
method. The first patch broke ruby/test/ruby/test_method.rb
.
https://github.com/ruby/ruby/blob/d1fb446b62b1e114252606dcf040dd9392f25170/test/ruby/test_method.rb#L1300
I fixed the problem with this commit https://github.com/ruby/ruby/pull/3221/commits/d1fb446b62b1e114252606dcf040dd9392f25170.
Updated by sawa (Tsuyoshi Sawada) over 4 years ago
- Subject changed from Define instance_methods and so on explicitly to class generated by DelegateClass to Define instance_methods and so on explicitly on classes generated by DelegateClass
- Description updated (diff)
Updated by pocke (Masataka Kuwabara) over 4 years ago
- Status changed from Open to Closed
Applied in changeset git|ba81bc24e62d03cc0f4c05cf4e2b378696631568.
Add instance_methods to class generated by DelegateClass
Also, make DelegateClass.instance_method fallback to superclass.
Fixes [Bug #16982]
Updated by jeremyevans0 (Jeremy Evans) over 4 years ago
I agree that this is a bug, and your pull request is a good way to fix it. I have squash merged your pull request. Thank you @pocke (Masataka Kuwabara)!