Подтвердить что ты не робот

Синтаксис вложенного модуля Ruby (и Rails)

Мне интересно, какая разница между двумя следующими модулями:

# First Example
module Parent
  module Child
  end
end

и

# Second Example
module Parent::Child
end

Используя второй метод, кажется, что родительский модуль должен быть предварительно определен, в противном случае я получаю ошибку "неинициализированной константы"

Учитывая это, что является предпочтительным способом определения таких модулей, а затем добавления вложенных дочерних элементов в отношении синтаксиса и файловой структуры (т.е. папок и т.д.). Приветствуем ссылку на путь Rails.

Являются ли эти два примера для всех целей и целей эквивалентными?

4b9b3361

Ответ 1

В первом примере он определяет модуль Parent, а затем модуль Child. Второй пример, как вы говорите, должен иметь модуль Parent, определенный перед началом работы. За счет еще одной строки кода вы гарантируете, что модуль, который вы размещаете, используя ваш первый пример, всегда будет определен.

Для примера Rails рассмотрим файл railties/lib/rails/engine.rb, который повторно открывает модуль Rails и то определяет класс Engine внутри него. Это можно было бы сделать просто:

class Rails::Engine

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

Ответ 2

Я предпочитаю второй метод (если я уверен, что Parent уже определен), потому что он выглядит более чистым, особенно. когда вложенность очень глубокая.

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

Ответ 3

Вообще говоря, вы не хотите определять модуль с использованием синтаксиса Parent:: Child модуля, если вы не можете быть абсолютно уверены, что Parent уже существует. Подмодуль может быть определен только с помощью синтаксиса:: if, если родительский модуль определен. В вашем примере, если вы выполните следующее, вы не получите неинициализированную постоянную ошибку.

module Parent
end

module Parent::Child
end

Ответ 4

Кажется, что ответ Banister также является причиной такого поведения:

ruby-1.9.2-p290 :001 > module A; module A; A.ancestors; end; end
 => [A::A] 
ruby-1.9.2-p290 :002 > module A::A; A.ancestors; end
 => [A] 

Внутренний модуль A является константой внутри внешнего модуля A и, следовательно, не отображается с использованием второго метода.

Редактирование моего предыдущего комментария:

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