Zeitwerk,require_dependency并将Ruby类拆分为几个文件

时间:2019-10-22 21:47:15

标签: ruby-on-rails ruby

在Rails 6之前,有一种简单的方法可以将任何Ruby类拆分为多个文件,而无需引入任何其他模块或关注点。对于那些恰好太大而无法保存在一个文件中的神类,这是非常有用的:

# god.rb
class God < ApplicationRecord
  require_dependency 'god~callbacks'
  require_dependency 'god~scopes'
  require_dependency 'god~search'
  require_dependency 'god~something_else'
  require_dependency 'god~and_more'
  require_dependency 'god~and_even_more'
  ...
end

# god~callbacks.rb
class God
  before_save :nullify_blanks
  before_save :nullify_unrelated_attrs
  ...
end

文件结构如下:

models/
  god.rb
  god~callbacks.rb
  god~scopes.rb
  god~search.rb
  ...

效果很好-随时更改任何这些文件中的任何内容都会正确地重新加载更改。

自Rails 6起,我们使用了新型装载机-Zeitwerk。很棒,但似乎不适用于require_dependency,至少在以这种非典型方式使用该方法时如此。

问题是,是否可以将类定义拆分为几个文件并保持自动重载与Zeitwerk一起使用。目的是在不引入任何内部模块/问题的情况下拆分类。

而且,请不要评论1000行长的类是否是一种好的设计实践,这不是问题的重点。

2 个答案:

答案 0 :(得分:4)

从技术上讲,我相信这是可行的,尽管这种拆分代码的方式并不常见,而且解决方案中的醋比糖还多:)。

首先,您需要告诉Zeitwerk ignore those files。例如,在初始化程序中,您可以执行以下操作:

# ignore accepts a glob pattern.
Rails.autoloaders.main.ignore("god~*")

第二,您需要load个文件,以便重新加载再次解释它们:

class God < ApplicationRecord
  load "#{__dir__}/god~callbacks.rb"
  ...
end

我假设这些文件未在其他位置加载,所以幂等性并不重要。如果这很重要,那么您需要一些醋。

上面的解决方案未经测试,但是您明白了。

这是拆分代码的一种不寻常的方式,您知道,通常使用模块,模块的名称反映了代码的组织方式,即文件名的作用。我建议使用模块。但是,如果要保留这种样式,原则上可以,尽管解决方案有点强制。

答案 1 :(得分:2)

您可以通过在config.autoload = :classic文件中设置application.rb来选择不使用Zeitwerk。如果要继续使用Zeitwerk,为什么不将require_dependency调用替换为include