class RuboCop::ConfigLoader
directories are inspected.
during a run of the rubocop program, if files in several
file from which it was read. Several different Configs can be used
and all its cops. A Config is associated with a YAML configuration
This class represents the configuration of the RuboCop application
def add_missing_namespaces(path, hash)
def add_missing_namespaces(path, hash) hash.keys.each do |k| q = Cop::Cop.qualified_cop_name(k, path) next if q == k hash[q] = hash.delete(k) end end
def base_configs(path, inherit_from)
def base_configs(path, inherit_from) configs = Array(inherit_from).compact.map do |f| if f =~ /\A#{URI::Parser.new.make_regexp(%w(http https))}\z/ f = RemoteConfig.new(f, File.dirname(path)).file else f = File.expand_path(f, File.dirname(path)) if auto_gen_config? next if f.include?(AUTO_GENERATED_FILE) end print 'Inheriting ' if debug? end load_file(f) end configs.compact end
def clear_options
def clear_options @debug = @auto_gen_config = @root_level = nil end
def config_files_in_path(target)
def config_files_in_path(target) possible_config_files = dirs_to_search(target).map do |dir| File.join(dir, DOTFILE) end possible_config_files.select { |config_file| File.exist?(config_file) } end
def configuration_file_for(target_dir)
user's home directory is checked. If there's no .rubocop.yml
inspected file is. If no .rubocop.yml is found there, the
directory structure starting at the given directory where the
Returns the path of .rubocop.yml searching upwards in the
def configuration_file_for(target_dir) config_files_in_path(target_dir).first || DEFAULT_FILE end
def configuration_from_file(config_file)
def configuration_from_file(config_file) config = load_file(config_file) return config if config_file == DEFAULT_FILE found_files = config_files_in_path(config_file) if found_files.any? && found_files.last != config_file print 'AllCops/Exclude ' if debug? config.add_excludes_from_higher_level(load_file(found_files.last)) end merge_with_default(config, config_file) end
def default_configuration
def default_configuration @default_configuration ||= begin print 'Default ' if debug? load_file(DEFAULT_FILE) end end
def dirs_to_search(target_dir)
def dirs_to_search(target_dir) dirs_to_search = [] Pathname.new(File.expand_path(target_dir)).ascend do |dir_pathname| break if dir_pathname.to_s == @root_level dirs_to_search << dir_pathname.to_s end dirs_to_search << Dir.home if ENV.key? 'HOME' dirs_to_search end
def gem_config_path(gem_name, relative_config_path)
def gem_config_path(gem_name, relative_config_path) spec = Gem::Specification.find_by_name(gem_name) return File.join(spec.gem_dir, relative_config_path) rescue Gem::LoadError => e raise Gem::LoadError, "Unable to find gem #{gem_name}; is the gem installed? #{e}" end
def load_file(path)
def load_file(path) path = File.absolute_path(path) hash = load_yaml_configuration(path) add_missing_namespaces(path, hash) resolve_inheritance_from_gems(hash, hash.delete('inherit_gem')) resolve_inheritance(path, hash) resolve_requires(path, hash) hash.delete('inherit_from') config = Config.new(hash, path) config.deprecation_check do |deprecation_message| warn("#{path} - #{deprecation_message}") end config.validate config.make_excludes_absolute config end
def load_yaml_configuration(absolute_path)
def load_yaml_configuration(absolute_path) yaml_code = IO.read(absolute_path, encoding: Encoding::UTF_8) hash = yaml_safe_load(yaml_code, absolute_path) || {} puts "configuration from #{absolute_path}" if debug? unless hash.is_a?(Hash) raise(TypeError, "Malformed configuration in #{absolute_path}") end hash end
def merge(base_hash, derived_hash)
with the addition that any value that is a hash, and occurs in both
Return a recursive merge of two hashes. That is, a normal hash merge,
def merge(base_hash, derived_hash) result = base_hash.merge(derived_hash) keys_appearing_in_both = base_hash.keys & derived_hash.keys keys_appearing_in_both.each do |key| next unless base_hash[key].is_a?(Hash) result[key] = merge(base_hash[key], derived_hash[key]) end result end
def merge_with_default(config, config_file)
AllCops:DisabledByDefault is true, it changes the Enabled params so
Merges the given configuration with the default one. If
def merge_with_default(config, config_file) configs = if config.for_all_cops['DisabledByDefault'] disabled_default = transform(default_configuration) do |params| params.merge('Enabled' => false) # Overwrite with false. end enabled_user_config = transform(config) do |params| { 'Enabled' => true }.merge(params) # Set true if not set. end [disabled_default, enabled_user_config] else [default_configuration, config] end Config.new(merge(configs.first, configs.last), config_file) end
def transform(config)
Returns a new hash where the parameters of the given config hash have
def transform(config) Hash[config.map { |cop, params| [cop, yield(params)] }] end
def yaml_safe_load(yaml_code, filename)
def yaml_safe_load(yaml_code, filename) if YAML.respond_to?(:safe_load) # Ruby 2.1+ if defined?(SafeYAML) && SafeYAML.respond_to?(:load) SafeYAML.load(yaml_code, filename, whitelisted_tags: %w(!ruby/regexp)) else YAML.safe_load(yaml_code, [Regexp], [], false, filename) end else YAML.load(yaml_code, filename) # rubocop:disable Security/YAMLLoad end end