class RuboCop::Config
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_excludes_from_higher_level(highest_config)
def add_excludes_from_higher_level(highest_config) return unless highest_config.for_all_cops['Exclude'] excludes = for_all_cops['Exclude'] ||= [] highest_config.for_all_cops['Exclude'].each do |path| unless path.is_a?(Regexp) || absolute?(path) path = File.join(File.dirname(highest_config.loaded_path), path) end excludes << path unless excludes.include?(path) end end
def add_missing_namespaces
def add_missing_namespaces keys.each do |k| q = Cop::Cop.qualified_cop_name(k, loaded_path) next if q == k self[q] = self[k] delete(k) end end
def base_dir_for_path_parameters
config/default.yml, for example, are not relative to RuboCop's config
relative to the current directory. This is so that paths in
to the directory where that file is. Paths in other config files are
Paths specified in .rubocop.yml and .rubocop_todo.yml files are relative
def base_dir_for_path_parameters config_files = [ConfigLoader::DOTFILE, ConfigLoader::AUTO_GENERATED_FILE] @base_dir_for_path_parameters ||= if config_files.include?(File.basename(loaded_path)) && loaded_path != File.join(Dir.home, ConfigLoader::DOTFILE) File.expand_path(File.dirname(loaded_path)) else Dir.pwd end end
def check_obsolete_parameter(cop, parameter, alternative = nil)
def check_obsolete_parameter(cop, parameter, alternative = nil) if self[cop] && self[cop].key?(parameter) raise ValidationError, "obsolete parameter #{parameter} (for #{cop}) " \ "found in #{loaded_path}" \ "#{"\n" if alternative}#{alternative}" end end
def check_target_ruby
def check_target_ruby return unless target_ruby_version unless KNOWN_RUBIES.include?(target_ruby_version) msg = "Unknown Ruby version #{target_ruby_version.inspect} found " msg += case @target_ruby_version_source when :dot_ruby_version 'in `.ruby-version`.' when :rubocop_yml "in `TargetRubyVersion` parameter (in #{loaded_path})." \ end msg += "\nKnown versions: #{KNOWN_RUBIES.join(', ')}" raise ValidationError, msg end end
def cop_enabled?(cop)
def cop_enabled?(cop) department = cop.cop_type.to_s.capitalize! if (dept_config = self[department]) return false if dept_config['Enabled'] == false end for_cop(cop).empty? || for_cop(cop)['Enabled'] end
def deprecation_check
def deprecation_check %w(Exclude Include).each do |key| plural = "#{key}s" next unless for_all_cops[plural] for_all_cops[key] = for_all_cops[plural] # Stay backwards compatible. for_all_cops.delete(plural) yield "AllCops/#{plural} was renamed to AllCops/#{key}" end end
def file_to_exclude?(file)
def file_to_exclude?(file) file = File.expand_path(file) patterns_to_exclude.any? do |pattern| match_path?(pattern, file) end end
def file_to_include?(file)
def file_to_include?(file) relative_file_path = path_relative_to_config(file) # Optimization to quickly decide if the given file is hidden (on the top # level) and can not be matched by any pattern. is_hidden = relative_file_path.start_with?('.') && !relative_file_path.start_with?('..') return false if is_hidden && !possibly_include_hidden? absolute_file_path = File.expand_path(file) patterns_to_include.any? do |pattern| match_path?(pattern, relative_file_path) || match_path?(pattern, absolute_file_path) end end
def for_all_cops
def for_all_cops @for_all_cops ||= self['AllCops'] || {} end
def for_cop(cop)
def for_cop(cop) @for_cop[cop.respond_to?(:cop_name) ? cop.cop_name : cop] end
def initialize(hash = {}, loaded_path = nil)
def initialize(hash = {}, loaded_path = nil) @loaded_path = loaded_path @for_cop = Hash.new do |h, cop| h[cop] = self[Cop::Cop.qualified_cop_name(cop, loaded_path)] || {} end replace(hash) end
def make_excludes_absolute
def make_excludes_absolute each_key do |key| validate_section_presence(key) next unless self[key]['Exclude'] self[key]['Exclude'].map! do |exclude_elem| if exclude_elem.is_a?(String) && !absolute?(exclude_elem) File.expand_path(File.join(base_dir_for_path_parameters, exclude_elem)) else exclude_elem end end end end
def path_relative_to_config(path)
def path_relative_to_config(path) relative_path(path, base_dir_for_path_parameters) end
def patterns_to_exclude
def patterns_to_exclude @patterns_to_exclude ||= for_all_cops['Exclude'] end
def patterns_to_include
def patterns_to_include @patterns_to_include ||= for_all_cops['Include'] end
def possibly_include_hidden?
Returns true if there's a chance that an Include pattern matches hidden
def possibly_include_hidden? @possibly_include_hidden ||= patterns_to_include.any? do |s| s.is_a?(Regexp) || s.start_with?('.') || s.include?('/.') end end
def reject_obsolete_cops
def reject_obsolete_cops OBSOLETE_COPS.each do |cop_name, message| next unless key?(cop_name) || key?(cop_name.split('/').last) message += "\n(obsolete configuration found in #{loaded_path}, please" \ ' update it)' raise ValidationError, message end end
def reject_obsolete_parameters
def reject_obsolete_parameters check_obsolete_parameter('Style/SpaceAroundOperators', 'MultiSpaceAllowedForOperators', 'If your intention was to allow extra spaces ' \ 'for alignment, please use AllowForAlignment: ' \ 'true instead.') check_obsolete_parameter('AllCops', 'RunRailsCops', "Use the following configuration instead:\n" \ "Rails:\n Enabled: true") end
def target_ruby_version
def target_ruby_version @target_ruby_version ||= if File.file?('.ruby-version') @target_ruby_version_source = :dot_ruby_version File.read('.ruby-version').to_f else @target_ruby_version_source = :rubocop_yml for_all_cops['TargetRubyVersion'] end end
def validate
def validate # Don't validate RuboCop's own files. Avoids infinite recursion. base_config_path = File.expand_path(File.join(ConfigLoader::RUBOCOP_HOME, 'config')) return if File.expand_path(loaded_path).start_with?(base_config_path) valid_cop_names, invalid_cop_names = keys.partition do |key| ConfigLoader.default_configuration.key?(key) end reject_obsolete_cops warn_about_unrecognized_cops(invalid_cop_names) reject_obsolete_parameters check_target_ruby validate_parameter_names(valid_cop_names) validate_enforced_styles(valid_cop_names) end
def validate_enforced_styles(valid_cop_names)
def validate_enforced_styles(valid_cop_names) valid_cop_names.each do |name| next unless (style = self[name]['EnforcedStyle']) valid = ConfigLoader.default_configuration[name]['SupportedStyles'] next if valid.include?(style) msg = "invalid EnforcedStyle '#{style}' for #{name} found in " \ "#{loaded_path}\n" \ "Valid choices are: #{valid.join(', ')}" raise ValidationError, msg end end
def validate_parameter_names(valid_cop_names)
def validate_parameter_names(valid_cop_names) valid_cop_names.each do |name| validate_section_presence(name) self[name].each_key do |param| next if COMMON_PARAMS.include?(param) || ConfigLoader.default_configuration[name].key?(param) warn Rainbow("Warning: unrecognized parameter #{name}:#{param} " \ "found in #{loaded_path}").yellow end end end
def validate_section_presence(name)
def validate_section_presence(name) return unless key?(name) && self[name].nil? raise ValidationError, "empty section #{name} found in #{loaded_path}" end
def warn_about_unrecognized_cops(invalid_cop_names)
def warn_about_unrecognized_cops(invalid_cop_names) invalid_cop_names.each do |name| if name == 'Syntax' raise ValidationError, "configuration for Syntax cop found in #{loaded_path}\n" \ 'This cop cannot be configured.' end # There could be a custom cop with this name. If so, don't warn next if Cop::Cop.all.any? { |c| c.match?([name]) } warn Rainbow("Warning: unrecognized cop #{name} found in " \ "#{loaded_path}").yellow end end