Class: RuboCop::Config
| Relationships & Source Files | |
| Namespace Children | |
|
Classes:
| |
| Super Chains via Extension / Inclusion / Inheritance | |
|
Class Chain:
self,
SimpleForwardable
|
|
|
Instance Chain:
self,
FileFinder,
PathUtil
|
|
| Inherits: | Object |
| Defined in: | lib/rubocop/config.rb |
Overview
This class represents the configuration of the RuboCop 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 rubocop program, if files in several directories are inspected.
Constant Summary
-
DEFAULT_RAILS_VERSION =
# File 'lib/rubocop/config.rb', line 205.0 -
EMPTY_CONFIG =
# File 'lib/rubocop/config.rb', line 19{}.freeze
PathUtil - Included
Class Method Summary
- .create(hash, path, check: true)
-
.new(hash = RuboCop::ConfigLoader.default_configuration, loaded_path = nil) ⇒ Config
constructor
rubocop:disable-next Metrics/AbcSize, Metrics/MethodLength.
Instance Attribute Summary
- #active_support_extensions_enabled? ⇒ Boolean readonly
- #disabled_new_cops? ⇒ Boolean readonly
- #enabled_new_cops? ⇒ Boolean readonly
-
#internal? ⇒ Boolean
readonly
True if this is a config file that is shipped with RuboCop.
- #loaded_path readonly
-
#possibly_include_hidden? ⇒ Boolean
readonly
Returns true if there’s a chance that an Include pattern matches hidden files, false if that’s definitely not possible.
- #string_literals_frozen_by_default? ⇒ Boolean readonly
Instance Method Summary
- #add_excludes_from_higher_level(highest_config)
- #allowed_camel_case_file?(file) ⇒ Boolean
-
#base_dir_for_path_parameters
Paths specified in configuration files starting with .rubocop are relative to the directory where that file is.
- #bundler_lock_file_path ⇒ String?
- #check
- #clusivity_config_for_badge?(badge) ⇒ Boolean Internal use only
- #cop_enabled?(name) ⇒ Boolean
- #deprecation_check
-
#enabled_new_cop?(qualified_cop_name) ⇒ Boolean
Whether the given pending cop should be enabled, based on the
NewCopssetting of its department (if any) or ofAllCops. - #file_to_exclude?(file) ⇒ Boolean
-
#file_to_include?(file) ⇒ Boolean
Returns true if the file matches any include pattern.
- #for_all_cops
-
#for_badge(badge) ⇒ Config
Note: the 'Enabled' attribute is same as that returned by
for_cop. -
#for_cop(cop) ⇒ Config
Note: the 'Enabled' attribute is calculated according to the department’s and 'AllCops' configuration; other attributes are not inherited.
-
#for_department(department_name) ⇒ Config
Note: the 'Enabled' attribute will be present only if specified at the department’s level.
-
#for_enabled_cop(cop) ⇒ Config, Hash
If the given cop is enabled, returns its configuration hash.
-
#gem_versions_in_target
Returns target’s locked gem versions (i.e.
- #inspect Internal use only
- #loaded_features
- #loaded_plugins
- #make_excludes_absolute
- #parser_engine
- #path_relative_to_config(path)
- #patterns_to_exclude
- #patterns_to_include
- #pending_cops
- #signature
- #smart_loaded_path
- #target_rails_version
- #to_s
- #validate_after_resolution
-
#comparable_version(value)
private
Returns a
Gem::Versionfor values like'1.19'or1.19, andnilfor non-version values like'N/A'orhref="#next">[next]'. - #department_of(qualified_cop_name) private
- #enable_cop?(qualified_cop_name, cop_options) ⇒ Boolean private
- #gem_version_to_major_minor_float(gem_version) ⇒ Float private
- #match_relative_or_absolute_path?(pattern, relative_file_path, absolute_file_path) ⇒ Boolean private
-
#new_cops_covered?(qualified_cop_name) ⇒ Boolean
private
Whether the cop’s pending status is resolved by a
NewCopssetting, so that it should not appear in the pending cops warning. -
#new_cops_setting_for(qualified_cop_name)
private
The effective
NewCopssetting for the given cop: the department-level setting if present, otherwise theAllCopssetting. - #new_cops_version_covers?(new_cops_version, qualified_cop_name) ⇒ Boolean private
- #read_gem_versions_from_target_lockfile private
- #read_rails_version_from_bundler_lock_file ⇒ Float? private
- #target_rails_version_from_bundler_lock_file ⇒ Float? private
FileFinder - Included
PathUtil - Included
| #absolute? | Returns true for an absolute Unix or Windows path. |
| #glob? | Returns true for a glob. |
| #hidden_dir?, #hidden_file?, #hidden_file_in_not_hidden_dir?, | |
| #match_path? | rubocop:disable-next Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity. |
| #maybe_hidden_file? | Loose check to reduce memory allocations. |
| #pwd | Returns the current working directory, cached for the duration of a run. |
| #relative_path, #remote_file?, | |
| #reset_pwd | Reset the cached pwd. |
| #smart_path | |
Constructor Details
.new(hash = RuboCop::ConfigLoader.default_configuration, loaded_path = nil) ⇒ Config
rubocop:disable-next Metrics/AbcSize, Metrics/MethodLength
# File 'lib/rubocop/config.rb', line 31
def initialize(hash = RuboCop::ConfigLoader.default_configuration, loaded_path = nil) @loaded_path = loaded_path @for_cop = Hash.new do |h, cop| cop_name = cop.respond_to?(:cop_name) ? cop.cop_name : cop if ConfigObsoletion.deprecated_cop_name?(cop) # Since a deprecated cop will no longer have a qualified name (as the badge is no # longer valid), and since we do not want to automatically enable the cop, we just # set the configuration to an empty hash if it is unset. # This is necessary to allow a renamed cop have its old configuration merged in # before being used (which is necessary to allow it to be disabled via config). = self[cop_name].dup || {} else qualified_cop_name = Cop::Registry.qualified_cop_name(cop_name, loaded_path, warn: false) = self[qualified_cop_name].dup || {} ['Enabled'] = enable_cop?(qualified_cop_name, ) # If the cop has deprecated names (ie. it has been renamed), it is possible that # users will still have old configuration for the cop's old name. In this case, # if `ConfigObsoletion` is configured to warn rather than error (and therefore # RuboCop runs), we want to respect the old configuration, so merge it in. # # NOTE: If there is configuration for both the cop and a deprecated names, the old # configuration will be merged on top of the new configuration! ConfigObsoletion.deprecated_names_for(cop).each do |deprecated_cop_name| deprecated_config = @for_cop[deprecated_cop_name] next if deprecated_config.empty? warn Rainbow(<<~WARNING).yellow Warning: Using `#{deprecated_cop_name}` configuration in #{loaded_path} for `#{cop}`. WARNING .merge!(@for_cop[deprecated_cop_name]) end end h[cop] = h[cop_name] = end @hash = hash @validator = ConfigValidator.new(self) @badge_config_cache = {}.compare_by_identity @clusivity_config_exists_cache = {} end
Class Method Details
.create(hash, path, check: true)
[ GitHub ]Instance Attribute Details
#active_support_extensions_enabled? ⇒ Boolean (readonly)
[ GitHub ]
# File 'lib/rubocop/config.rb', line 229
def active_support_extensions_enabled? for_all_cops['ActiveSupportExtensionsEnabled'] end
#disabled_new_cops? ⇒ Boolean (readonly)
[ GitHub ]
# File 'lib/rubocop/config.rb', line 207
def disabled_new_cops? for_all_cops['NewCops'] == 'disable' end
#enabled_new_cops? ⇒ Boolean (readonly)
[ GitHub ]
# File 'lib/rubocop/config.rb', line 211
def enabled_new_cops? for_all_cops['NewCops'] == 'enable' end
#internal? ⇒ Boolean (readonly)
True if this is a config file that is shipped with RuboCop
# File 'lib/rubocop/config.rb', line 109
def internal? base_config_path = File.(File.join(ConfigLoader::RUBOCOP_HOME, 'config')) File.(loaded_path).start_with?(base_config_path) end
#loaded_path (readonly)
[ GitHub ]# File 'lib/rubocop/config.rb', line 21
attr_reader :loaded_path
#string_literals_frozen_by_default? ⇒ Boolean (readonly)
[ GitHub ]
# File 'lib/rubocop/config.rb', line 233
def string_literals_frozen_by_default? for_all_cops['StringLiteralsFrozenByDefault'] end
Instance Method Details
#add_excludes_from_higher_level(highest_config)
[ GitHub ]# File 'lib/rubocop/config.rb', line 126
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
#allowed_camel_case_file?(file) ⇒ Boolean
# File 'lib/rubocop/config.rb', line 257
def allowed_camel_case_file?(file) # Gemspecs are allowed to have dashes because that fits with bundler best # practices in the case when the gem is nested under a namespace (e.g., # `bundler-console` conveys `Bundler::Console`). return true if File.extname(file) == '.gemspec' file_to_include?(file) { |pattern| /[A-Z]/.match?(pattern.to_s) } end
#base_dir_for_path_parameters
Paths specified in configuration files starting with .rubocop 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 RuboCop’s config directory since that wouldn’t work.
# File 'lib/rubocop/config.rb', line 298
def base_dir_for_path_parameters @base_dir_for_path_parameters ||= if loaded_path && File.basename(loaded_path).start_with?('.rubocop') && loaded_path != File.join(Dir.home, ConfigLoader::DOTFILE) File.(File.dirname(loaded_path)) else PathUtil.pwd end end
#bundler_lock_file_path ⇒ String?
# File 'lib/rubocop/config.rb', line 328
def bundler_lock_file_path return nil unless loaded_path base_path = base_dir_for_path_parameters ['Gemfile.lock', 'gems.locked'].each do |file_name| path = find_file_upwards(file_name, base_path) return path if path end nil end
#check
[ GitHub ]# File 'lib/rubocop/config.rb', line 84
def check deprecation_check { || warn("#{loaded_path} - #{}") } @validator.validate make_excludes_absolute self end
#clusivity_config_for_badge?(badge) ⇒ Boolean
#comparable_version(value) (private)
Returns a Gem::Version for values like '1.19' or 1.19, and nil
for non-version values like 'N/A' or href="#next">[next]'.
#cop_enabled?(name) ⇒ Boolean
# File 'lib/rubocop/config.rb', line 203
def cop_enabled?(name) !!for_cop(name)['Enabled'] end
#department_of(qualified_cop_name) (private)
[ GitHub ]# File 'lib/rubocop/config.rb', line 414
def department_of(qualified_cop_name) *cop_department, _ = qualified_cop_name.split('/') return nil if cop_department.empty? self[cop_department.join('/')] end
#deprecation_check
[ GitHub ]# File 'lib/rubocop/config.rb', line 138
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
#enable_cop?(qualified_cop_name, cop_options) ⇒ Boolean (private)
# File 'lib/rubocop/config.rb', line 402
def enable_cop?(qualified_cop_name, ) # If the cop is explicitly enabled or `Lint/Syntax`, the other checks can be skipped. return true if ['Enabled'] == true || qualified_cop_name == 'Lint/Syntax' department = department_of(qualified_cop_name) cop_enabled = .fetch('Enabled') { !for_all_cops['DisabledByDefault'] } return true if cop_enabled == 'override_department' return false if department && department['Enabled'] == false cop_enabled end
#enabled_new_cop?(qualified_cop_name) ⇒ Boolean
Whether the given pending cop should be enabled, based on the NewCops setting of
its department (if any) or of AllCops. A department may set NewCops to enable,
disable, pending, or a version, in which case pending cops added in that version
or earlier are enabled.
# File 'lib/rubocop/config.rb', line 219
def enabled_new_cop?(qualified_cop_name) setting = new_cops_setting_for(qualified_cop_name) case setting.to_s when 'enable' then true when '', 'pending', 'disable' then false else new_cops_version_covers?(setting, qualified_cop_name) end end
#file_to_exclude?(file) ⇒ Boolean
# File 'lib/rubocop/config.rb', line 276
def file_to_exclude?(file) file = File.(file) patterns_to_exclude.any? { |pattern| match_path?(pattern, file) } end
#file_to_include?(file) ⇒ Boolean
Returns true if the file matches any include pattern. If a block is given, the block is called to determine if the pattern is relevant (true returned by the block) or should be skipped (false returned).
# File 'lib/rubocop/config.rb', line 240
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 cannot 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.(file) patterns_to_include.any? do |pattern| next if block_given? && !yield(pattern) match_relative_or_absolute_path?(pattern, relative_file_path, absolute_file_path) end end
#for_all_cops
[ GitHub ]# File 'lib/rubocop/config.rb', line 199
def for_all_cops @for_all_cops ||= self['AllCops'] || {} end
#for_badge(badge) ⇒ Config
Note: the 'Enabled' attribute is same as that returned by for_cop
# File 'lib/rubocop/config.rb', line 165
def for_badge(badge) @badge_config_cache[badge] ||= begin department_config = self[badge.department_name] cop_config = for_cop(badge.to_s) if department_config merged_config = department_config.merge(cop_config) if department_config['Exclude'] && cop_config['Exclude'] merged_config['Exclude'] = department_config['Exclude'] | cop_config['Exclude'] end merged_config else cop_config end end end
#for_cop(cop) ⇒ Config
Note: the 'Enabled' attribute is calculated according to the department’s and 'AllCops' configuration; other attributes are not inherited.
# File 'lib/rubocop/config.rb', line 152
def for_cop(cop) @for_cop[cop] end
#for_department(department_name) ⇒ Config
Note: the 'Enabled' attribute will be present only if specified at the department’s level
#for_enabled_cop(cop) ⇒ Config, Hash
If the given cop is enabled, returns its configuration hash. Otherwise, returns an empty hash.
# File 'lib/rubocop/config.rb', line 159
def for_enabled_cop(cop) cop_enabled?(cop) ? for_cop(cop) : EMPTY_CONFIG end
#gem_version_to_major_minor_float(gem_version) ⇒ Float (private)
# File 'lib/rubocop/config.rb', line 389
def gem_version_to_major_minor_float(gem_version) segments = gem_version.segments Float("#{segments[0]}.#{segments[1]}") end
#gem_versions_in_target
Returns target’s locked gem versions (i.e. from Gemfile.lock or gems.locked)
# File 'lib/rubocop/config.rb', line 354
def gem_versions_in_target @gem_versions_in_target ||= read_gem_versions_from_target_lockfile end
#inspect
# File 'lib/rubocop/config.rb', line 358
def inspect # :nodoc: "#<#{self.class.name}:#{object_id} @loaded_path=#{loaded_path}>" end
#loaded_features
[ GitHub ]# File 'lib/rubocop/config.rb', line 80
def loaded_features @loaded_features ||= ConfigLoader.loaded_features end
#loaded_plugins
[ GitHub ]# File 'lib/rubocop/config.rb', line 76
def loaded_plugins @loaded_plugins ||= ConfigLoader.loaded_plugins end
#make_excludes_absolute
[ GitHub ]# File 'lib/rubocop/config.rb', line 114
def make_excludes_absolute each_key do |key| dig(key, 'Exclude')&.map! do |exclude_elem| if exclude_elem.is_a?(String) && !absolute?(exclude_elem) File.(File.join(base_dir_for_path_parameters, exclude_elem)) else exclude_elem end end end end
#match_relative_or_absolute_path?(pattern, relative_file_path, absolute_file_path) ⇒ Boolean (private)
# File 'lib/rubocop/config.rb', line 364
def match_relative_or_absolute_path?(pattern, relative_file_path, absolute_file_path) should_use_absolute_path = absolute?(pattern.to_s) || pattern.to_s.start_with?('..') || relative_file_path.start_with?('..') match_path?(pattern, should_use_absolute_path ? absolute_file_path : relative_file_path) end
#new_cops_covered?(qualified_cop_name) ⇒ Boolean (private)
Whether the cop’s pending status is resolved by a NewCops setting,
so that it should not appear in the pending cops warning.
Unlike #enabled_new_cop?, disable counts as covered.
# File 'lib/rubocop/config.rb', line 433
def new_cops_covered?(qualified_cop_name) setting = new_cops_setting_for(qualified_cop_name) case setting.to_s when 'enable', 'disable' then true when '', 'pending' then false else new_cops_version_covers?(setting, qualified_cop_name) end end
#new_cops_setting_for(qualified_cop_name) (private)
The effective NewCops setting for the given cop: the department-level
setting if present, otherwise the AllCops setting.
# File 'lib/rubocop/config.rb', line 423
def new_cops_setting_for(qualified_cop_name) department = department_of(qualified_cop_name) setting = department['NewCops'] if department setting || for_all_cops['NewCops'] end
#new_cops_version_covers?(new_cops_version, qualified_cop_name) ⇒ Boolean (private)
# File 'lib/rubocop/config.rb', line 443
def new_cops_version_covers?(new_cops_version, qualified_cop_name) = self[qualified_cop_name] version_added = comparable_version(['VersionAdded']) if pinned_version = comparable_version(new_cops_version) return false if version_added.nil? || pinned_version.nil? version_added <= pinned_version end
#parser_engine
[ GitHub ]# File 'lib/rubocop/config.rb', line 308
def parser_engine @parser_engine ||= for_all_cops.fetch('ParserEngine', :default).to_sym end
#path_relative_to_config(path)
[ GitHub ]# File 'lib/rubocop/config.rb', line 289
def path_relative_to_config(path) relative_path(path, base_dir_for_path_parameters) end
#patterns_to_exclude
[ GitHub ]# File 'lib/rubocop/config.rb', line 285
def patterns_to_exclude for_all_cops['Exclude'] || [] end
#patterns_to_include
[ GitHub ]# File 'lib/rubocop/config.rb', line 281
def patterns_to_include for_all_cops['Include'] || [] end
#pending_cops
[ GitHub ]# File 'lib/rubocop/config.rb', line 339
def pending_cops keys.each_with_object([]) do |qualified_cop_name, pending_cops| department = department_of(qualified_cop_name) next if department && department['Enabled'] == false = self[qualified_cop_name] next unless ['Enabled'] == 'pending' next if new_cops_covered?(qualified_cop_name) pending_cops << CopConfig.new(qualified_cop_name, ) end end
#read_gem_versions_from_target_lockfile (private)
[ GitHub ]# File 'lib/rubocop/config.rb', line 395
def read_gem_versions_from_target_lockfile lockfile_path = bundler_lock_file_path return nil unless lockfile_path Lockfile.new(lockfile_path).gem_versions end
#read_rails_version_from_bundler_lock_file ⇒ Float? (private)
# File 'lib/rubocop/config.rb', line 376
def read_rails_version_from_bundler_lock_file return nil unless gem_versions_in_target # Look for `railties` instead of `rails`, to support apps that only use a subset of `rails` # See https://github.com/rubocop/rubocop/pull/11289 rails_version_in_target = gem_versions_in_target['railties'] return nil unless rails_version_in_target gem_version_to_major_minor_float(rails_version_in_target) end
#signature
[ GitHub ]# File 'lib/rubocop/config.rb', line 104
def signature @signature ||= Digest::SHA1.hexdigest(to_s) end
#smart_loaded_path
[ GitHub ]# File 'lib/rubocop/config.rb', line 323
def smart_loaded_path PathUtil.smart_path(@loaded_path) end
#target_rails_version
[ GitHub ]# File 'lib/rubocop/config.rb', line 312
def target_rails_version @target_rails_version ||= if for_all_cops['TargetRailsVersion'] for_all_cops['TargetRailsVersion'].to_f elsif target_rails_version_from_bundler_lock_file target_rails_version_from_bundler_lock_file else DEFAULT_RAILS_VERSION end end
#target_rails_version_from_bundler_lock_file ⇒ Float? (private)
# File 'lib/rubocop/config.rb', line 371
def target_rails_version_from_bundler_lock_file @target_rails_version_from_bundler_lock_file ||= read_rails_version_from_bundler_lock_file end
#to_s
[ GitHub ]# File 'lib/rubocop/config.rb', line 100
def to_s @to_s ||= @hash.to_s end
#validate_after_resolution
[ GitHub ]# File 'lib/rubocop/config.rb', line 91
def validate_after_resolution @validator.validate_after_resolution self end