works when append_features is called either directly or when Foo is
included in a class. That is, super finds a superclass where
append_features is defined. According to the docs this class is Module.
Is this where append_features is actually defined? And if user-defined
modules have superclasses, why don’t the superclass and ancestors
methods report this class?
Is this where append_features is actually defined? And if user-defined
modules have superclasses, why don’t the superclass and ancestors
methods report this class?
Foo.append_features works because Foo is a Module (Foo.class == Module),
and Module#append_features is defined, the same way it would work for
any other sort of object.
Classes are the only special case; if Bar were a class, calling e.g.
Bar.hoge would also search the singleton methods defined on the classes
in
Bar.ancestors, in addition to searching the regular instance methods on
Bar.class.ancestors.
Does this make Foo a singleton class of Module? This would explain how
Foo could respond to super, yet have no superclass. But this would
still be strange because
module Foo
def self.append_features(b)
super
end
end
would make append_features a module method and yet
Module.new.respond_to?(:append_features, true) is true. For a class,
this implies that append_features would be an instance method. I take
it this works differently for modules?
Is this where append_features is actually defined? And if user-defined
modules have superclasses, why don’t the superclass and ancestors
methods report this class?
Foo.append_features works because Foo is a Module (Foo.class == Module),
and Module#append_features is defined, the same way it would work for
any other sort of object.
Classes are the only special case; if Bar were a class, calling e.g.
Bar.hoge would also search the singleton methods defined on the classes
in
Bar.ancestors, in addition to searching the regular instance methods on
Bar.class.ancestors.
would make append_features a module method and yet
Module.new.respond_to?(:append_features, true) is true. For a class,
this implies that append_features would be an instance method. I take
it this works differently for modules?
No, Foo is an instance of Module.
module Foo
def self.append_features(b)
super
end
end
The self.append_features in the def means that we are defining the
method in the context
of the singleton class of Foo. Try running this:
class Module
def provides_method(meth)
instance_methods.include?(meth.to_s) ? “provides #{meth}” : “does
not provide #{meth}”
end
end
module Foo
def self.append_features(b)
puts “I am #{self}”
puts “My class is #{self.class} which
#{self.class.provides_method(:append_features)}”
sing_class = class <<self; self;end
puts “My singleton class is #{sing_class} which
#{sing_class.provides_method(:append_features)}”
super
end
end
class C
include Foo
end
which produces the following output:
I am Foo
My class is Module which does not provide append_features
My singleton class is #Class:Foo which provides append_features
I now see what is going on in general. Class Class or Class Module
instance methods become Class or Module methods in instances of Class or
Module.
Instances of Class or Module create singletons to reference their Class
or Module methods. When an instance method of the same name exists in
Class or Module, that method is invoked by a call to super in the Class
or Module method defined in the singleton. No superclass is necessarily
involved.
would make append_features a module method and yet
Module.new.respond_to?(:append_features, true) is true. For a class,
this implies that append_features would be an instance method. I take
it this works differently for modules?
No, Foo is an instance of Module.
module Foo
def self.append_features(b)
super
end
end
The self.append_features in the def means that we are defining the
method in the context
of the singleton class of Foo. Try running this:
class Module
def provides_method(meth)
instance_methods.include?(meth.to_s) ? “provides #{meth}” : “does
not provide #{meth}”
end
end
module Foo
def self.append_features(b)
puts “I am #{self}”
puts “My class is #{self.class} which
#{self.class.provides_method(:append_features)}”
sing_class = class <<self; self;end
puts “My singleton class is #{sing_class} which
#{sing_class.provides_method(:append_features)}”
super
end
end
class C
include Foo
end
which produces the following output:
I am Foo
My class is Module which does not provide append_features
My singleton class is #Class:Foo which provides append_features