In Ruby, constant lookup is affected by nesting and methods retain their nesting.
For example, if I have these modules:
module A
X = 1
end
module B
X = 2
end
module Foo
end
I can define a method Foo.a
that has a nesting of [A, Foo]
:
module Foo
module ::A
Module.nesting #=> [A, Foo]
def Foo.a
X
end
end
end
Foo.a #=> 1
And a method Foo.b
that has a nesting of [Foo, B]
:
module B
module ::Foo
Module.nesting #=> [Foo, B]
def Foo.b
X
end
end
end
Foo.b #=> 2
The difference becomes apparent if I define Foo::X
:
Foo::X = 3
Foo.a #=> 1 <- still resolves to A::X
Foo.b #=> 3 <- now resolves to Foo::X
But how do I determine the nesting of a given method?
In short: no, Ruby does not support nested methods.
We call (or invoke) the method by typing its name and passing in arguments. You'll notice that there's a (words) after say in the method definition. This is what's called a parameter. Parameters are used when you have data outside of a method definition's scope, but you need access to it within the method definition.
- in ruby, there are 2 types of return from the method: explicit return (using the return keyword) and implicit return; - exception from all rules about return value — assignment methods; - a return value can be directly assigned to variables.
You are thinking about it the wrong way. There is no such thing as "nesting of methods". Constants are nested somewhere. Nesting has path resolution connected to names of modules and classes. Methods are contained within a module/class (be it "normal" or singleton).
Where a method is placed is semantical. There is a concept, similar to self
, which determines where a method will be defined, called default definee. There is no keyword for it, but it's roughly equivalent to:
kind_of?(Module) ? name : self.class.name
Where a constant is placed/searched for is purely syntactical. When you refer to X
, it does not care the least bit if you placed it a method or not:
DEEP_MIND = Object.new
module Foo
X = 42
end
module Foo
module Bar
def DEEP_MIND.talk
p X
end
end
end
DEEP_MIND.talk # => 42
module Foo::Bar
def DEEP_MIND.talk
p X
end
end
DEEP_MIND.talk # => uninitialized constant
All it cares about is what the "current nesting" on the line of the code where you tried to reference it.
Now, if you actually wanted to find "the current nesting inside the body of the method", then you need some way to pretend you are actually there.
Sadly, I don't think there is any other way other than the one showed in @Eric's answer. Using block with instance_eval
/instance_exec
will give you the nesting of where the block was defined.
This would work:
Foo.method(:a).to_proc.binding.eval('Module.nesting')
#=> [A, Foo]
Foo.method(:b).to_proc.binding.eval('Module.nesting')
#=> [Foo, B]
Tested with Ruby 2.2.1 and 2.3.1. It doesn't work with Ruby 2.1.5.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With