此方法如何超过 Rubocop 帐户分支条件大小?

How is this method exceeding the Rubocop Account Branch Condition size?

我有一个简单的 before_save 方法,用于根据 user_idapplication_idcontact_id 是否已经存在于模型.

class Note < ApplicationRecord
  belongs_to :contact
  belongs_to :application
  belongs_to :user
  belongs_to :account

  before_save :assign_account_id

  private

  def assign_account_id
    self.account_id =
      if user_id.present?
        user.account.id
      elsif application_id.present?
        application.account.id
      elsif contact_id.present?
        contact.account.id
      end
  end
end

该方法有效,在我看来,它是我能得到的最简单的方法,但 Rubocop 坚持认为它略微超过了分配分支条件大小(ABC 大小),其中限制是 15 而我的方法的 ABC 是 15.33.

根据this article,ABC 大小为 15 是通过 8 个赋值、8 个分支和 8 个条件实现的。但是,我只计算了 1 个赋值 self.account_id =、1 个分支(return)和三个条件(3 个 if/elsif 语句)。

我错了吗?额外的任务、分支或条件从何而来?对 present? 的调用,遍历模型层次结构?

注意:我注意到正在寻找替代实现,我有兴趣了解导致此分数的原因。


对于任何感兴趣的人,这是我最终采用的满足 ABC 大小的解决方案。

self.account_id = [
  user&.account&.id,
  application&.account&.id,
  contact&.account&.id
].find(&:present?)

之所以选择它,是因为垂直列表最能传达字段的级联特性。我觉得我能够 return 做到这一点并且仍然能够理解它在做什么。

This is the web page that the rubocop documentation references in its source code,在 Metrics/AbcSize 的文档中(截至最新版本;0.61.0)。

换句话说,它说:

A scalar ABC size value (or "aggregate magnitude") is computed as: |ABC| = sqrt((A*A)+(B*B)+(C*C))

其中AAssignments的个数,B是[=的个数50=]Branches和CConditions.

的个数
  • 您的代码有 1 个作业 (self.account_id =)。
  • 您的代码有 15 个分支 (!!!) (user_id, .present?, user, .account, .id, application_id, .present?, application, .account, .id, contact_id, .present?, contact.account.id)
  • 您的代码有 3 个条件 (if ... elsif ... elsif)。

将其代入上述公式得到:

ABC = sqrt(1*1 + 15*15 + 3*3)
    = sqrt(235)
    = 15.32970...

这就是 15.33 的(四舍五入)值的来源。


我知道您并不是真的要求替代实现,但无论如何这里有一个:

def assign_account_id
  self.account_id = (user || application || contact).account.id
end

...您甚至可以考虑将这些括号移动到一个单独的方法中。