如何取消 ruby 常量的命名空间?

How do I un-namespace a ruby constant?

我正在使用不处理命名空间模型的库。我有一个 rails 引擎,其中包含我需要使用的所有 ActiveRecord 模型,因此我使用引擎的名称空间引用它们,例如:TableEngine::Posts.

Ruby 中有没有办法取消帖子 class 的命名空间?

类似于

TableEngine::Posts.demodulize # => Posts

首先你可以添加你需要的常量并将 Class/Module 分配给它(记住两者都只是对象)。您应该复制它以重置名称:

Posts = TableEngine::Posts.dup

之后删除源常量名称:

Object.send :remove_const, :TableEngine

然后:

Posts
# => Posts
TableEngine
# => NameError: uninitialized constant TableEngine
TableEngine::Posts
# => NameError: uninitialized constant TableEngine

更新。为什么需要 dup

注意,class SomeClass 是创建类型 Class 对象并将其分配给某个常量的快捷方式:

SomeClass = Class.new

创建 class 时,未设置其名称值:

klass = Class.new
# => #<Class:0x00000001545a28>
klass.name
# => nil

第一次赋值给常量时,名称被赋值并记忆:

Klass = klass
# => Klass
klass.name
# => "Klass"

当您稍后将 Class 类型的对象分配给另一个常量时,它仍然只是同一个对象,由两个常量引用:

NewKlass = Klass
# => Klass
Klass.name
# => "Klass"
NewKlass.name
# => "Klass"

这就是为什么即使删除初始常量,对象仍将保留旧名称的原因。

Object.send :remove_const, :Klass
# => Klass
NewKlass
# => Klass
NewKlass.name
# => "Klass"

Klass
# => NameError: uninitialized constant Klass

对象本身没有改变。改变的是 Object 对象携带的常量列表。

当您复制 Class 类型的对象时,它创建时没有任何名称(它是新对象):

new_klass = NewKlass.dup
# => #<Class:0x000000016ced90>
new_klass.name
# => nil

当你将它分配给新常量时,名称就设置好了。这就是上面第一个例子中它接收新名称的方式:

Posts = TableEngine::Posts.dup
# => Post

我最终使用了@Andrew 建议的解决方案,稍作改动:

::Posts = TableEngine::Posts.dup

添加“::”可防止帖子 class 被创建它的上下文命名空间,例如:

class PostsController < ApplicationController
    Posts = TableEngine::Posts.dup # => PostsController::Posts
    ::Posts = TableEngine::Posts.dup # => Posts
end