вызов цикломатической сложности 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

Сообщения об ошибках: введите описание изображения здесь

Цель этой функции — определить, какой браузер использует клиент, через браузерный гем. Если клиент использует устаревший браузер, мы удаляем его из приложения с просьбой обновить его. Прямо сейчас у меня есть этот игнор, чтобы коп не задохнулся, но мне любопытно, как эксперты переделают это.

Обратите внимание, что этот код также используется в инициализаторе:

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

person Chris Hough    schedule 02.02.2016    source источник


Ответы (2)


Я бы рекомендовал разбить ваш большой метод на несколько более мелких и использовать переменные экземпляра, чтобы уменьшить дублирование:

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

  def browser_not_supported?
    [email protected]? || 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)

В качестве предпочтения стиля я также добавил к каждому методу вопросительный знак, чтобы указать, что они возвращают логические значения.

Вы также можете использовать немного магии метапрограммирования, чтобы ruby ​​написал для вас функции [browser]_bad?, но это может оказаться менее читаемым:

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


  def browser_not_supported
    [email protected]? || 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

Я не запускал этот код, поэтому извините за несколько опечаток.

person Josh    schedule 02.02.2016

Я мог бы сделать что-то вроде этого. 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
person MilesStanfield    schedule 02.02.2016