首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Rubocop度量/CyclomaticComplexity

Rubocop度量/CyclomaticComplexity
EN

Stack Overflow用户
提问于 2018-09-26 22:55:47
回答 2查看 3.2K关注 0票数 2

指标/圈复杂度: notification_path的圈复杂度太高。9/8,我不知道如何解决这个问题。你能帮帮我吗?谢谢

代码语言:javascript
复制
def notification_path
  return h.company_trial_activation_index_path if User.current.company.trial_pending?

  dot = object.eventable

  case object.event.to_sym
  when :new_app, :updates_approved, :updates_disapproved, :new_partial_app, :completed_app, :received_lead
    h.company_dot_application_path(id: dot.id)
  when :bg_check_received, :bg_check_failed, :bg_check_completed
    h.company_dot_application_background_checks_path(dot)
  when :voe_completed, :voe_corrected, :voe_invalid,
    :voe_driving_school_completed, :voe_driving_school_corrected, :voe_driving_school_invalid
    h.company_dot_application_applications_requests_path(dot_application_id: dot.id)
  when :voe_instructions, :voe_driving_school_instructions
    h.company_dot_application_applications_requests_path(dot.id)
  when :email_reply, :note, :sms_reply
    h.company_dot_application_communications_path(dot.id)
  when :follow_up_task, :follow_up_task_on_due_date
    h.company_dot_application_follow_up_tasks_path(dot_application_id: dot.id)
  when :bulk_actions_background_location, :bulk_actions_background_assign_user, :bulk_actions_background_lead_source
    h.home_users_path
  else
    h.home_users_path
  end
end
EN

回答 2

Stack Overflow用户

发布于 2018-09-26 23:53:45

在讨论圈复杂度之前,让我们先解决该函数的两个更大的问题。数组的巨大列表,以及全局变量。因为Rubocop的目的是使您的代码更容易阅读和维护,并减少错误的可能性,而不是勾选列表上的东西。

如果符号列表被命名,事情将会更具可读性。

代码语言:javascript
复制
WHATEVER_THESE_ARE = [
  :new_app, :updates_approved, :updates_disapproved,
  :new_partial_app, :completed_app, :received_lead
].freeze
BG_CHECK_DONE = [
  :bg_check_received, :bg_check_failed, :bg_check_completed
].freeze
...and so on...

def notification_path
  return h.company_trial_activation_index_path if User.current.company.trial_pending?

  dot = object.eventable

  case object.event.to_sym
  when WHATEVER_THESE_ARE
    h.company_dot_application_path(id: dot.id)
  when BG_CHECK_DONE
    h.company_dot_application_background_checks_path(dot)
  ...and so on...
  end
end

然后请注意,您的函数不带参数。它使用了两个全局变量,模糊地命名为objecth。我不知道这些到底是什么,这些名字没有帮助,但也许你为了这个问题对它们进行了消毒。使用它们作为全局变量会使代码更加复杂。它们应该作为参数传递,或者至少是描述性的命名。

代码语言:javascript
复制
def notification_path(better_name_for_h, better_name_for_object)
  ...
end

好的,继续讨论气旋复杂性。case基本上是一个很大的if/elsif/else,每个when都会增加一点复杂性。对于这么大的表,我们似乎无能为力,但让我们首先观察一下,这种情况只依赖于object.eventobject.eventable (事件表?为什么它被命名为dot?)和h。我们可以做一个提取方法。

代码语言:javascript
复制
def notification_path(h, object)
  return h.company_trial_activation_index_path if User.current.company.trial_pending?

  dot_to_application_path(object.event, object.eventable, h)
end

def dot_to_application_path(event, dot, h)
  case event.to_sym
  when WHATEVER_THESE_ARE
    h.company_dot_application_path(id: dot.id)
  when BG_CHECK_DONE
    h.company_dot_application_background_checks_path(dot)
  ...
  else
    h.home_users_path
  end
end

其他人观察到最后的条件是多余的,所以去掉7。有时你只是比Rubocop更清楚,逻辑真的是如此复杂,可以添加一个例外。

代码语言:javascript
复制
# rubocop:disable Metrics/CyclonicComplexity
def dot_to_application_path(event, dot, h)

这是最后的办法。考虑Rubocop的抱怨总是值得的。我们已经通过尝试修复Rubocop问题改进了代码。

或者我们可以进一步挖掘。

我们可以观察到这个表做了两件事。它选择了适当的路径方法,并标准化了它的调用方式。每种路径方法对dot的处理略有不同,这使得事情变得更加复杂和容易出错。

如果这些方法是一致的,我们可以用散列查找替换这种情况。

代码语言:javascript
复制
WHATEVER_THESE_ARE = [
  :new_app, :updates_approved, :updates_disapproved,
  :new_partial_app, :completed_app, :received_lead
].freeze
BG_CHECK_DONE = [
  :bg_check_received, :bg_check_failed, :bg_check_completed
].freeze
...

# You'll want to put this somewhere else.
def flatten_keys(hash)
  hash.each_with_object({}) { |(keys, value), new_hash|
    keys.each { |key| new_hash[event] = value }
  }
end  

EVENT_TO_APPLICATION_PATH_METHOD = flatten_keys({
  WHATEVER_THESE_ARE => :company_dot_application_path,
  BG_CHECK_DONE => :company_dot_application_background_checks_path,
  ...
}).freeze

def notification_path(h, object)
  return h.company_trial_activation_index_path if User.current.company.trial_pending?

  method = EVENT_TO_DOT_APPLICATION_PATH_METHOD[object.event.to_sym] || :home_users_path
  h.send(method, dot)
end

现在我们可以看到这段代码有多简单了!

为了实现这一点,你可以重构这些方法,使它们保持一致,或者你可以编写包装器方法,使其保持一致。重构是更好的选择,但这可能超出了您的范围。

最后,这一切可能都足够复杂,需要将所有逻辑放入一个类中。

票数 4
EN

Stack Overflow用户

发布于 2018-09-26 23:44:24

我注意到你用

h.company_dot_application_applications_requests_path(dot_application_id: dot.id)

在一个地方

h.company_dot_application_applications_requests_path(dot.id)

在另一个地方。如果这些调用相等,则该方法可以简化一点:

代码语言:javascript
复制
def notification_path
  return h.company_trial_activation_index_path if User.current.company.trial_pending?

  dot = object.eventable

  case object.event.to_sym
  when :new_app, :updates_approved, :updates_disapproved, :new_partial_app, :completed_app, :received_lead
    h.company_dot_application_path(id: dot.id)
  when :bg_check_received, :bg_check_failed, :bg_check_completed
    h.company_dot_application_background_checks_path(dot)
  when :voe_completed, :voe_corrected, :voe_invalid, :voe_driving_school_completed, :voe_driving_school_corrected, :voe_driving_school_invalid, :voe_instructions, :voe_driving_school_instructions
    h.company_dot_application_applications_requests_path(dot.id)
  when :email_reply, :note, :sms_reply
    h.company_dot_application_communications_path(dot.id)
  when :follow_up_task, :follow_up_task_on_due_date
    h.company_dot_application_follow_up_tasks_path(dot_application_id: dot.id)
  else
    h.home_users_path
  end
end
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52520697

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档