class RubbyCop::Config

This class represents the configuration of the RubbyCop application and all its cops. A Config is associated with a YAML configuration file from which it was read. Several different Configs can be used during a run of the rubbycop program, if files in several directories are inspected.

Constants

COMMON_PARAMS
DEFAULT_RAILS_VERSION
DEFAULT_RUBY_VERSION

2.1 is the oldest officially supported Ruby version.

KNOWN_RUBIES
OBSOLETE_COPS
OBSOLETE_PARAMETERS

Attributes

loaded_path[R]

Public Class Methods

new(hash = {}, loaded_path = nil) click to toggle source
# File lib/rubbycop/config.rb, line 113
def initialize(hash = {}, loaded_path = nil)
  @loaded_path = loaded_path
  @for_cop = Hash.new do |h, cop|
    qualified_cop_name = Cop::Cop.qualified_cop_name(cop, loaded_path)
    cop_options = self[qualified_cop_name] || {}
    cop_options['Enabled'] = enable_cop?(qualified_cop_name, cop_options)
    h[cop] = cop_options
  end
  @hash = hash
end

Public Instance Methods

[](key) click to toggle source
# File lib/rubbycop/config.rb, line 124
def [](key)
  @hash[key]
end
[]=(key, value) click to toggle source
# File lib/rubbycop/config.rb, line 128
def []=(key, value)
  @hash[key] = value
end
add_excludes_from_higher_level(highest_config) click to toggle source
# File lib/rubbycop/config.rb, line 184
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
base_dir_for_path_parameters() click to toggle source

Paths specified in configuration files starting with .rubbycop are relative to the directory where that file is. Paths in other config files are relative to the current directory. This is so that paths in config/default.yml, for example, are not relative to RubbyCop's config directory since that wouldn't work.

# File lib/rubbycop/config.rb, line 284
def base_dir_for_path_parameters
  @base_dir_for_path_parameters ||=
    if File.basename(loaded_path).start_with?('.rubbycop') &&
       loaded_path != File.join(Dir.home, ConfigLoader::DOTFILE)
      File.expand_path(File.dirname(loaded_path))
    else
      Dir.pwd
    end
end
delete(key) click to toggle source
# File lib/rubbycop/config.rb, line 132
def delete(key)
  @hash.delete(key)
end
deprecation_check() { |"AllCops/#{plural} was renamed to AllCops/#{key}"| ... } click to toggle source
# File lib/rubbycop/config.rb, line 196
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
each(&block) click to toggle source
# File lib/rubbycop/config.rb, line 136
def each(&block)
  @hash.each(&block)
end
file_to_exclude?(file) click to toggle source
# File lib/rubbycop/config.rb, line 260
def file_to_exclude?(file)
  file = File.expand_path(file)
  patterns_to_exclude.any? do |pattern|
    match_path?(pattern, file)
  end
end
file_to_include?(file) click to toggle source
# File lib/rubbycop/config.rb, line 233
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
for_all_cops() click to toggle source
# File lib/rubbycop/config.rb, line 211
def for_all_cops
  @for_all_cops ||= self['AllCops'] || {}
end
for_cop(cop) click to toggle source
# File lib/rubbycop/config.rb, line 207
def for_cop(cop)
  @for_cop[cop.respond_to?(:cop_name) ? cop.cop_name : cop]
end
key?(key) click to toggle source
# File lib/rubbycop/config.rb, line 140
def key?(key)
  @hash.key?(key)
end
keys() click to toggle source
# File lib/rubbycop/config.rb, line 144
def keys
  @hash.keys
end
make_excludes_absolute() click to toggle source
# File lib/rubbycop/config.rb, line 168
def make_excludes_absolute
  each 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
map(&block) click to toggle source
# File lib/rubbycop/config.rb, line 148
def map(&block)
  @hash.map(&block)
end
merge(other_hash) click to toggle source
# File lib/rubbycop/config.rb, line 152
def merge(other_hash)
  @hash.merge(other_hash)
end
path_relative_to_config(path) click to toggle source
# File lib/rubbycop/config.rb, line 275
def path_relative_to_config(path)
  relative_path(path, base_dir_for_path_parameters)
end
patterns_to_exclude() click to toggle source
# File lib/rubbycop/config.rb, line 271
def patterns_to_exclude
  for_all_cops['Exclude']
end
patterns_to_include() click to toggle source
# File lib/rubbycop/config.rb, line 267
def patterns_to_include
  for_all_cops['Include']
end
possibly_include_hidden?() click to toggle source

Returns true if there's a chance that an Include pattern matches hidden files, false if that's definitely not possible.

# File lib/rubbycop/config.rb, line 252
def possibly_include_hidden?
  return @possibly_include_hidden if defined?(@possibly_include_hidden)

  @possibly_include_hidden = patterns_to_include.any? do |s|
    s.is_a?(Regexp) || s.start_with?('.') || s.include?('/.')
  end
end
target_rails_version() click to toggle source
# File lib/rubbycop/config.rb, line 311
def target_rails_version
  @target_rails_version ||=
    for_all_cops.fetch('TargetRailsVersion', DEFAULT_RAILS_VERSION)
end
target_ruby_version() click to toggle source
# File lib/rubbycop/config.rb, line 294
def target_ruby_version
  @target_ruby_version ||=
    if for_all_cops['TargetRubyVersion']
      @target_ruby_version_source = :rubbycop_yml

      for_all_cops['TargetRubyVersion']
    elsif File.file?('.ruby-version') &&
          /\A(ruby-)?(?<version>\d+\.\d+)/ =~ File.read('.ruby-version')

      @target_ruby_version_source = :dot_ruby_version

      version.to_f
    else
      DEFAULT_RUBY_VERSION
    end
end
to_h() click to toggle source
# File lib/rubbycop/config.rb, line 156
def to_h
  @hash
end
to_hash() click to toggle source
# File lib/rubbycop/config.rb, line 160
def to_hash
  @hash
end
to_s() click to toggle source
# File lib/rubbycop/config.rb, line 164
def to_s
  @to_s ||= @hash.to_s
end
validate() click to toggle source
# File lib/rubbycop/config.rb, line 215
def validate
  # Don't validate RubbyCop'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_and_parameters
  warn_about_unrecognized_cops(invalid_cop_names)
  check_target_ruby
  validate_parameter_names(valid_cop_names)
  validate_enforced_styles(valid_cop_names)
  reject_mutually_exclusive_defaults
end

Private Instance Methods

check_target_ruby() click to toggle source
# File lib/rubbycop/config.rb, line 403
def check_target_ruby
  return if 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 :rubbycop_yml
      "in `TargetRubyVersion` parameter (in #{loaded_path})." \
    end

  msg += "\nKnown versions: #{KNOWN_RUBIES.join(', ')}"

  raise ValidationError, msg
end
enable_cop?(qualified_cop_name, cop_options) click to toggle source
# File lib/rubbycop/config.rb, line 430
def enable_cop?(qualified_cop_name, cop_options)
  cop_department, cop_name = qualified_cop_name.split('/')
  department = cop_name.nil?

  unless department
    department_options = self[cop_department]
    if department_options && department_options.fetch('Enabled') == false
      return false
    end
  end

  cop_options.fetch('Enabled', true)
end
obsolete_cops() click to toggle source
# File lib/rubbycop/config.rb, line 395
def obsolete_cops
  OBSOLETE_COPS.map do |cop_name, message|
    next unless key?(cop_name) || key?(Cop::Badge.parse(cop_name).cop_name)
    message + "\n(obsolete configuration found in #{loaded_path}, please" \
               ' update it)'
  end
end
obsolete_parameter_message(cop, parameter, alternative) click to toggle source
# File lib/rubbycop/config.rb, line 387
def obsolete_parameter_message(cop, parameter, alternative)
  return unless self[cop] && self[cop].key?(parameter)

  "obsolete parameter #{parameter} (for #{cop}) " \
    "found in #{loaded_path}" \
    "\n#{alternative}"
end
obsolete_parameters() click to toggle source
# File lib/rubbycop/config.rb, line 380
def obsolete_parameters
  OBSOLETE_PARAMETERS.map do |params|
    obsolete_parameter_message(params[:cop], params[:parameter],
                               params[:alternative])
  end
end
reject_mutually_exclusive_defaults() click to toggle source
# File lib/rubbycop/config.rb, line 421
def reject_mutually_exclusive_defaults
  disabled_by_default = for_all_cops['DisabledByDefault']
  enabled_by_default = for_all_cops['EnabledByDefault']
  return unless disabled_by_default && enabled_by_default

  msg = 'Cops cannot be both enabled by default and disabled by default'
  raise ValidationError, msg
end
reject_obsolete_cops_and_parameters() click to toggle source
# File lib/rubbycop/config.rb, line 370
def reject_obsolete_cops_and_parameters
  messages = [
    obsolete_cops,
    obsolete_parameters
  ].flatten.compact
  return if messages.empty?

  raise ValidationError, messages.join("\n")
end
validate_enforced_styles(valid_cop_names) click to toggle source
# File lib/rubbycop/config.rb, line 352
def validate_enforced_styles(valid_cop_names)
  valid_cop_names.each do |name|
    styles = self[name].select { |key, _| key.start_with?('Enforced') }

    styles.each do |style_name, style|
      supported_key = RubbyCop::Cop::Util.to_supported_styles(style_name)
      valid = ConfigLoader.default_configuration[name][supported_key]
      next unless valid
      next if valid.include?(style)

      msg = "invalid #{style_name} '#{style}' for #{name} found in " \
        "#{loaded_path}\n" \
        "Valid choices are: #{valid.join(', ')}"
      raise ValidationError, msg
    end
  end
end
validate_parameter_names(valid_cop_names) click to toggle source
# File lib/rubbycop/config.rb, line 339
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
validate_section_presence(name) click to toggle source
# File lib/rubbycop/config.rb, line 334
def validate_section_presence(name)
  return unless key?(name) && self[name].nil?
  raise ValidationError, "empty section #{name} found in #{loaded_path}"
end
warn_about_unrecognized_cops(invalid_cop_names) click to toggle source
# File lib/rubbycop/config.rb, line 318
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.registry.contains_cop_matching?([name])

    warn Rainbow("Warning: unrecognized cop #{name} found in " \
                 "#{loaded_path}").yellow
  end
end