Ruby: extend self
It is a convenient way to make instance methods into class methods. But you can also use it as a more efficient singleton.
extend self in a module
Your first example defines two instance methods and makes them also available as class (or module) methods via extend
:
module MyModule
def first_method; end
def second_method; end
end
MyModule.instance_methods #=> [:second_method, :first_method]
MyModule.methods - Module.methods #=> []
MyModule.extend MyModule
MyModule.instance_methods #=> [:second_method, :first_method]
MyModule.methods - Module.methods #=> [:second_method, :first_method]
Whereas your second example just defines two class (or module) methods and no instance methods:
module MyModule
def self.first_method; end
def self.second_method; end
end
MyModule.instance_methods #=> []
MyModule.methods - Module.methods #=> [:second_method, :first_method]
The first variant can be useful when you want to provide some utility functions that can be called as:
MyModule.first_method
or be included in other modules / classes:
class Foo
include MyModule
def another_method
first_method # <- no explicit receiver needed
end
end
Ruby also provides the helper method module_function
to define methods that way:
module MyModule
def first_method
end
module_function :first_method
end
It adds the method as a class methods and makes the instance method private. It's how the methods in Kernel
work.
Using extend self in module
First of all, regarding the actual question: No :).
Class (or any other object) cares how methods are defined in a module you're including. Basically, method's in a module you've described are defined as mixin
methods. extend self
doesn't redefine methods to be a module methods, but, basically, duplicates them to both contexts.
It's pretty much a question about how does extend
work, it's just a tricky case.
First of all, think of extend
as an include
in object's singleton class context. Those two definitions are equal:
module SomeModule
def hi
'hi'
end
end
class SomeClass
extend SomeModule
end
class SomeClass
class << self
include SomeModule
end
end
Given that, by using extend self
in a module you're saying: Take all of the mixin methods I've defined and extend module's singleton class with them. This magic is a result of ruby's nature: an ability to re-open any definition. Here's how a verbose version of extend self
would look like:
module Module1
def hi
'hi'
end
end
module Module1
extend Module1 # which is self
#### now "hi" is both here:
# def hi; end
#### and here:
# class << self; def hi; end
end
Module1.hi # => 'hi'
class SomeClass; include Module1; end;
SomeClass.new.hi # => 'hi'
__ EDIT __
Just a quick proof that object cares about how methods in a module are defined:
module SomeModule
def self.hi
'hi'
end
end
object = 'some string'
class << object
include SomeModule
end
object.hi # => NoMethodError: undefined method
Ruby modules and extend self
The first example is typically a way people achieve the functionality of module_function
(when they do not know the existence of this method).
A module_function
is both an instance method and a class method. In your second code example the method is just a class method.
Ruby self.extended gets called as instance method
def bar
without an explicit definee (i.e. def foo.bar
) defines bar
in the closest lexically enclosing module. The closest lexically enclosing module for all three of your def
s is always Country
, so all three methods are defined in the Country
module.
If you want to define a singleton method, you could use
<pre class="lang-rb prettyprint-override">module Country
def self.extended(base)
def base.animals
puts "animals"
end
end
end
See Ruby what class gets a method when there is no explicit receiver? for more details.
Is extend self the same as module_function?
module_function
makes the given instance methods private, then duplicates and puts them into the module's metaclass as public methods. extend self
adds all instance methods to the module's singleton, leaving their visibilities unchanged.
module M
extend self
def a; end
private
def b; end
end
module N
def c; end
private
def d; end
module_function :c, :d
end
class O
include M
include N
end
M.a
M.b # NoMethodError: private method `b' called for M:Module
N.c
N.d
O.new.a
O.new.b # NoMethodError: private method `b' called for O
O.new.c # NoMethodError: private method `c' called for O
O.new.d # NoMethodError: private method `d' called for O
Related Topics
Passing Parameters from View to Controller
Why Won't Heroku Accept My Gemfile.Lock in Windows
Converting Ruby Array to Array of Consecutive Pairs
How to Set Sslcontext Options in Ruby
403 Forbidden on Rails App W/ Nginx, Passenger
Nokogiri Will Not Install - Error: Failed to Build Gem Native Extension
Is This the Best Way to Unescape Unicode Escape Sequences in Ruby
How to Use the Debugger with Ruby 2.0
The Class/Object Paradox Confusion
Installing Rvm (Ruby Version Manager)
In Ruby on Rails, Are '#Encoding: Utf-8' and 'Config.Encoding = "Utf-8"' Different
Serving Static Files With Sinatra
Why Use "Self" to Access Activerecord/Rails Model Properties
How to Search a Folder and All of Its Subfolders For Files of a Certain Type