rubocop 圈复杂度挑战

rubocop cyclomatic complexity challenge

这是阻塞 rubocop 的代码块:

  def self.browser_not_supported(browser)
    return true if browser.chrome? && browser.version.to_i < AppConfig.requirements['browser_google'].to_i
    return true if browser.firefox? && browser.version.to_i < AppConfig.requirements['browser_firefox'].to_i
    return true if browser.safari? && browser.version.to_i < AppConfig.requirements['browser_safari'].to_i
    return true if browser.ie? && browser.version.to_i < AppConfig.requirements['browser_msft'].to_i
    return true unless browser.modern?
  end

错误信息:

此功能的目标是通过浏览器 gem 确定客户使用的浏览器。如果客户使用的是旧版浏览器,我们会将他们踢出应用程序,要求他们升级。现在,我有这个忽略所以警察不会窒息但我很好奇那里的专家会如何修改这个。

请注意此代码也用在初始化程序中:

Rails.configuration.middleware.use Browser::Middleware do
    redirect_to '/error/browser-upgrade-required' if ApplicationHelper.browser_not_supported(browser)
end

我建议将您的大方法拆分成一堆较小的方法并使用实例变量来帮助减少重复:

class BrowserChecker
  def initialize(browser)
    @browser = browser
    @version = browser.version.to_i
  end

  def browser_not_supported?
    !@browser.modern? || chrome_bad? || firefox_bad? || io_bad?
  end

  private

  def chrome_bad?
    @browser.chrome? && @version < AppConfig.requirements['browser_google'].to_i
  end

  def firefox_bad?
    @browser.firefox? && @version < AppConfig.requirements['browser_firefox'].to_i
  end

  def safari_bad?
    @browser.safari? && @version < AppConfig.requirements['browser_safari'].to_i
  end

  def ie_bad?
    @browser.ie? && @version < AppConfig.requirements['browser_msft'].to_i
  end
end


# called like this
BrowserChecker.new(some_browser_object)

作为一种风格偏好,我还在每个方法后面附加了一个问号以表明它们是 return 个布尔值。

您也可以使用一些元编程魔法让 ruby 为您编写 [browser]_bad? 函数,但最终可能会降低可读性:

class BrowserChecker
  def initialize(browser)
    @browser = browser
  end


  def browser_not_supported
    !@browser.modern? || chrome_bad? || firefox_bad? || io_bad?
  end

  ['google', 'firefox', 'safari', 'msft'].each do |browser|
    define_method "#{browser}_bad?".to_sym do
      @browser.send("#{browser}?".to_sym) && @version < AppConfig.requirements["browser_#{browser}"].to_i
    end
  end
end

我没有运行这个代码所以请原谅一些错别字。

我可能会做这样的事情。 Eval 在这种情况下可以安全使用,因为没有评估用户提交的内容。一切由你掌控。

def self.browser_not_supported(browser)
  unsupported?(browser) || !browser.modern?
end

private

def self.unsupported?(browser)
  browsers.any? do |name, tech_name|
    if eval("#{browser}.#{name}?")
      browser.version.to_i < AppConfig.requirements[tech_name].to_i
    end
  end
end

def self.browsers
  {
    chrome: 'browser_google',
    firefox: 'browser_firefox',
    safari: 'browser_safari',
    ie: 'browser_msft'
  }
end