在 Ruby 中自动将嵌套类转换为紧凑样式



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

鲁博警察:类和模块儿童

# Nested
class Foo
class Bar
end
end
# Compact
class Foo::Bar
end

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

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

我希望 RuboCop 可以为我做到这一点,虽然文档似乎建议它支持自动更正,但我无法让它工作。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

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

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

使用显式定义(并重新打开(命名空间类和模块 嵌 套。使用示波器解析运算符可能会导致令人惊讶的结果 由于 Ruby 的词法范围而不断查找,这取决于 定义点的模块嵌套。
- 红宝石风格指南

因此,假设您有:

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。你的小"改进"实际上会破坏任何依赖于正确模块嵌套的代码。

我刚刚为我的一个 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 个代码进行了类似的更改。

最新更新