Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why 'self' method of module cannot become a singleton method of class?

Tags:

ruby

module Test
  def self.model_method
    puts "this is a module method"
  end
end

class A
  include Test
end

A.model_method

this will be error with:

undefined method `model_method' for A:Class (NoMethodError)

But when I use metaclass of A. it works:

module Test
  def model_method
    puts "this is a module method"
  end
end

class A
  class << self
    include Test
  end
end

A.model_method

Can someone explain this?

like image 536
LeoShi Avatar asked Apr 06 '12 04:04

LeoShi


People also ask

What is self in a Ruby module?

To answer your question, you can use self to define your method as a class method inside your module, and without self to define the method as instance method and it depends on your need and usecase that when you want what type of behaviour from your module methods. Follow this answer to receive notifications.

What is class self in Ruby?

Class Method Self A class method is a method that refers only to that class in all contexts, but not to any individual instances of that class. A class instance method is a method that applies to all instances of that class, but not for the class object itself.

What is Module_function in Ruby?

module_function can be used in a way similar to private : module Something def foo puts 'foo' end module_function def bar puts 'bar' end end. That way, you can call Something.


2 Answers

If you want to have both class methods and instance methods mixed into a class when including a module, you may follow the pattern:

module YourModule
  module ClassMethods
    def a_class_method
      puts "I'm a class method"
    end
  end

  def an_instance_method
    puts "I'm an instance method"
  end

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

class Whatever
  include YourModule
end

Whatever.a_class_method
# => I'm a class method

Whatever.new.an_instance_method
# => I'm an instance method

Basically to over-simplify it, you extend to add class methods and you include to add instance methods. When a module is included, it's #included method is invoked, with the actual class it was included in. From here you can extend the class with some class methods from another module. This is quite a common pattern.

See also: http://api.rubyonrails.org/classes/ActiveSupport/Concern.html

like image 150
d11wtq Avatar answered Sep 26 '22 10:09

d11wtq


Including a module is analogous to copying its instance methods over.

In your example, there are no instance methods to copy to A. model_method is actually an instance method of Test's singleton class.


Given:

module A
  def method
  end
end

This:

module B
  include A
end

Is analogous to this:

module B
  def method
  end
end

When you think of it this way, this makes perfect sense:

module B
  class << self
    include A
  end
end

B.method

Here, the methods are being copied to the B module's singleton class, which makes them the "class methods" of B.

Note that this is exactly the same thing as:

module B
  extend A
end

In reality, the methods are not being copied; there is no duplication. The module is simply included in the method lookup list.

like image 37
Matheus Moreira Avatar answered Sep 23 '22 10:09

Matheus Moreira