How to find a nesting method in Ruby?

In Ruby, constant searching depends on nesting and methods preserving 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 an attachment [A, Foo] :

 module Foo module ::A Module.nesting #=> [A, Foo] def Foo.a X end end end Foo.a #=> 1 

And the Foo.b method, which has an attachment [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 to determine the nesting of this method?

+6
source share
2 answers

This will 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 does not work with Ruby 2.1.5.

+4
source

You think about it wrong. There is no such thing as nesting methods. Constants are nested somewhere. Nesting has path resolution associated with module and class names. Methods are contained in a module / class (whether it is "normal" or single-line).


If the method is placed in semantics. There is a concept similar to self that defines where a method called default definee will be defined. There is no keyword for this, but it is roughly equivalent:

 kind_of?(Module) ? name : self.class.name 

If a constant is placed / searched, it is purely syntactic. When you reference X , it doesn’t care if you put it in 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 he cares about is that the "current nesting" in the line of code is where you tried to reference it.


Now, if you really wanted to find the "current nest inside the method body", you need to somehow pretend that you are actually there.

Unfortunately, I don’t think there is another way than the one shown in @ Eric answer . Using a block with instance_eval / instance_exec will give you a nesting of where the block was defined.

+2
source

Source: https://habr.com/ru/post/1012794/


All Articles