Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Not understanding Classes, Modules, and the class << self method

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.

like image 704
Nathan Avatar asked Mar 27 '12 23:03

Nathan


People also ask

What is class << self in Ruby?

Now, to answer the question: class << self opens up self 's singleton class, so that methods can be redefined for the current self object (which inside a class or module body is the class or module itself).

What is the relationship between classes and modules?

Classes may generate instances (objects), and have per-instance state (instance variables). Modules may be mixed in to classes and other modules. The mixed in module's constants and methods blend into that class's own, augmenting the class's functionality. Classes, however, cannot be mixed in to anything.

How do you define a class method in Ruby?

There are two standard approaches for defining class method in Ruby. The first one is the “def self. method” (let's call it Style #1), and the second one is the “class << self” (let's call it Style #2). Both of them have pros and cons.

What is an Eigenclass?

eigenclass (plural eigenclasses) (object-oriented programming) A hidden class associated with each specific instance of another class.


2 Answers

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
like image 76
jnevelson Avatar answered Nov 15 '22 21:11

jnevelson


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

like image 39
Giron Avatar answered Nov 15 '22 22:11

Giron