Ruby 类名解析中的歧义

Sea*_*ean 5 ruby ruby-on-rails

我最近在 Rails 代码库中进行了一些代码重构,其中我转换了一些定义这样的类的代码(类主体被省略):

foo/user_bar.rb

module Foo
  class UserBar; end
end
Run Code Online (Sandbox Code Playgroud)

foo/sub_user_bar.rb

module Foo
  class SubUserBar < UserBar; end
end
Run Code Online (Sandbox Code Playgroud)

...到:

foo/bar/user.rb

module Foo
  module Bar
    class User; end
  end
end
Run Code Online (Sandbox Code Playgroud)

foo/bar/sub_user.rb

module Foo
  module Bar
    class SubUser < User; end
  end
end
Run Code Online (Sandbox Code Playgroud)

这引入了一个微妙的问题,因为已经有一个名为User(Rails 模型)的现有顶级类,并且SubUser是从它派生的,而不是来自User同一模块。我猜这是因为 Rails 加载类的顺序是不可预测的......?

无论如何,我发现我可以通过SubUser像这样声明类来消除歧义:

class SubUser < self::User
Run Code Online (Sandbox Code Playgroud)

...这似乎有效,虽然我在适度的搜索中找不到任何例子。不过,它看起来确实有点奇怪。现在我担心我真的应该为模块中的每个类都这样做,以防万一引入了同名的顶级类。

我公司的代码库中有两种类型的模块内类声明:

class A::B::Foo; end
Run Code Online (Sandbox Code Playgroud)

和:

module A; module B; class Foo; end; end; end
Run Code Online (Sandbox Code Playgroud)

我一直更喜欢后一种方法,因为它允许在没有完全限定名称的情况下访问模块中的其他名称,但现在我发现使用它时可能存在陷阱。那么这里的最佳实践是什么?

  • 不要在module; 中声明类 始终使用完全限定名称 ( class A::B::C::Foo < A::B::C::Bar)
  • 在一个module但始终完全限定超类名称中声明类( module A; module B; module C; class Foo < A::B::C::Bar)
  • 在 a 中声明类module并使用非限定名称,但self::在同一模块中扩展类时始终使用
  • 在 a 中声明类module并使用不合格的名称,但要注意顶级命名空间中可能的名称冲突(似乎有风险)

或者 Ruby 和/或 Rails 是否提供了其他一些更简洁的方法来解决这个问题?

tad*_*man 5

通常在有歧义的地方指定完整的命名空间路径:

module Foo
  module Bar
    class SubUser < Foo::Bar::User; end
  end
end
Run Code Online (Sandbox Code Playgroud)

这可能看起来很冗长,但它也是具体且明确的。

您要在何处引用文字顶级,请User指定::User.