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
On Sep 18, 9:14 am, Matt Jones <al2o...@gmail.com> wrote: > On Monday, 17 September 2012 21:04:58 UTC-4, John Merlino wrote: > > > 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? > > 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: > > http://opensoul.org/blog/archives/2011/02/07/concerning-activesupport... > > --Matt Jones -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk@googlegroups.com. To unsubscribe from this group, send email to rubyonrails-talk+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out.