【问题标题】:Automatically convert nested classes to compact style in Ruby在 Ruby 中自动将嵌套类转换为紧凑样式
【发布时间】:2020-05-03 20:30:08
【问题描述】:

我有一个非常大的代码库,它混合使用嵌套和紧凑样式进行类定义。

RuboCop: ClassAndModuleChildren

# Nested
class Foo
  class Bar
  end
end

# Compact
class Foo::Bar
end

我正在构建一个自动化工具,它使用正则表达式来重新组织大量类的命名空间。当类定义为紧凑格式时,这很容易做到,但当它们采用嵌套格式时,这要困难得多。

因此,我需要一种将嵌套样式的所有实例转换为紧凑样式的方法。

我希望 RuboCop 可以为我做到这一点,虽然 docs 似乎暗示它支持自动更正,但我无法让它工作。 RuboCop 报告违规行为,但没有解决问题。

bundle exec rubocop --auto-correct app/controllers/announcements_controller.rb
Inspecting 1 file
C

Offenses:

app/controllers/announcements_controller.rb:1:8: C: Style/ClassAndModuleChildren: Use compact module/class definition instead of nested style.
module Vapid
       ^^^^^
app/controllers/announcements_controller.rb:2:10: C: Style/ClassAndModuleChildren: Use compact module/class definition instead of nested style.
  module V2
         ^^

1 file inspected, 2 offenses detected

如果有人可以完成这项工作,或者知道自动采用紧凑样式的更好方法,我将不胜感激。

【问题讨论】:

  • 您使用的是哪个版本的 RuboCop?
  • @AndyWaite 0.71.0
  • 只是想指出这两个样式不是完全一样的东西,如果父类还没有定义,'compact'样式会出错
  • 您是否尝试过通过代码来执行此操作,例如ObjectSpace.each_object遍历?

标签: ruby-on-rails ruby rubocop


【解决方案1】:

我刚刚为我的一个 Rails 应用解决了这个问题。对于位于 app/policies 的嵌套子文件夹中的一组 Pundit 策略,以下对我有用(使用 Rubocop 1.24.0/Rails 7.0/MRI 3.0.0):

# Rails.root/.rubocop.yml
Style/ClassAndModuleChildren:
  EnforcedStyle: compact

然后从命令行:

rubocop --only Style/ClassAndModuleChildren -A app/policies/*

这会自动改变

class TestSpecimen
  class TapePolicy < ApplicationPolicy
  end
end

class TestSpecimen::TapePolicy < ApplicationPolicy
end

并对其他 59 个代码场合进行了类似的更改。

【讨论】:

    【解决方案2】:

    简单的答案是不要这样做。你(以及写那个警察的人)错误地假设这两种“风格”实际上做同样的事情。他们没有。后者被认为是一种非常糟糕的做法。

    使用显式定义(并重新打开)命名空间的类和模块 嵌套。使用范围解析运算符可能会导致令人惊讶的 由于 Ruby 的词法作用域,不断查找,这取决于 在定义点嵌套模块。
    - The Ruby Style Guide

    假设你有:

    module Foo
      TEST = "I'm nested in Foo"
    end
    
    module Foo
      class Bar
        puts TEST
      end
    end
    

    这将放置I'm nested in Foo,因为TEST 被解析为Foo::TEST。让我们更改类定义以使用范围解析运算符:

    TEST = "I'm in the global scope"
    
    module Foo
      TEST = "I'm nested in Foo"
    end
    
    class Foo::Bar
      puts TEST
    end
    

    这将输入I'm in the global scope。因为模块嵌套仍然是全局范围,TEST 解析为::TEST。您的小“改进”实际上会破坏任何依赖于正确模块嵌套的代码。

    【讨论】:

      猜你喜欢
      • 2014-08-15
      • 1970-01-01
      • 2023-03-23
      • 1970-01-01
      • 1970-01-01
      • 2021-05-11
      • 2020-05-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多