Project

General

Profile

Bug #8743

Inconsistent behaviour calling public_methods on class (Plus documentation slightly ambiguous)

Added by stestagg (Steve Stagg) about 6 years ago. Updated 3 months ago.

Status:
Closed
Priority:
Normal
Assignee:
-
Target version:
-
ruby -v:
ruby 2.1.0dev (2013-08-06 trunk 42401) [x86_64-darwin12.4.0]
Backport:
[ruby-core:<unknown>]

Description

=begin
= Background

I was trying to identify classes on which a specific class method (def self.xx) was actually defined (in the case of multiple levels of inheritance). This currently doesn't seem to be possible, although the docs suggest that calling class.public_methods(false) should do this.

While investigating, I discovered that the behaviour of calling instance.public_methods(false) is not consistent with that of calling class.public_methods(false) [They should be different, of course, but the behaviour should be consistent]. The attached test script highlights this.

= Steps to Reproduce

Run the attached ruby script

= Expected Result

Ideally, all tests pass, but at least test_consistent_behaviour should pass

= Actual Results

test_this_is_what_i_expect, and test_consistent_behaviour both fail.

= Example test output

steves@sapphire ~/s/t/ruby> env RUBYLIB=./lib ./ruby ~/foo.rb
Run options:

# Running tests:

[2/5] PublicMethodsTest#test_consistent_behaviour = 0.00 s
1) Failure:
PublicMethodsTest#test_consistent_behaviour [/Users/steves/foo.rb:73]:
Differences: bar. "bar" is inherited from A, but doesn't include methods inherited from Object!

[5/5] PublicMethodsTest#test_this_is_what_i_expect = 0.00 s
2) Failure:
PublicMethodsTest#test_this_is_what_i_expect [/Users/steves/foo.rb:59]:
Differences: allocate, new, superclass.

Finished tests in 0.005998s, 833.6112 tests/s, 2834.2781 assertions/s.
5 tests, 17 assertions, 2 failures, 0 errors, 0 skips

ruby -v: ruby 2.1.0dev (2013-08-06 trunk 42401) [x86_64-darwin12.4.0]

Seen on ruby 1.8, 2.0 and trunk
=end


Files

foo.rb (2.22 KB) foo.rb stestagg (Steve Stagg), 08/06/2013 09:24 PM

History

Updated by jeremyevans0 (Jeremy Evans) 3 months ago

  • Backport deleted (1.9.3: UNKNOWN, 2.0.0: UNKNOWN)
  • Status changed from Open to Closed

The reason for this interesting behavior is because the documentation for include flag (2nd argument) for public_methods is not precise. It states:

If the all parameter is set to false, only those methods
in the receiver will be listed.

However, the behavior is actually:

If the all parameter is set to false, the list will include methods
in ancestors, stopping after a non-singleton class is encountered
(including the methods from the non-singleton class).

The lookup process for Empty.public_methods(false) is something like this:

  • Empty.singleton_class # adds no methods
  • Object.singleton_class # adds no methods
  • BasicObject.singleton_class # adds no methods
  • Class # adds 3 methods [:allocate, :superclass, :new]
  • Module # does not get here, as Class is not a singleton class

So that is the reason Empty.public_methods(false) gives you [:allocate, :superclass, :new].

B.public_methods(false) including singleton methods from A is similar:

  • B.singleton_class # adds no methods
  • A.singleton_class # adds 1 method [:bar]
  • Object.singleton_class # adds no methods
  • BasicObject.singleton_class # adds no methods
  • Class # adds 3 methods [:allocate, :superclass, :new]
  • Module # does not get here, as Class is not a singleton class

Which is the reason that Bar.public_methods(false) gives you [:bar, :allocate, :superclass, :new].

I'm not sure it worth updating the documentation to be more precise in this area, but I'm open to suggestions.

Also available in: Atom PDF