What does "self" mean in a module? [duplicate] - ruby

This question already has answers here:
Ruby self in layman terms?
(3 answers)
Closed 7 years ago.
What is the difference between:
module Math
def self.square(num)
num**2
end
end
puts Math.square(6)
and
module Math
def square(num)
num**2
end
end
puts Math.square(6)
What is "self" in the first example? I'm only used to using self inside of a class, where self refers to the instance of the class.

Well, let’s see:
module Foo
p self
end
# prints: Foo
So self is the module itself. This allows us to define methods directly on Foo, rather than instances of it:
module Foo
def self.bar
42
end
end
Foo.bar #=> 42
class A; include Foo; end
A.new.respond_to?(:bar) #=> false
Note that this is not unique to Modules, and is the same for Classes. And since self == Foo, nothing is stopping us from doing:
def Foo.baz
3.14
end
Foo.baz #=> 3.14

Related

Ruby: how does constant lookup works when using the shortcut notation `class A::B`

When working in a class defined in a module, I'd like to access another class defined in the same module.
When using this code
module SomeModule
class Foo
def self.get_bar
Bar
end
end
end
module SomeModule
class Bar
end
end
# works and returns SomeModule::Bar
SomeModule::Foo.get_bar
Looking up Bar from SomeModule::Foo works. It is not found in local scope SomeModule::Foo, so it looks one level up to SomeModule and finds SomeModule::Bar.
But when using the shortcut notation class A::B to define the classes, the lookup does not work anymore:
module SomeModule
end
class SomeModule::Foo
def self.get_bar
Bar
end
end
class SomeModule::Bar
end
# does not work and raises a NameError
SomeModule::Foo.get_bar
It produces the error NameError: uninitialized constant SomeModule::Foo::Bar. But for me both codes look identical and should produce the same output. I'm obvisouly missing a key concept here.
Can someone explain why the lookup works in one case and not the other? And is it possible to know in advance if the lookup will work or fail by introspecting the class?
There is an awesome post explaining how it works in detail. The summary will be that Ruby's constant lookup is based on lexical scope.
There is a method Module.nesting which returns an array of constants where Ruby is looking for a required const first.
module SomeModule
class Buzz
def self.get_bar
p Module.nesting #=> [SomeModule::Buzz, SomeModule]
Bar
end
end
end
class SomeModule::Foo
def self.get_bar
p Module.nesting #=> [SomeModule::Foo]
Bar rescue puts "Oops, can not find it"
end
end
class SomeModule::Bar
end
SomeModule::Buzz.get_bar
SomeModule::Foo.get_bar
Ruby constant lookup is based on the lexical scope, and these two examples are quite different with regards to that. Take a look:
module SomeModule
puts Module.nesting.inspect #=> [SomeModule]
puts Module.nesting.map(&:constants).inspect # => [[]], we didn't define Foo yet
class Foo
puts Module.nesting.inspect #=> [SomeModule::Foo, SomeModule]
puts Module.nesting.map(&:constants).inspect #=> [[], [:Foo]], at this point SomeModule is already "aware" of Foo
def self.get_bar
Bar
end
end
end
module SomeModule
puts Module.nesting.inspect #=> [SomeModule]
puts Module.nesting.map(&:constants).inspect #=> [[:Foo]], we didn't define Bar yet
class Bar
puts Module.nesting.inspect #=> [SomeModule::Bar, SomeModule]
puts Module.nesting.map(&:constants).inspect #=> [[], [:Foo, :Bar]]
end
end
and the second one
module SomeModule
puts Module.nesting.inspect #=> [SomeModule]
puts Module.nesting.map(&:constants).inspect #=> [[]]
end
class SomeModule::Foo
puts Module.nesting.inspect #=> [SomeModule:Foo]
puts Module.nesting.map(&:constants).inspect #=> [[]]
def self.get_bar
Bar
end
end
class SomeModule::Bar
puts Module.nesting.inspect #=> [SomeModule:Bar]
puts Module.nesting.map(&:constants).inspect #=> [[]]
end
As you see, Bar in 1st and 2nd case is being resolved in quite different lexical scopes which in turn leads to quite different result.
Regarding your question
is it possible to know in advance if the lookup will work or fail by introspecting the class
It is possible for isolated piece of code, but application-wide I wouldn't rely on that. When in doubt just specify the nesting explicitly starting from the outermost context (::SomeModule::Bar)...

Acces local variable from a class.new ruby [duplicate]

This question already has an answer here:
Closures in Ruby with Module
(1 answer)
Closed 4 months ago.
I have a question about scopes in ruby, why the baz method cannot access the variable foo, it seems counter intuitive because the scope of baz is contained in that of create_B
class A
def self.create_B(foo)
Class.new do
def baz
p foo
end
end
end
end
A.create_B(4).new.baz
NameError: undefined local variable or method `foo' for #<#<Class:0x00007f3a31bddf18>:0x00007f3a31bdde28>
from (pry):23:in `baz'
The def keyword creates a new scope. In order to access variables that were defined outside, you can use the define_method method:
class A
def self.create_B(foo)
Class.new do
define_method(:baz) do
p foo
end
end
end
end
A.create_B(4).new.baz
#=> 4

How to determine the class a method was defined in?

I would like to dynamically determine the class the current method was defined in.
Here's a static example of what I'm trying to do:
class A
def foo
puts "I was defined in A"
end
end
class B < A
def foo
puts "I was defined in B"
super
end
end
A.new.foo
# I was defined in A
B.new.foo
# I was defined in B
# I was defined in A <- this is the tricky one
How can I replace A and B in the strings above with a dynamic expression?
Apparently, #{self.class} does not work. (it would print I was defined in B twice for B)
I suspect that the answer is "you can't", but maybe I'm overlooking something.
What about this?
class A
def foo
puts "I was defined in #{Module.nesting.first}"
end
end
class B < A
def foo
puts "I was defined in #{Module.nesting.first}"
super
end
end
Corrected following WandMaker's suggestion.
You could use Module.nesting.first.
However, note that this works purely lexically, the same way constants resolution works, so it won't cut it if you have more dynamic needs:
Foo = Class.new do
def foo
Module.nesting
end
end
Foo.new.foo # => []
I have this nagging feeling that if you could do this, it would violate object-orientated encapsulation, although I can't quite place my finger on exactly why. So, it shouldn't come as a surprise that it's hard.
I can see a way if you are open to modifying the method definitions:
class A
this = self
define_method(:foo) do
puts "I was defined in #{this}"
end
end
class B < A
this = self
define_method(:foo) do
puts "I was defined in #{this}"
super()
end
end
A.new.foo
# I was defined in A
B.new.foo
# I was defined in B
# I was defined in A

instance_eval vs class_eval in module

class Foo
include Module.new { class_eval "def lab; puts 'm' end" }
def lab
super
puts 'c'
end
end
Foo.new.lab #=> m c
========================================================================
class Foo
include Module.new { instance_eval "def lab; puts 'm' end" }
def lab
super
puts 'c'
end
end
Notice here I changed class_eval to instance_eval
Foo.new.lab rescue nil#=> no super class method lab
Foo.lab #=> undefined method lab for Foo class
So it seems that including the module neither defined an instance method nor a class method.
Any explanation what's going on here?
This code was tested on ruby 1.8.7 on mac.
First, think of what include does. it makes the instance methods of the module being included into instance methods on the including class. i.e. apart from the fact that your working example uses an anonymous module it is equivalent to:
module M1
def lab
puts 'm'
end
end
class Foo
include M1
def lab
super
puts 'c'
end
end
Next, think of what class_eval does. It evaluates the given code in the context of the class or module. i.e. it's exactly like you reopened the module and typed the code passed to class_eval. So MyModule = Module.new { class_eval "def lab; puts 'm' end" } is equivalent to
module MyModule
def lab
puts 'm'
end
end
Hopefully this explains the case that works.
When you use instance_eval you are evaluating the code within the context of the receiving object (in this case the instance of module) so MyMod2 = Module.new { instance_eval "def lab; puts 'm' end" } is equivalent to
module MyMod2
def MyMod2.lab
puts 'm'
end
end
i.e. it creates a module method which you'd call via MyMod2.lab and such methods are not added as instance methods by include.
Please note: this answer borrows a bit of its explanation from an answer I wrote to a previous question asking about instance_eval vs. class_eval relating to an example from The Ruby Programming Language book. You might find that answer helpful too.
including a module just takes the instance methods - you are looking for extend. luckily to get the best of both worlds, you can simply do:
module Something
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def blah
puts "lol"
end
end
end
class Test
include Something
end
irb:
>> Test.blah
lol
=> nil

What does self mean in Ruby? [duplicate]

This question already has answers here:
Ruby Definition of Self
(3 answers)
Closed 7 years ago.
What does ruby self represent? what is it? what does it mean? Could some please explain it to me? in simple terms please
And what is its function in a class?
class MyClass
def method.self
end
end
self refers to the object that is currently in context.
In your example, self is the class itself and def self.method is defining a class method. For example:
class MyClass
def self.method
puts "Hello!"
end
end
> MyClass.method
#=> "Hello"
You can also use self on instances of a class.
class MyClass
def method_a
puts "Hello!"
end
def method_b
self.method_a
end
end
> m = MyClass.new
> m.method_b
#=> "Hello!"
In this case, self refers to the instance of MyClass.
There is a good blog post on self in Ruby here, or, as it was pointed out in the comments, there is some more on this in the Ruby documentation.

Resources