Ruby 分解圈复杂度和感知复杂度

Ruby 分解圈复杂度和感知复杂度,ruby,cyclomatic-complexity,rubocop,Ruby,Cyclomatic Complexity,Rubocop,我的测试应用程序中有以下方法: def on(definition, visit = false, &block) if @page.is_a?(definition) block.call @page if block return @page end if @context.is_a?(definition) block.call @context if block @page = @context unless @page.is_a?(

我的测试应用程序中有以下方法:

def on(definition, visit = false, &block)
  if @page.is_a?(definition)
    block.call @page if block
    return @page
  end

  if @context.is_a?(definition)
    block.call @context if block
    @page = @context unless @page.is_a?(definition)
    return @context
  end

  @page = definition.new(@browser)
  @page.view if visit

  @page.correct_url? if @page.respond_to?(:url_matches)
  @page.correct_title? if @page.respond_to?(:title_is)

  @model = @page

  block.call @page if block

  @page
end
当我对包含此方法的文件运行rubocop工具时,我得到以下响应:

C: Cyclomatic complexity for on is too high. [10/6]
C: Perceived complexity for on is too high. [10/7]
我不明白的是它认为的“太复杂”,因此我很难想出如何解决这个问题。理想情况下,我宁愿不告诉rubocop避免警告,因为它无疑告诉我一些有用的东西

正如您所看到的,由于方法复杂,我有几个
if
调用,然后我必须使用
@page
对象,以确保它设置正确。(在上下文中,此示例是Watir WebDriver对象。)

我同意这种方法很复杂,因为它需要检查
@page
是否已经存在并设置为某个值,以及检查
@page
是否应该与
@context
相同。但是,我也不知道该怎么办

此方法所在模块的完整代码如下:

我最初认为我可以将其分解为不同的方法调用,这可能会降低每个方法的复杂性。但这意味着阅读我的代码的人必须跳转到一系列不同的方法来理解
on
在做什么。在我看来,仅仅是移动东西并不能从整体上消除复杂性;更确切地说,这只不过是在洗牌。还是我错了

这里的任何建议都将不胜感激

更新代码

我已经把这个减少了一些。以下是我现在拥有的:

def on(definition, visit = false, &block)
  if @page.is_a?(definition)
    block.call @page if block
    return @page
  end

  if @context.is_a?(definition)
    block.call @context if block
    @page = @context
    return @context
  end

  @page = definition.new(@browser)
  @page.view if visit

  @model = @page

  block.call @page if block

  @page
end
根据反馈,我删除了一个
,除非
限定符,这个限定符似乎没有用。我还删除了两行,我发现我可以在其他地方更好地使用它们(检查标题和url)

这完全消除了“感知的复杂性”,留给我的只有以下几点:

C: Cyclomatic complexity for on is too high. [7/6]

我似乎“一点”(或任何术语)太复杂了。

有些地方的代码是多余的。例如,您有:

if @page.is_a?(definition)
  ...
  return ...
end
这意味着,在后面的任何部分中,您可以假设
@page.is_a?(定义)
不是
true
,除非您在该部分之后修改
@page
。然而,你有:

if @context.is_a?(definition)
  ... unless @page.is_a?(definition)
end

您的代码尖叫着说它无法推断出整个代码中的对象标识/类类型。你总是问“嘿,你是这个吗?你知道怎么做吗?”。保护安全是可以的,但在调用此方法之前,您可能应该在其他地方验证您的输入。但我不知道我怎么能做到。(我并不是说这不可能!)问题是,上下文工厂
on
方法是这样调用的:
on(SomePage)
。这可以发生在测试脚本中的任何地方。此外,您可以在(SomePage)
上使用
,然后在(SomeOtherPage)
上使用
。对于逻辑来说,重要的是要知道SomeOtherPage不是SomePage。但是你也可以在新的(SomePage)上执行
这意味着SomePage是SomePage,但它是一个新的——不同的——实例。所以,挑战在于我不知道测试编写者将要做什么。不过,把你的话牢记在心,我会看看我是否能把它清理干净。啊!说得好。是的,除非不需要限定符。根据rubocop的说法,如果我去掉这一点,我确实会从我的复杂性中去掉一个“点”。这让我觉得on的圈复杂度太高了。[9/6]
感知到的on复杂性太高。[9/7]
。有趣。所以,它的复杂性似乎是基于我的条件,至少在某种程度上是这样。这已经有一段时间了,我意识到我没有接受任何与此相关的东西。这个答案无疑让我走上了理解的道路,我需要把重点放在哪里;因此接受(立即逾期)。