Как найти вложенность метода в 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
даст вам вложенность того, где был определен блок.