# frozen_string_literal: true # # Copyright:: Chef Software, Inc. # Author:: Tim Smith () # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # module RuboCop module Cop module Chef module ChefRuby # Rubygems is VERY slow to require gems even if they've already been loaded. To work around this # wrap your require statement with an `if defined?()` check. # class UnlessDefinedRequire < Base extend RuboCop::Cop::AutoCorrector MSG = "Workaround rubygems slow requires by only running require if the class isn't already defined" REQUIRE_TO_CLASS = { "addressable/uri" => "Addressable::URI", "appscript" => "Appscript", "base64" => "Base64", "benchmark" => "Benchmark", "cgi" => "CGI", "chef-utils" => "ChefUtils::CANARY", "chef-utils/dist" => "ChefUtils::Dist", "csv" => "CSV", "digest" => "Digest", "digest/md5" => "Digest::MD5", "digest/sha1" => "Digest::SHA1", "digest/sha2" => "Digest::SHA2", "droplet_kit" => "DropletKit", "erb" => "Erb", "erubis" => "Erubis", "etc" => "Etc", "excon" => "Excon", "faraday" => "Faraday", "ffi_yajl" => "FFI_Yajl", "ffi" => "FFI", "fileutils" => "FileUtils", "find" => "Find.find", "forwardable" => "Forwardable", "ipaddr" => "IPAddr", "json" => "JSON", "mime/types" => "MIME::Types", "mixlib/archive" => "Mixlib::Archive", "mixlib/cli" => "Mixlib::CLI", "mixlib/config" => "Mixlib::Config", "mixlib/shellout" => "Mixlib::ShellOut", "multi_json" => "MultiJson", "net/http" => "Net::HTTP", "net/ssh" => "Net::SSH", "netaddr" => "NetAddr", "nokogiri" => "Nokogiri", "ohai" => "Ohai::System", "open-uri" => "OpenURI", "openssl" => "OpenSSL", "optparse" => "OptionParser", "ostruct" => "OpenStruct", "pathname" => "Pathname", "pp" => "PP", "rack" => "Rack", "rbconfig" => "RbConfig", "retryable" => "Retryable", "rexml/document" => "REXML::Document", "rubygems" => "Gem", "rubygems/package" => "Gem::Package", "securerandom" => "SecureRandom", "set" => "Set", "shellwords" => "Shellwords", "singleton" => "Singleton", "socket" => "Socket", "sslshake" => "SSLShake", "stringio" => "StringIO", "tempfile" => "Tempfile", "thor" => "Thor", "time" => "Time.zone_offset", "timeout" => "Timeout", "tmpdir" => "Dir.mktmpdir", "tomlrb" => "Tomlrb", "uri" => "URI", "webrick" => "WEBrick", "win32/registry" => "Win32::Registry", "win32ole" => "WIN32OLE", "winrm" => "WinRM::Connection", "yard" => "YARD", "zip" => "Zip", "zlib" => "Zlib", "pastel" => "Pastel", }.freeze def_node_matcher :require?, <<-PATTERN (send nil? :require (str $_) ) PATTERN def on_send(node) require?(node) do |r| next if node.parent && node.parent.conditional? # catch both if and unless next unless REQUIRE_TO_CLASS[r] add_offense(node.loc.expression, message: MSG, severity: :refactor) do |corrector| corrector.replace(node.loc.expression, "#{node.source} unless defined?(#{REQUIRE_TO_CLASS[r]})") end end end end end end end end