Bug #9311
closedmodule_function breaks on `singleton_class?`
Description
=begin
When trying to use Sass 3.3.0-rc2 with Rails 3.x, an error similar to the one below is produced:
[6] pry(Sass::Util)> Sass::Util.methods.grep /singleton_class/
=> [:singleton_class?, :singleton_class]
[7] pry(Sass::Util)> Sass::Util.method_function :singleton_class?
NoMethodError: undefined method `method_function' for Sass::Util:Module
from (pry):6:in `<module:Util>'
This is actually pretty trivially reproduced via:
2.1.0 :001 > module Foo
2.1.0 :002?> methods.grep(/singleton/).each {|x| module_function x }
2.1.0 :003?> end
NameError: undefined method `singleton_class?' for module `Foo'
from (irb):2:in `module_function'
from (irb):2:in `block in <module:Foo>'
from (irb):2:in `each'
from (irb):2:in `<module:Foo>'
from (irb):1
from /usr/local/rvm/rubies/ruby-2.1.0/bin/irb:11:in `<main>'
Now, Sass performs the following:
(Sass::Util.methods - Module.methods).each {|method| module_function method }
This succeeds if you don't include ActiveSupport, but ActiveSupport extends Class with the following:
class Class
private
def singleton_class?
ancestors.first != self
end
end
This causes singleton_class?
to no longer show in the Module.methods
list (I suspect because of the new method cache invalidation stuff?):
2.1.0 :001 > Module.methods.sort
=> [... :singleton_class, :singleton_class?, :singleton_method, :singleton_methods, :superclass, ...]
2.1.0 :002 > class Class
2.1.0 :003?> private
2.1.0 :004?> def singleton_class?
2.1.0 :005?> ancestors.first != self
2.1.0 :006?> end
2.1.0 :007?> end
=> :singleton_class?
2.1.0 :008 > Module.methods.sort
=> [... :singleton_class, :singleton_method, :singleton_methods, :superclass, ...]
Since it's no longer in the Module.methods list, Sass attempts to module_function
it and the whole thing blows up.
This is fixable in both Sass and ActiveSupport (which I'll file tickets for), but it feels like this is a Ruby bug. Doing something similar in 2.0 (which doesn't have singleton_class?
) results in the following:
2.0.0p247 :001 > class Class
2.0.0p247 :002?> private
2.0.0p247 :003?> def singleton_class
2.0.0p247 :004?> false
2.0.0p247 :005?> end
2.0.0p247 :006?> end
=> nil
2.0.0p247 :007 > module Foo
2.0.0p247 :008?> module_function :singleton_class
2.0.0p247 :009?> end
=> Foo
2.0.0p247 :010 > Foo.singleton_class
=> #<Class:Foo>
Which seems to work just fine.
=end
Files
Updated by hsbt (Hiroshi SHIBATA) over 10 years ago
- Tracker changed from Backport to Bug
- Project changed from Backport21 to Ruby master
- ruby -v set to ruby 2.1.0
Updated by tmm1 (Aman Karmani) over 10 years ago
- File bug9311-test.diff bug9311-test.diff added
Attached regression test for trunk.
Updated by tmm1 (Aman Karmani) over 10 years ago
- ruby -v changed from ruby 2.1.0 to -
Updated by nobu (Nobuyoshi Nakada) over 10 years ago
- Status changed from Open to Rejected
Module.singleton_class?
is a method of Module
, not defined in Module
instances.
Other singleton_
* methods are defined in Kernel
as instance methods.
Updated by tmm1 (Aman Karmani) over 10 years ago
This causes singleton_class? to no longer show in the Module.methods list (I suspect because of the new method cache invalidation stuff?):
This has nothing to do with method cache, but is instead caused by ActiveSupport marking :singleton_class? as private.
>> Module.methods.include?(:singleton_class?)
=> true
>> class Class; def singleton_class?() super end; end
>> Module.methods.include?(:singleton_class?)
=> true
>> class Class; private :singleton_class?; end
>> Module.methods.include?(:singleton_class?)
=> false