类 和模块的子定义样式更改后出现未初始化的常量错误

uninitialized constant error after change style of children definitions at classes and modules

我有一个 gem,其中包含模块的所有 类 都是这样的

require 'concurrent_rails/adapters/future'

module ConcurrentRails
  class Promises
    include ConcurrentRails::Adapters::Future

这是模块

module ConcurrentRails::Adapters
  module Future
    extend ActiveSupport::Concern

    class_methods do
      ....

这很好用,但我试图将 类 和模块的定义保持在一行中:

module ConcurrentRails::Adapters::Future
  extend ActiveSupport::Concern

  class_methods do
    ...

当我像上面那样更改定义时,没有触及 promises.rb 文件,我得到这个错误:

future.rb:3:in `<top (required)>': uninitialized constant ConcurrentRails::Adapters (NameError)

我之前在 concurrent_rails.rb 定义中尝试过 require 文件,但没有任何效果。

如果有帮助,here 是来源

作为一般规则,我建议不要使用嵌套的 class/module 定义。当然,它节省了一行 code/indentation,但是你 运行 遇到了这种问题。

例如,参见 this rubocop rule:

Class: RuboCop::Cop::Style::ClassAndModuleChildren

Overview

This cop checks the style of children definitions at classes and modules. Basically there are two different styles:

The compact style is only forced for classes/modules with one child.

Examples:

  • EnforcedStyle: nested (default)

    # good
    # have each child on its own line
    class Foo
      class Bar
      end
    end
    
  • EnforcedStyle: compact

    # good
    # combine definitions as much as possible
    class Foo::Bar
    end
    

定义 nested 模块是有问题的,因为它只在 ruby 父模块已经定义的情况下有效。例如:

irb(main):001:1* module Foo::Bar
irb(main):002:0> end
Traceback (most recent call last):
        1: from (irb):1
NameError (uninitialized constant Foo)

虽然这很好用:

irb(main):001:1* module Foo
irb(main):002:2*   module Bar
irb(main):003:1*   end
irb(main):004:0> end

此外,即使父模块已经定义,你仍然可以运行进入other issues with module nesting in ruby

所以,简而言之:module ConcurrentRails::Adapters::Future 没有起作用,因为 ConcurrentRails::Adapters 还没有被定义。

可以通过首先显式定义“父模块”来解决这个问题,但是,无论如何我都不建议使用 3 层以上的嵌套模块定义。