Как правило, плохая идея определять класс как «класс A», но затем «волшебным образом» включать его в модуль B. Если вы хотите сослаться на класс A как B :: A, вы должны определить его, используя либо :
module B
class A
# contents
end
end
или
class B::A
# contents
end
В противном случае любой, кто читает ваш код, будет сбит с толку. В этом случае вы ничего не получите в ясности, краткости или удобстве, используя «хитрости», так что простой код лучше. Здесь есть урок: возможности метапрограммирования в Ruby великолепны, но нет необходимости использовать их безвозмездно. Используйте их только тогда, когда вы действительно что-то получите. В противном случае вы просто усложняете понимание кода.
НО, прочитав ваш комментарий, похоже, в вашем случае есть действительно веская причина сделать что-то подобное. Я полагаю, что следующее решение будет даже лучше, чем вы предполагаете:
m = Module.new
m.module_eval("class C; end")
m.constants
=> [:C]
m.const_get(:C)
=> #<Module:0xfd0da0>::C
Видишь? Если вам нужно «гарантированное уникальное» пространство имен, вы можете использовать анонимный модуль. Вы можете хранить эти модули в хэше или другой структуре данных и извлекать из них классы по мере необходимости. Это решает проблему, о которой вы упоминали, что пользователи вашего приложения будут добавлять свои собственные классы, и вы не хотите, чтобы имена конфликтовали.