8

I have the following code:

class MyClass  
  module MyModule
    class << self

      attr_accessor :first_name

      def myfunction
        MyModule.first_name = "Nathan"
      end

    end
  end
end

When I call the method myfunction like so, it works fine:

> me = MyClass::MyModule.myfunction
=> "Nathan"
> me
=> "Nathan"

But if I removed the class << self and add a self. prefix to myfunction, it doesn't work.

For example:

class MyClass  
  module MyModule

    attr_accessor :first_name

    def self.myfunction
      MyModule.first_name = "Nathan"
    end

  end
end


> me = MyClass::MyModule.myfunction
NoMethodError: undefined method `first_name=' for MyClass::MyModule:Module

I'm trying to understand the class << self method. I thought it was a way add the self. prefix to the all the methods inside of it, but if that was true, why doesn't it work if I remove it and prefix each method with self. manually?

Thanks in advance for your help.

Nathan
  • 7,627
  • 11
  • 46
  • 80
  • 2
    If you really want to learn the details of Ruby metaprogramming, I recommend the [Metaprogramming Ruby book by Paolo Perrotta](http://pragprog.com/book/ppmetr/metaprogramming-ruby). – sarnold Mar 28 '12 at 00:04

2 Answers2

7

This is because your attr_accessor :first_name is also wrapped by the class << self.

To do it the way you suggest, you can use mattr_accessor like so:

require 'active_support'

class MyClass  
  module MyModule

    mattr_accessor :first_name

    def self.myfunction
      MyModule.first_name = "Nathan"
    end

  end
end
jnevelson
  • 2,092
  • 2
  • 21
  • 31
  • So this is a rails specific thing that relies on active_support? I assume the mattr_accessor is a module specific setter/getter method? – Nathan Mar 28 '12 at 03:22
  • That's correct. For better or for worse, `mattr_accessor` is only accessible via Rails. – jnevelson Mar 28 '12 at 06:44
  • There is a bunch of stuff that sometimes I wish were also available in regular Ruby, not just Rails or ActiveRecord. – Andres Riofrio Apr 05 '12 at 22:41
4

To better understand how you can achieve what you want, take a look at the following example:

module PrintingModule

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

  module ClassMethods

    def class_method_of_class
      puts "I am class #{self.name}"
    end

  end

  def instance_method_of_class
    puts "My name is:  #{@name}"
  end

  class << self
    def static_module_method
      puts "Printer version 1.0"
    end
  end
end

class SomeObject
  include PrintingModule
  def initialize(name)
    @name = name
  end
end

object = SomeObject.new("Something")
object.instance_method_of_class
SomeObject.class_method_of_class
PrintingModule.static_module_method

I hope it's more clear now, note that this is just one of possible way (there are others)

UPDATE: I'll try to be more specific. When you define instance/singleton methods on module, what you are really doing is that you are defining instance methods of class which will include that module and on the other hand, class methods defined on module will become class methods of that module. The second think to know is that attr_accessor creates instance method for getter and setter of the given parameter.

Now to answer one part of your question, in the first example you are creating 3 class methods on module's class. In the second one, you are creating 1 class method where you are trying to access another class method (setter), but your getters and setters are defined as instance methods = they will become instance of method of class which will include your module, you cannot get to them this way = you have no access to your getters and setters. As for explanation of self, well I'm not that skilled, but as far as I know, when you use "class << self" you are opening eigenclass (each object has it's own anynonymous one) of the object (note that Class, modules or instances of classes are of course objects too) where you are defining instance methods. Class method of object in Ruby = instance method of the eigenclass of the object. So you can do this for example:

text = "something"
class << text
  def say_hi
    puts "Hi!"
  end
end

text.say_hi

When you create instance of class (String in that example), that instance gets it's own unique anonymous class which is subclass of that Class. In the example, you have defined instance method on the eigenclass of the anonymous subclass of String class. So you can use method "say_hi" on the text object but not on the String class. So "class << self" is opening those eigenclasses.

On the other hand, "self" alone just represents an object in the current context, which means the same in some scenarios (for example yours). As for self.included method, it is just a callback method which gets called when the module is included in the class with a parameter representing the object (here class SomeObject).

I hope that I have answered at least part of your question. More information here: Difference between 'self.method_name' and 'class << self' in Ruby

Community
  • 1
  • 1
Giron
  • 75
  • 6
  • I see how you're using mixins, and most all of it makes sense except for the `def self.included(object)...` stuff up top. The thing is though is that I'm not so much looking to achieve anything as much as I am trying to understand the behavior. I'm not sure your example explained why the `class << self` worked with a mixed in module but the `.self` prefix did not when trying to access the class method. Actually, I'm confused in my examples as to how the instance method :first_name is available with a class call. – Nathan Mar 28 '12 at 03:19
  • I have updated my answer, I hope that it will answer at least part of your questions. Have a nice day. – Giron Mar 28 '12 at 21:44