Получение иерархии вложенности для любого данного модуля в Ruby - PullRequest
1 голос
/ 08 июля 2019

У меня есть метод, который должен иметь возможность доступа к иерархии вложений определения модуля. Предположим, у меня есть это определение:

module A
  module B
    module C
    end
  end
end

Я пытаюсь написать метод таким образом, чтобы, если в метод передана ссылка на C, он мог вернуть результат Module.nesting, как если бы он был вызван внутри определения. Например:

get_nesting(A::B::C) # => [A::B::C, A::B, A]

Однако я не могу понять, как вызвать Module.nesting в другом контексте. Я пытался использовать instance_exec, но это просто возвращает вложение в текущей области.

module X
  def self.get_nesting(m)
    m.instance_exec { Module.nesting }
  end
end

X.get_nesting(A::B::C) # => [X]

Я хочу, чтобы это вернуло [A::B::C, A::B, A].

Есть ли способ получить вложение для модуля таким способом, используя Module.nesting или иначе?

1 Ответ

1 голос
/ 09 июля 2019

Попробуйте:

module A
  module B
    module C
      Module.nesting
    end
  end
end
  #=> [A::B::C, A::B, A]

module A::B
  module C
    Module.nesting
  end
end
  #=> [A::B::C, A::B] 

Причина, по которой A не включена в последнее возвращаемое значение, заключается в том, что nesting зависит от структуры кода ("лексического"), а не от родительского элемента-детские отношения модулей.По этой причине я думаю, что любой метод, который заставляет self равняться данному модулю (аргумент метода), а затем выполнять Module.nesting, обречен на неудачу.

Однако вы можете сделать следующее.

def get_nesting(mod)
  a = mod.to_s.split('::')
  a.size.times.map { |i| Module.const_get(a[0..i].join('::')) }.reverse
end

get_nesting(A)       #=> [A] 
get_nesting(A::B)    #=> [A::B, A] 
get_nesting(A::B::C) #=> [A::B::C, A::B, A] 

get_nesting(A::B::C).map { |m| m.class } 
  #=> [Module, Module, Module]

Учитывая, что это зависит от Module # to_s , это будет классифицироваться как кладж.

...