Modules in Ruby - ruby

Please explain why self is used in def self.included (klass) below.
module A
def self.included(klass)
puts "A -> #{klass}"
puts A
puts self
end
end
class X
include A
end

By writing def self.included you are defining a method that is part of the singleton class of module A. In general, singleton methods can only be called by doing A.included() but this singleton method has a special name included that causes the Ruby interpreter to call when the module gets included in to a class.
A normal method in a module (defined with def foo) can only be called if the module gets included in to something else.

This is how you declare a module method that can be called directly. Normally methods defined within a module are only usable if another class or module includes them, like class X in this example.
module Example
def self.can_be_called
true
end
def must_be_included
true
end
end
In this case you will see these results:
Example.can_be_called
# => true
Example.must_be_included
# => NoMethodError: undefined method `must_be_included' for Example:Module
The self declared methods are not merged in to the classes or modules that include it, though. They are special-purpose that way.

Related

How to overwrite eigenclass method in ruby?

I have a module
module A
class << self
def is_okay?; false; end
end
end
and I need to overwrite is_okay? method in another module. Module B is included into A in this way
A.send(:include, B)
I have tried this
module B
class << self
def is_okay?; true; end
end
end
and that
module B
def self.is_okay?; true; end
end
but it didn't work. How can I achieve this?
This may or may not work in your situation:
module B
def is_okay?
true
end
end
module A
class << self
prepend B
def is_okay?
false
end
end
end
prepend is similar to include, but inserts itself before the class, at the "bottom" of the ancestor chain.
EDIT:
Since you clarified in your comments below (I would suggest clarifying your original question), you can alias the same as any other method.
module A
class << self
alias original_is_okay? is_okay?
def is_okay?
true
end
end
end
This will allow for "overwriting it, whether or not you have access to it.
Consider the following.
module B
def bi
"hello from bi"
end
def self.bm
"hello from bm"
end
end
B.instance_methods(false)
#=> [:bi]
B.methods(false)
#=> [:bm]
Note that defining a module method (here bm) with self. is the same as defining an instance method on the module's singleton class.
Now create a module A that includes B.
module A
def self.am
"hello from am"
end
end
A.methods(false)
#=> [:am]
A.include B
A.instance_methods.include?(:bi)
#=> true
A.methods.include?(:bm)
#=> false
As expected, bi is now an instance method of A. include, however, disregards module methods, here B::bm. Is there any way for the module method B::m to become a module method of A? The answer is "no". In effect, we want
A.singleton_class.include B.singleton_class
but that doesn't work because B.singleton_class is a class.
Module#include does not make it clear whether a module (that is possibly a class) can include a class. Try it, however, and you will see the following an exception is raised:
TypeError (wrong argument type Class (expected Module))
If module methods of a module M are not made available to another module that includes M, is there any reason for modules to have module methods? Yes, to provide libraries of methods! An example is the module Math. That module contains many module methods and no instance methods. When used, those methods are therefore invoked on their receiver, Math. For example,
Math.sin(x)

Ruby prepend doesn't work for class method

I'm trying to use prepend method in ruby to overwrite methods of a class, here is how my code works:
module PrependedModule
def self.klass_method
puts 'PrependedModule klass_method'
end
def instance_method_a
puts 'PrepenedModule instance method'
end
end
class SomeClass
prepend PrependedModule
def self.klass_method
puts 'SomeClass klass_method'
end
def instance_method_a
puts 'SomeClass instance_method'
end
end
SomeClass.klass_method
SomeClass.new.instance_method_a
#output:
#SomeClass klass_method
#PrependedModule instance method
#expected:
#PrependedModule klass_method
#PrependedModule instance method
The output of this script is shown above, as we can see, the instance method instance_method_a was overwritten by module PrependedModule, but not the class method klass_method, when I called klass_method on SomeClass, it still executes it's origin method, instead of the one defined in PrependedModule.
I'm confused about this and don't know what happend with class methods when using prepend. It would be a great help if anyone can solve this question for me.
Singleton classes do not work that way. You need to explicitly prepend the methods to the eigenclass of SomeClass:
module PrependedModule
module ClassMethods
def klass_method
puts 'PrependedModule klass_method'
end
end
def instance_method_a
puts 'PrepenedModule instance method'
end
end
class SomeClass
# prepending to the class
prepend PrependedModule
class << self
# prepending to the eigenclass
prepend PrependedModule::ClassMethods
end
def self.klass_method
puts 'SomeClass klass_method'
end
def instance_method_a
puts 'SomeClass instance_method'
end
end
With include or prepend you can only gain access to a module's instance methods1. You therefore might ask if there is any reason to define module methods on a module. The answer is a resounding "yes". There are two reasons you might want to do that.
The first has nothing to do with including or prepending the module. You need only look at the module Math to understand why you might want to do that. All methods defined on Math are module methods. These constitute a library of useful functions. They are of course methods, but since all have Math as their receiver, they behave like functions in non-OOP languages.
The second reason is that you might want to define a callback method (aka hook method) on a module that is to be included or prepended by another module. The main ones are Module#included, Module#prepended, Module#extended, Class#inherited and BasicObject#method_missing. The last of these is an instance method; the others are module methods. An example of Module#prepended is given below.
#mudasoba has shown how to confine instance methods to a sub-module Sub of Mod so that Mod::Sub can be prepended (or included) to a class's (or module's) singleton class. A commonly-used pattern for doing that employs the callback Module#prepended. It follows.
module PrependedModule
module ClassMethods
def klass_method
puts 'PrependedModule klass_method'
end
end
def instance_method_a
puts 'PrepenedModule instance method'
end
def self.prepended(mod)
mod.singleton_class.prepend(ClassMethods)
end
end
class SomeClass
def self.klass_method
puts 'SomeClass klass_method'
end
def instance_method_a
puts 'SomeClass instance_method'
end
prepend PrependedModule
end
SomeClass.klass_method
# PrependedModule klass_method
SomeClass.new.instance_method_a
# PrepenedModule instance method
1 I've always found it curious that instance methods can be defined on modules (that are not classes), considering that such modules cannot have instances. True, these methods become instance methods in classes that include or prepend the module, but keep in mind that those modules can be included or prepended by other modules (that are not classes) as well. One might therefore expect such methods to have some name other than "instance method". Finding a suitable alternative would be a challenge, however, which is perhaps one reason why that nomenclature has persisted.
Someone can comment on when this was introduced, but my personal experience and also suggested by https://stackoverflow.com/users/256970/cary-swoveland in comments section of the selected answer, you can always do
class Source
def self.hello
puts "hello"
end
end
module Extension
def hello
# you're also allowed to call super from here
puts "world"
end
end
Source.singleton_class.prepend Extension
Now if you call Source.hello, the method from the Extension module will be called.
This is also valid for overriding Module's static/class methods But I've mentioned the code explicitly because I've rarely come accross this solution on S/O.
module Source
def self.hello
puts "hello"
end
end
module Extension
def hello
# you're also allowed to call super from here
puts "world"
end
end
Source.singleton_class.prepend Extension
class Foo
singleton_class.prepend ClassMethods
def self.hello
puts "hi"
end
end
module ClassMethods
def hello
puts "ho"
end
end

Meaning of Syntax for Ruby Module

I've been going through some tutorials to find this information, but haven't seen anything that directly addresses it.
I've seen several times on modules the following syntax:
module MyModule
def run()
puts "running"
end
end
I've also seen syntax that looks like this:
module MyModule
def MyModule.run()
puts "running"
end
end
What's the advantage to including the module name before the method and vice versa?
module MyModule
def MyModule.run()
puts "running"
end
end
is exactly the same as:
module MyModule
def self.run()
puts "running"
end
end
Usually def self.run is used, because it's better when you have to change the module name and it's more idiomatic. I don't see any advantages in writing def MyModule.run.
This has nothing to do with modules. This is just normal method definition syntax.
The syntax for a method definition in Ruby is
def <target>.<selector>(<parameters>)
# …
end
For example:
def foo.bar(baz)
end
This will define a method named bar on the object referenced by foo (more precisely, in the singleton class of the object referenced by foo), with a single mandatory positional parameter whose binding is named baz.
Like with message sends, you can leave out the target, and Ruby will use an implicit default. In a message send, the implicit default is self, with a method definition, the default is the so-called default definee, which is usually the closest lexically enclosing module definition body.
So,
def MyModule.run
means "define a method named run on the object MyModule (or more precisely in the singleton class of the object MyModule)", whereas
def run
means "define a method named run in the default definee", i.e. the closest lexically enclosing module definition body, which in this case is MyModule.
The second version defines run as an instance method of MyModule, the first version defines run as an instance method of the singleton class of MyModule, which we sometimes call a "module method" or "module function".
Note that the first version is usually more idiomatically written as
def self.run
This is about using a module as a static namespace vs using a module as a mixin. Have a look at the following code (with output in comments):
module MyModule
def MyModule.run()
puts "#{self}: running"
end
def run()
puts "#{self}: running"
end
end
class Foo
include MyModule
end
MyModule.run #MyModule: running
foo = Foo.new
foo.run #<Foo:0x007f9b269bf028>: running
In the first usage, the module is basically just acting as a namespace to which you attach a method.
In the second, the module is mixed in to the class Foo. This means that it acts as if the run method was defined within the foo class in the first place; you could, if you wished, refer to instance variables #bar which aren't defined in the module, but only in the Foo class.
I guess both are same but in case when we call module method inside class then we have to give
ModuleName.method_name()
So that it can understand that this method is required for included or that particular module

Using extend self in module

Before voting for closing due to question duplication I want to say that my question is really simple one (not asked in above mentioned questions).
There are two modules, one defines module method using extend self, another defines mixin method.
module A
extend self
def module_a_meth
"Called module_a_meth"
end
end
module B
def module_b_meth
"Called module_b_meth"
end
end
There is a class, where I both include and extend these modules:
class Test
include A
extend A
include B
extend B
end
When we includeing module, its methods become class' instance methods, when extending - class methods.
Question:
it doesn't matter for class, if methods in module defined as module methods or mixin methods, right? I mean, when included - EVERY method (either module methods or mixin methods) become instance methods, and when extended - either become class methods.
If I'm wrong - where is the difference?
obj = Test.new
puts obj.module_a_meth
puts obj.module_b_meth
puts Test.module_a_meth
puts Test.module_b_meth
#=> Called module_a_meth
#=> Called module_b_meth
#=> Called module_a_meth
#=> Called module_b_meth
EDIT
Please start your answer with Yes or No, since my question implies this type of answer :).
Regardless of whether you are using extend or include you are always copying over instance methods. The difference is where those instance methods live.
When you call Class#include you are "copying" all of the instance methods in the module to be instance methods in the class. It's similar to how inheritance work, and if you call Class#ancestors you'll see the module there.
When you call Object#extend you are copying all of the instance methods of the module to the object's singleton class. This is a class reserved just for this object instance that is created at runtime. This is how you get "class methods" (e.g. MyClass.hello_world); by adding them to the class's singleton. You can also do things like extend a particular object instance (e.g. s = String.new; s.extend(SomeModule); s.hello_world)
There are some other differences too. The context binding is different depending on whether you use extend or include. extend doesn't cause the module to show up in the ancestor chain while include does.
When trying to add both "class" and instance methods, one common pattern you'll see is doing things like this which uses the included callback to extend the base class with a ClassMethods module:
module MyModule
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def hello_world
end
end
end
ActiveSupport::Concerns also abstracts this pattern allowing you to add both instance and "class" methods in one call.
I personally prefer having modules only work with instance methods and using singleton methods (e.g. def self.my_method) to have scoped methods (sort of like how you would use private methods). This allows consumers to use either extend or include however they want and have it work as expected.
I'm not sure if that answers your question or not, but there's some info for you
Let's look at this in steps.
module A
puts "self = #{self}"
extend self
def module_a_meth
"Called module_a_meth"
end
end
class Test
end
Test.include A
#-> self = Test
Test.instance_methods.include?(:module_a_meth)
#=> true
Test.methods.include?(:module_a_meth)
#=> false - no class method
So include includes :module_a_meth as an instance method. As self is Test, the line:
extend self
is equivalent to:
extend Test
which of course makes no reference to the module. Now we extend and obtain the expected result:
Test.extend A
#=> true
Test.methods.include?(:module_a_meth)
#=> true
including and extending B is normal:
module B
def module_b_meth
"Called module_b_meth"
end
end
Test.include B
Test.instance_methods.include?(:module_b_meth)
#=> true
Test.extend B
Test.methods.include?(:module_b_meth)
#=> true
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

In what sort of situation is the code:
module M
extend self
def greet
puts "hello"
end
end
more beneficial to use over say something like:
module M
def self.greet
puts "hello"
end
end
In the top, one is an instance method being extended, and the latter is just a class method, but when calling either method, you'd have to M.greet , right? I was just curious if anyone could shed some light on when to use one code over the other. Thanks!
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.
It would be possible to do this with your first example, but not your second:
include M
greet
A module can be used as a namespace by writing module methods, and a module's instance methods can be mixed into another object.
The self-extending module concept allows a module to be used in both ways; either as a stand-alone namespace or as a mixin. Consider this module:
module M
def bar
puts "bar"
end
end
class C
include M
end
It has an instance method and can be mixed in to another object. It does not have a module method and cannot, therefore be used as a namespace:
puts M::bar # => undefined method `bar' for M:Module
puts C.bar # => this is bar
But, a module is an just an object of class Module, as we can demonstrate
puts M.class # => Module
This means that we can do something crazy. We can mix a module into itself so that its methods become both instance and module methods.
module M
extend self
def bar
puts "bar"
end
end
puts M::bar # => this is bar
puts C.bar # => this is bar

Resources