首页 > 解决方案 > 更改类和模块的子定义样式后未初始化的常量错误

问题描述

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

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)

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

如果有帮助,这里是源

标签: rubyrubygems

解决方案


作为一般规则,我建议不要嵌套类/模块定义。当然,它节省了一行代码/缩进,但你遇到了这类问题。

例如,请参阅rubocop规则

类: RuboCop::Cop::Style::ClassAndModuleChildren

概述

这个警察检查类和模块中子定义的样式。基本上有两种不同的风格:

紧凑样式仅适用于具有一个孩子的类/模块。

例子:

  • EnforcedStyle:嵌套(默认)

    # good
    # have each child on its own line
    class Foo
      class Bar
      end
    end
    
  • 强制风格:紧凑

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

定义嵌套模块是有问题的,因为它只有在父模块已经定义的情况下才能在 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

此外,即使已经定义了父模块,您仍然可以在 ruby​​ 中遇到模块嵌套的其他问题

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

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


推荐阅读