why do people use extend in a module definition?
for example, the rubygem Devise has the following piece of code in lib/devise/controllers/helpers.rb
module Helpers
extend ActiveSupport::Concern
why use extend
here? Will include
do the same?
No, include
will not do the same.
extend
and include
perform similar but distinct roles. include
takes the instance methods of the included module and makes them available to instances of the including module. In effect, include
inserts the included module as a superclass of the including (in fact, #ancestors
will even show the included module).
extend
, on the other hand, adds the methods of the named module to the receiver. In the case of calling extend
during a module definition, that means that the "extended" module's instance methods will become class methods of the "extending" module. It's often used to import decorators (really just calls to class methods) into a class or module being defined.
So, in brief, the snippet above will take the instance methods of ActiveSupport::Concern
and make them class methods of Helpers
.
Basically, Object#extend
is just:
class Object
def extend(*ms)
ms.each do |m|
class << self
include m # Obviously, this won't work since m isn't in scope
end
end
end
end
So, it's easy to see that they are obviously not the same, since the methods end up in different classes.
A working, but less obvious version of Object#extend
would be:
class Object
def extend(*ms)
ms.each do |m|
singleton_class.send :include, m # Because Module#include is private
end
end
end
精彩评论