Как найти вложенность метода в Ruby?

в Ruby постоянный поиск зависит от вложенности, а методы сохраняют вложенность.

например, если у меня есть эти модули:

module A
  X = 1
end

module B
  X = 2
end

module Foo
end

Я могу определить метод Foo.a это имеет гнездо [A, Foo]:

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

Foo.a #=> 1

и метод Foo.b это имеет гнездо [Foo, B]:

module B
  module ::Foo
    Module.nesting #=> [Foo, B]
    def Foo.b
      X
    end
  end
end

Foo.b #=> 2

разница становится очевидной, если я определяю Foo::X:

Foo::X = 3

Foo.a #=> 1  <- still resolves to A::X
Foo.b #=> 3  <- now resolves to Foo::X

но как определить вложенность данного метода?

2 ответов


Это будет работать:

Foo.method(:a).to_proc.binding.eval('Module.nesting')
#=> [A, Foo]

Foo.method(:b).to_proc.binding.eval('Module.nesting')
#=> [Foo, B]

протестировано с Ruby 2.2.1 и 2.3.1. Он не работает с Ruby 2.1.5.


вы думаете об этом неправильно. Нет такой вещи, как "вложение методами". Константы где-то вложены. Вложенность имеет разрешение пути, связанное с именами модулей и классов. Методы содержатся в модуле / классе (будь то "нормальные" или синглтон).


где метод помещается семантический. Существует понятие, подобное self, который определяет, где будет определен метод, называемый definee по умолчанию. Там это не ключевое слово для него, но это примерно эквивалентно:

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

где константа помещается / ищется, является чисто синтаксической. Когда вы ссылаетесь на X, ему все равно, если вы разместили его методом или нет:

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

все это заботится о том, что "текущие вложения" в строке кода, где вы пытались ссылаться на него.


теперь, если вы действительно хотели найти "текущие вложения внутри тело метода", тогда вам нужно как-то притвориться, что вы действительно там.

к сожалению, я не думаю, что есть какой-либо другой способ, кроме показанного в @Эрика. Используя блок instance_eval/instance_exec даст вам вложенность того, где был определен блок.