简体   繁体   中英

rubocop cyclomatic complexity challenge

Here is the code block that is chocking 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

Error Messages: 在此处输入图片说明

The goal of this function is to determine which browser the customer is using via the browser gem. If the customer is using a legacy browser we kick them out of the application asking them to upgrade. Right now, I have this ignore so the cop does not choke but I am curious how experts out there would rework this.

Please note this code is also used in an initializer:

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

I would recommend splitting your large method into a bunch of smaller methods and using instance variables to help reduce the duplication:

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)

As a style preference, I have also appended each of the methods with a question mark to indicate they return booleans.

You could also use a bit of metaprogramming magic to have ruby write the [browser]_bad? functions for you but that may end up less readable:

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

I haven't run this code so please excuse a few typos.

I might do something like this. Eval in this circumstance can be used safely because nothing user submitted is being evaluated. It's all code you control.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM