以更易读/可维护的方式重构Rubocop Style / GuardClause

时间:2018-06-13 06:38:30

标签: ruby-on-rails ruby rubocop

Rubocop抱怨: Style / GuardClause:使用保护子句而不是将代码包装在条件表达式中。     如果issue_flag == true&& issue_notification_sent&& !issue_notification_follow_up_sent&& send_follow_up     ^^

我的原始代码是

if issue_flag == true && issue_notification_sent && !issue_notification_follow_up_sent && send_follow_up
  email_address = "sales@test.com"
  puts "Emailing Follow Up #{email_address} - #{sales_order}"
  UserMailer.issue_notification(self, email_address).deliver_now
  update(issue_notification_follow_up_sent: true)
end

并且从阅读docs开始,我似乎可以通过实现以下代码来解决这个问题:

return unless issue_flag == true && issue_notification_sent && !issue_notification_follow_up_sent && send_follow_up
email_address = "sales@test.com"
puts "Emailing Follow Up #{email_address} - #{sales_order}"
UserMailer.issue_notification(self, email_address).deliver_now
update(issue_notification_follow_up_sent: true)

我可以看到,除非符合条件,否则这基本上会从方法中提前破坏,但对我而言,这似乎不太可读。它似乎也不太可维护,因为在此代码之后无法添加其他条件,除非它们在第一行传递条件,例如,如果issue_flag == true && !issue_notification_sent执行其他操作(任何符合此条件的条件已经在第1行返回)上面重构的代码。)

有没有更好的方法来重构这个,以便在下面的代码之后添加更多条件,而不会过早地返回代码?

感谢。

2 个答案:

答案 0 :(得分:0)

我认为我们可以做类似下面的事情

# issue_flag is boolean so we can directly put it
# create a new method with all the condition and give a proper name
return unless issue_flag && send_follow_up? # change name accourdingly
  email_address = "sales@test.com"
  puts "Emailing Follow Up #{email_address} - #{sales_order}"
  UserMailer.issue_notification(self, email_address).deliver_now
  update(issue_notification_follow_up_sent: true)
end
# document its behaviour
def send_follow_up?
  issue_notification_sent && !issue_notification_follow_up_sent && send_follow_up
end

保护结构用于将控件发送出阻止,因此如果您需要更改某些内容或在该条件之后执行某些操作,则您将无法使用保护条款。在这种情况下看看下面的代码,我们不会使用保护条款

def test
  if something_here?
    do_something
  end

  do_something_else
  do_something_else1
  do_something_else2
end

答案 1 :(得分:0)

我可能会将该方法的大部分内容提取为具有清晰名称的私有部分,以表明其意图。伪代码实现如下所示:

def method_name
  return unless flag? && issue_notification_sent_with_follow_up

  log_follow_up
  UserMailer.issue_notification(self, @email_address).deliver_now
  update(issue_notification_follow_up_sent: true)
end

private

def flag?
  issue_flag == true
end

def issue_notification_sent_with_follow_up
  issue_notification_sent && !issue_notification_follow_up_sent && send_follow_up
end

def log_follow_up
  @email_address = "sales@test.com"
  puts "Emailing Follow Up #{@email_address} - #{sales_order}"
end