Difference between "class << anObject" and anObject.class_eval

I see the following code in the attribute_fu plugin:

module AttributeFu
    module Associations #:nodoc:                                                                                                                                                
        def self.included(base) #:nodoc:                                                                                                                                          
            base.class_eval do
                extend ClassMethods
                class << self; alias_method_chain :has_many, :association_option; end

                class_inheritable_accessor  :managed_association_attributes
                write_inheritable_attribute :managed_association_attributes, []

                after_update :save_managed_associations
            end
        end

        ...
    end
end

      

When I try to replace

class << self; alias_method_chain :has_many, :association_option; end

      

with: alias_method_chain: has_many,: association_option?

I am getting the following error

/usr/lib/ruby/gems/1.8/gems/activesupport-2.1.1/lib/active_support/core_ext/module/aliasing.rb:31:in `alias_method': undefined method `has_many' for class `ActiveRecord::Base' (NameError)
        from /usr/lib/ruby/gems/1.8/gems/activesupport-2.1.1/lib/active_support/core_ext/module/aliasing.rb:31:in `alias_method_chain'
        from /home/twong/git/physpace/vendor/plugins/attribute_fu/lib/attribute_fu/associations.rb:9:in `included'

      

I thought these two lines would do the same, but it looks like I'm wrong. Can someone explain my mistake?

0


source share


2 answers


# init.rb
ActiveRecord::Base.class_eval { include AttributeFu::Associations }

module AttributeFu
    module Associations
        def self.included(base)
            # base == ActiveRecord::Base (the class)
            base.class_eval do
                # class_eval makes self == ActiveRecord::Base, and makes def define instance methods.
                extend ClassMethods

                # If has_many were an instance method, we could do this
                #   alias_method_chain :has_many, :association_option; end
                # but it a class method, so we have to do the alias_method_chain on
                # the meta-class for ActiveRecord::Base, which is what class << self does.
                class << self; alias_method_chain :has_many, :association_option; end
            end
        end
    end
end

      

Another way to play with this is to put it in the IRB:

class A ; end
A.class_eval { puts self.inspect ; class << self ; puts self.inspect ; end }

      



see also

+3


source


In this case, self

doesn't mean anObject, it's more sugar.

class << self
  ...
end

      

defines class methods for the enclosing object. Method alias_method_chain

is a method similar to what is. In this case, he aliases has_many

before has_many_without_association_options

and has_many_with_association_options

with has_many

. In your case, these are methods of the alias class, so you should use it in the scope of the class methods. This allows methods to be extended without much hassle.

Class methods are named, for example:

SomeThing.bar_method

      

whereas instance methods are called on class instances:

assoc = SomeThing.new
assoc.foo_method

      



Relevant code:

class SomeThing
  def foo_method
    ...
  end
  class << self
    def bar_method
      ...
    end
  end
end

      

in your case you have a module AttributeFu::Associations

. When included in the Foo class, it runs Foo.class_eval, which defines some of the instance attributes inside Foo, and runs a method alias_method_chain

inside the class's method scope ( class << self

).

There is also one extends ClassMethods

that should define:

def self.has_many_with_association_options
    ...
end

      

or

class << self
  def has_many_with_association_options
    ...
  end
end

      

0


source







All Articles