Self.included question

Hi there,

I see the following code chunk in a lot of Rails plugins:

  def self.included(base)
    base.extend(ClassMethods)
  end

  module ClassMethods
     def method_one
     end

     def method_two
     end
  end

I'm most curious about "self.included". I checked out the docs on 'included'
(http://www.ruby-doc.org/core/classes/Module.html#M001661). They pointed to
'Module.append_features' (
http://www.ruby-doc.org/core/classes/Module.html#M001659). Even after
reading the docs, I'm still a little lost. Could someone break it down a
little more than the docs? ...or point me at some other resource. I'd like
to know "why" this is done.

Thanks,
Dave

Hi there,

I see the following code chunk in a lot of Rails plugins:

  def self.included(base)
    base.extend(ClassMethods)
  end

  module ClassMethods
     def method_one
     end

     def method_two
     end
  end

I'm most curious about "self.included". I checked out the docs on 'included'
(class Module - RDoc Documentation).

This is the doc about #include not #included!!

They pointed to
'Module.append_features' (
class Module - RDoc Documentation). Even after
reading the docs, I'm still a little lost. Could someone break it down a
little more than the docs? ...or point me at some other resource. I'd like
to know "why" this is done.

Thanks,
Dave

The included hook is run whenever a module is included.
The parameter base passed to the hook is referring to the class into
which the module is included.
Basically
def self.included(base)
   base.extend(ClassMethods)
end
means:
and if you include me you also extend your class to all methods
defined in ClassMethods.

This means that instead of writing

class X
   include Y
   extend ClassMethods
end

you write
class X
   include Y # ==> the hook does X.extend(ClassMethods)
end

Although I do not know Rails it might be a reasonable guess that the
functionality of ClassMethods is closely coupled with the
functionality of the inserted module - and that methods of the module
need class methods from ClassMethods.

HTH
Robert

···

On 5/16/07, Dave Hoefler <dhoefler@gmail.com> wrote:

--
You see things; and you say Why?
But I dream things that never were; and I say Why not?
-- George Bernard Shaw

If a module implements self.included the interpreter calls that method whenever the module is included in another module or class, which is passed as its single argument.

Object#extend on the other hand adds the instance methods of the module or modules passed as arguments to the target object (as singleton methods). If the object is a class, that means you are making module instance methods available as class methods in that class, and that's what base is when a module is being included in a class.

In short, plugins put methods that will end up being class methods (acts_as_something, say) in their own nested module, conventionally called ClassMethods, and then include them in init.rb. For instance

   ActiveRecord::Base.send(:include, MyModule)

That triggers inclusion when Rails boots, so your code is able to call those class methods as if they belonged to the original API of ActiveRecord::Base (in the example).

-- fxn

···

On May 16, 2007, at 10:02 PM, Dave Hoefler wrote:

Hi there,

I see the following code chunk in a lot of Rails plugins:

def self.included(base)
   base.extend(ClassMethods)
end

module ClassMethods
    def method_one
    end

    def method_two
    end
end

I'm most curious about "self.included". I checked out the docs on 'included'
(class Module - RDoc Documentation). They pointed to
'Module.append_features' (
class Module - RDoc Documentation). Even after
reading the docs, I'm still a little lost. Could someone break it down a
little more than the docs? ...or point me at some other resource. I'd like
to know "why" this is done.

Robert Dober schrieb:

I'm most curious about "self.included". I checked out the docs on 'included'
(class Module - RDoc Documentation).

This is the doc about #include not #included!!

You are looking for the wrong Method - see documentation about "Object#extend". The usages are visible in the example:

module ClassMethods
   def method_one
     puts "in method_one"
   end

   def method_two
     puts "in method_two"
   end
end

def incl1(x)
   x.extend(ClassMethods)
end

module Mymod
   def self.incl2(x)
     x.extend(ClassMethods)
   end
end

incl1(String)
Mymod.incl2(Array)

String.method_one # => in method_one
String.method_two # => in method_two

Array.method_one # => in method_one

Wolfgang Nádasi-Donner

Robert and Xavier (fxn) -

Thank you for the explanations! That just cleared things up tremendously.

So say I have this module (rails plugin):

module Office
  def self.included(base)
    base.extend(ClassMethods)
  end

  module ClassMethods
    def working(options={})
      # do something based off the options
    end
  end

end

In one of my models I can then access the method 'working' by:

class ModelName < ActiveRecord::Base
   working :task => "Take a break!"
end

Thanks again

-Dave

···

On 5/16/07, Xavier Noria <fxn@hashref.com> wrote:

On May 16, 2007, at 10:02 PM, Dave Hoefler wrote:

> Hi there,
>
> I see the following code chunk in a lot of Rails plugins:
>
> def self.included(base)
> base.extend(ClassMethods)
> end
>
> module ClassMethods
> def method_one
> end
>
> def method_two
> end
> end
>
> I'm most curious about "self.included". I checked out the docs on
> 'included'
> (http://www.ruby-doc.org/core/classes/Module.html#M001661\). They
> pointed to
> 'Module.append_features' (
> class Module - RDoc Documentation). Even after
> reading the docs, I'm still a little lost. Could someone break it
> down a
> little more than the docs? ...or point me at some other resource.
> I'd like
> to know "why" this is done.

If a module implements self.included the interpreter calls that
method whenever the module is included in another module or class,
which is passed as its single argument.

Object#extend on the other hand adds the instance methods of the
module or modules passed as arguments to the target object (as
singleton methods). If the object is a class, that means you are
making module instance methods available as class methods in that
class, and that's what base is when a module is being included in a
class.

In short, plugins put methods that will end up being class methods
(acts_as_something, say) in their own nested module, conventionally
called ClassMethods, and then include them in init.rb. For instance

   ActiveRecord::Base.send(:include, MyModule)

That triggers inclusion when Rails boots, so your code is able to
call those class methods as if they belonged to the original API of
ActiveRecord::Base (in the example).

-- fxn

Robert Dober schrieb:

No it was not me, it was OP!

>> I'm most curious about "self.included". I checked out the docs on
>> 'included'
>> (class Module - RDoc Documentation).
> This is the doc about #include not #included!!

<snip>
Robert

···

On 5/16/07, Wolfgang Nádasi-Donner <wonado@donnerweb.de> wrote:

--
You see things; and you say Why?
But I dream things that never were; and I say Why not?
-- George Bernard Shaw

<snip>

module Office
  def self.included(base)
    base.extend(ClassMethods)
  end

  module ClassMethods
    def working(options={})
      # do something based off the options
    end
  end

end

In one of my models I can then access the method 'working' by:

class ModelName < ActiveRecord::Base

#given that you include Office before
      include Office

   working :task => "Take a break!"
end

Thanks again

-Dave

Cheers
Robert

···

On 5/16/07, Dave Hoefler <dhoefler@gmail.com> wrote:

--
You see things; and you say Why?
But I dream things that never were; and I say Why not?
-- George Bernard Shaw

Exactly.

In regular Ruby you'd need to include Office by hand in the model class, but in Rails it is normal (I'd say even expected) that the plugin does the include in AR::Base for you in init.rb using the idiom mentioned in the previous post.

-- fxn

···

On May 16, 2007, at 10:39 PM, Dave Hoefler wrote:

Robert and Xavier (fxn) -

Thank you for the explanations! That just cleared things up tremendously.

So say I have this module (rails plugin):

module Office
def self.included(base)
   base.extend(ClassMethods)
end

module ClassMethods
   def working(options={})
     # do something based off the options
   end
end

end

In one of my models I can then access the method 'working' by:

class ModelName < ActiveRecord::Base
  working :task => "Take a break!"
end