Reputation: 1210
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?
Upvotes: 17
Views: 19666
Reputation: 1653
Class: RuboCop::Cop::Style::ModuleFunction
rule recommends to use module_function to make all methods self.
ref: https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/ModuleFunction
# bad
module Test
extend self
# ...
end
# good
module Test
module_function
# ...
end
Upvotes: 0
Reputation: 1023
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.
Upvotes: 30
Reputation: 34318
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.
Upvotes: 6
Reputation: 198324
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]
Upvotes: 3