Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When to use self in module's methods

Tags:

ruby

self

My module definition looks like this:

module RG::Stats
  def self.sum(a, args = {})
    a.inject(0){ |accum, i| accum + i }
  end
end

To use this method I simply require the file containing this definition so that I can do:

RG::Stats.sum(array)

and also

RG::Stats.method(:sum)

However, if I need to know the list of methods using RG::Stats.instance_methods I get an empty array. This is because I have used self. If I omit self then RG::Stats.instance_methods gives the list of methods, but I cannot access them anymore.

The question is: how to use self in module's method definition?

like image 514
Rojj Avatar asked Sep 24 '15 01:09

Rojj


People also ask

What is self in a Ruby module?

self is a special variable that points to the object that "owns" the currently executing code. Ruby uses self everwhere: For instance variables: @myvar. For method and constant lookup. When defining methods, classes and modules.

What does extend self do?

extend self includes all the existing instance methods as module methods. This is equivalent to saying extend Rake . Also Rake is an object of class Module . This can be used to define self contained modules with private methods.

What is self class 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 the difference between extend and include in Ruby?

In simple words, the difference between include and extend is that 'include' is for adding methods only to an instance of a class and 'extend' is for adding methods to the class but not to its instance.


3 Answers

Use self in each method definition if you want the methods to be defined only in the singleton class of the module (where the methods defined using self live). Omit self and extend self if you want the methods of the module to be defined as instance methods and singleton methods at the same time.

For instance, you can call the method using RG::Stats.sum(array) and still have it listed by the instance_methods method if you do this:

module RG::Stats
  extend self

  def sum(a, args = {})
    a.inject(0){ |accum, i| accum + i }
  end
end

This way, the sum method is defined as an instance method and it is included in the singleton class of the module after using extend self.

You can check the instance methods of RG::Stats module to verify this:

RG::Stats.instance_methods
=> [:sum]

With this technique you don't have to worry about defining the method without the self keyword because modules can't have instances so it cannot be called like an instance method of RG::Stats module. It can only be called as a singleton method RG::Stats.sum(array) thanks to the extend self statement.

like image 82
izaban Avatar answered Oct 16 '22 18:10

izaban


If you use self, then you can use the module method directly using: RG::Stats.sum(array) as you mentioned above.

If you don't use self to define the method inside your module, then the method will be included as instance_method for a class where you include the module.

So, you can define the sum instance method inside your RG::Stats module:

module RG::Stats
  def sum(a, args = {})
    a.inject(0){ |accum, i| accum + i }
  end
end

Then, you can include RG::Stats module inside a class and then the sum method will be available as a instance_method for objects of the class:

class YourClass
  include RG::Stats

  . . .
  . . .
end

And you can call the sum method on an instance of YourClass: YourClass.new.sum

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.

like image 6
K M Rakibul Islam Avatar answered Oct 16 '22 18:10

K M Rakibul Islam


It is because def self.sum does not define an instance method; you are using the wrong method to select it. Try this instead:

RG::Stats.methods(false)
# => [:sum]
like image 3
Amadan Avatar answered Oct 16 '22 18:10

Amadan