"include" versus "extend" - what's the difference

Hi --

Hi,

Just wondering when one would use "include" over "extend"? Both seem to bring in methods to the class no?

Neither of them actually brings methods into a class. They both have the effect of adding a module to a method lookup path. When you do this:

   class C      include M    end

you're adding M to the method lookup path of instances of C. When you do this:

   c = C.new    c.extend(M)

you're adding M to the method lookup path of one particular instance of C. In other words, extend is a kind of object-specific version of include.

The context is I'm just trying to understand why both are used with the acts_as_audited plugin:

As with so many Ruby questions, it comes down to: classes are objects too :slight_smile: What you're seeing, among other things, is a class being extended so that the class object itself will respond to a particular set of methods. This technique is used a lot in the Rails source. I've also got a detailed discussion of it in my book.

David

Thanks David - understand this, but still having a few troubles understanding this in context. Don’t suppose you/someone could clarify how things work in the following situation. Its code from acts_as_audited. Basically the cutback guts of it which I’m having trouble with is as follows. The cutback code is below. Questions I have include:

Q1) Is the acts_as_audited function in class Contact run when the “Contact” class is being read into the interpreter OR is it just actually carried out when a Contact class is instantiated?

Q2) Whenever acts_as_audited is run from Contact does the “include” line include the methods into the Contact object? (or was the Contact context really a class as opposed to instantiated object?)

Q3) I assume “class_eval” is just included to somehow ensure things like the upcoming “extend” method is applied to the object which is calling (e.g. in this case the “contact” object)??? i.e. trying to understand why “class_eval” was required here

Q4) When the “extend” line in then hit within “class_eval” does it add these methods directly to the Contact object? (or was the Contact context really a class as opposed to instantiated object?)

Q5) I’m not sure if I should even ask about the last line “ActiveRecord::Base.send :include…” which is outside the modules, and when it is actually run and how it fits into things here :frowning: … but if you do understand and your on a roll with these questions I’m really trying to understand this stuff :slight_smile:

contact.rb ======model========

class Contact < ActiveRecord::Base acts_as_audited :user_class_name => ‘current_user’, :user_method => ‘login’ cattr_accessor :current_user # although I haven’t got the ‘current_user’ part working yet I must admit

end

#acts_as_audited.rb ======================================= module CollectiveIdea #:nodoc: module Acts #:nodoc: module Audited CALLBACKS = [:clear_changed_attributes, :audit_create, :audit_update, :audit_destroy]

  def self.included(base) # :nodoc:
    base.extend ClassMethods
  end
  module ClassMethods
    def acts_as_audited(options = {})
      return if self.included_modules.include?(CollectiveIdea::Acts::Audited::InstanceMethods)

      include CollectiveIdea::Acts::Audited::InstanceMethods
      class_eval do
        extend CollectiveIdea::Acts::Audited::SingletonMethods
        cattr_accessor :non_audited_columns, :audited_user_class_name, :audited_user_method

        .
        .
        .
      end
    end
  end

  module InstanceMethods
    . various def'ed methods
    .
    .
  end # InstanceMethods

 
  module SingletonMethods
  end
end

end end ActiveRecord::Base.send :include, CollectiveIdea::Acts::Audited #acts_as_audited.rb =======================================