Multiple modules defining same method included into a class

In Ruby, classes are never closed: you can always add methods to an
existing class. This applies to the classes you write as well as the
standard, built-in classes. All you have to do is open up a class
definition for an existing class, and the new contents you specify
will be added to whatever’s there. In the same regard, if module is
used with the name of a pre-existing module that module is re-opened.
If a method is defined in a re-opened module with the same name as a
pre-existing method in the same module the old method is overwritten
with the new. And, of course, modules can be made immutable,
effectively preventing them from being reopened by freezing the module
object. Frozen modules raise RuntimeErrors when methods are defined,
or variables manipulated, in their context.

When you include a module in a class, without a prefix (prefix meaning
something like this: AbstractController::Layouts), then ruby searches
for the module of that name within the scope of the current module
wrapping the class that the include was called in.

So, for example:

module ActionController
class Base
include Rendering

Since we “include Rendering” within the scope of the Base class
object, ruby first looksup the constant Rendering, that is, looking
for a module named Rendering in the ActionController namespace, since
that is the namesapce that Base is defined in???

Well, ActionController module does define a module named Rendering:

module ActionController
module Rendering
def render(*args)
raise ::AbstractController::DoubleRenderError if response_body
super
self.content_type ||= Mime[lookup_context.rendered_format].to_s
response_body
end

So now the method render(*args) is included in the Base class as an
instance method. So when we call, for example, (hypothetically)
ActionView::Base.new.render :action => “my_action”, :layout => false,
ActionView::Base is instantiated and we invoke the render instance
method, and since no render method is declared in the Base class
context, ruby scope chain does lookup into the module Rendering and
finds the method so calls it. Now, as you may know, it’s possible to
pass multiple kinds of arguments to render, depending on whether you
want to render a template or a partial or file, etc. The * syntax does
the job here, allowing you vary the number of arguments passed. It
checks if there is already a response to the request, and raises an
Exception, if so. Otherwise, it calls super.

During this super call, I got a little confused. In
ActionController::Base, there is another module included called
AbstractController::Layouts. Layouts in turn includes a module called
Rendering. Since there is a Rendering module within the
AbstractController namespace, it is found, and it indeed contains a
method called render.

def render(*args, &block)
options = _normalize_render(*args, &block)
self.response_body = render_to_body(options)
end

And because render is included in Layouts, it’s included as an
instance method, and because Layouts was included in
ActionController::Base, that render method utlimately makes its way up
to the Base class. Now we have two modules
(ActionController::Rendering and AbstractController::Rendering that
are including this method into Base. So why doesn’t one of them get
overwritten? Why does the call to super work?

So it does appear that the ActionController::Rendering module does
include AbstractController::Rendering, which means a call to super in
the render method of ActionController::Rendering will in turn call
the render method of AbstractController::Rendering. What makes this
somewhat confusing is that ActionController::Rendering is included in
ActionController::Base, but AbstractController::Rendering is included
in ActionController::Base as well. Yet AbstractController::Rendering
is also included in ActionController::Rendering. Wouldn’t
AbstractController::Rendering being included
ActionController::Rendering and the fact that
ActionController::Rendering is included in ActionController::Base make
AbstractController::Rendering being included in ActionController::Base
redundant?

On Monday, 17 September 2012 21:04:58 UTC-4, John M. wrote:

effectively preventing them from being reopened by freezing the module
module ActionController
module ActionController
instance method. So when we call, for example, (hypothetically)

end

And because render is included in Layouts, it’s included as an
instance method, and because Layouts was included in
ActionController::Base, that render method utlimately makes its way up
to the Base class. Now we have two modules
(ActionController::Rendering and AbstractController::Rendering that
are including this method into Base. So why doesn’t one of them get
overwritten? Why does the call to super work?

The modules aren’t “included” exactly - they’re just added to the list
of
ancestors (try ActionController::Base.ancestors for an eyeful) where
methods are looked up. Modules included later in the source are “higher”
on
the list (similar to subclass methods vs. base class methods) and
calling
‘super’ simply specifies that the next available method up the chain
should be called. This works (as of recent Rails versions) for generated
methods as well:

class SomeModel < ActiveRecord::Base
has_many :wats

def wats
# calling ‘super’ here hits the generated accessor from has_many
end
end

There’s one additional wrinkle for many of the modules in Rails itself -
many of them are extended with ActiveSupport::Concern, which tidies a
bunch
of things up and (most relevant here) changes the semantics of “include
SomeOtherModule”. See this article for more:

–Matt J.

Yep:

1.9.3p0 :005 > module B
1.9.3p0 :006?> def name
1.9.3p0 :007?> puts ‘b module’
1.9.3p0 :008?> end
1.9.3p0 :009?> end
=> nil
1.9.3p0 :010 > module C
1.9.3p0 :011?> def name
1.9.3p0 :012?> puts ‘c module’
1.9.3p0 :013?> end
1.9.3p0 :014?> end
=> nil
1.9.3p0 :015 > class A
1.9.3p0 :016?> include B
1.9.3p0 :017?> include C
1.9.3p0 :018?> end
=> A
1.9.3p0 :019 > A.new.name
c module
=> nil

…looking for a module named Rendering in the ActionController
namespace, since that is the namesapce that Base is defined in???

module Rendering
def greet
puts ‘hi’
end
end

module ActionController
class Base
include Rendering
end
end

obj = ActionController::Base.new
obj.greet

–output:–
hi

module Rendering
def greet
puts ‘hi’
end
end

module ActionController
module Rendering
def greet
puts ‘bye’
end
end

class Base
include Rendering
end
end

obj = ActionController::Base.new
obj.greet

–output:–
bye

module Rendering
def greet
puts ‘hi’
end
end

module ActionController
module Rendering
def greet
puts ‘bye’
end
end

class Base
include Rendering

module Rendering
  def greet
    puts "It's hot down here."
  end
end

end
end

obj = ActionController::Base.new
obj.greet

–output:–
bye

module Rendering
def greet
puts ‘hi’
end
end

module ActionController
module Rendering
def greet
puts ‘bye’
end
end

class Base
module Rendering
def greet
puts “It’s hot down here.”
end
end

include Rendering

end
end

obj = ActionController::Base.new
obj.greet

–output:–
It’s hot down here.