Class: RuboCop::Plugin::ConfigurationIntegrator Private
| Relationships & Source Files | |
| Inherits: | Object |
| Defined in: | lib/rubocop/plugin/configuration_integrator.rb |
Overview
A class for integrating plugin configurations into RuboCop. Handles configuration merging, validation, and compatibility for plugins.
Class Method Summary
- .integrate_plugins_into_rubocop_config(rubocop_config, plugins) Internal use only
- .combine_rubocop_configs(default_config, runner_context, plugins) private Internal use only
- .create_context(rubocop_config) private Internal use only
- .fake_out_rubocop_default_configuration(default_config) private Internal use only
-
.load_plugin_rubocop_config(plugin, runner_context)
private
Internal use only
rubocop:disable-next Metrics/AbcSize.
-
.merge_all_cop_settings(existing_all_cops, new_all_cops, already_configured_keys)
private
Internal use only
This is how we ensure "first-in wins": plugins can override AllCops settings that are set by RuboCop’s default configuration, but once a plugin sets an AllCop setting, they have exclusive first-in-wins rights to that setting.
- .merge_plugin_config_into_all_cops!(rubocop_config, plugin_config) private Internal use only
- .merge_plugin_config_into_default_config!(default_config, plugin_config) private Internal use only
-
.merge_plugin_config_with_default(plugin_config, plugin_config_path)
private
Internal use only
unset_nil: falsekeepsAllCopskeys declared with a nil value by a plugin (e.g.TargetRailsVersion: ~of rubocop-rails); .merge_all_cop_settings carries such keys into each subsequent plugin’s config, whereunset_nil: truewould delete them from the combined configuration. - .plugin_name(plugin) private Internal use only
- .resolver private Internal use only
- .validate_plugins!(plugins, runner_context) private Internal use only
-
.warn_about_obsolete_config(plugin, config)
private
Internal use only
Plugin configuration is loaded without validation, so an obsolete key in a plugin’s defaults used to surface only later, against the user’s own file, once the two had been merged.
Class Method Details
.combine_rubocop_configs(default_config, runner_context, plugins) (private)
[ GitHub ]# File 'lib/rubocop/plugin/configuration_integrator.rb', line 44
def combine_rubocop_configs(default_config, runner_context, plugins) fake_out_rubocop_default_configuration(default_config) do |fake_config| all_cop_keys_configured_by_plugins = [] plugins.reduce(fake_config) do |combined_config, plugin| RuboCop::ConfigLoader.instance_variable_set(:@default_configuration, combined_config) print 'Plugin ' if ConfigLoader.debug plugin_config, plugin_config_path = load_plugin_rubocop_config(plugin, runner_context) plugin_config['AllCops'], all_cop_keys_configured_by_plugins = merge_all_cop_settings( combined_config['AllCops'], plugin_config['AllCops'], all_cop_keys_configured_by_plugins ) plugin_config.make_excludes_absolute merge_plugin_config_with_default(plugin_config, plugin_config_path) end end end
.create_context(rubocop_config) (private)
[ GitHub ].fake_out_rubocop_default_configuration(default_config) (private)
[ GitHub ]# File 'lib/rubocop/plugin/configuration_integrator.rb', line 92
def fake_out_rubocop_default_configuration(default_config) orig_default_config = ConfigLoader.instance_variable_get(:@default_configuration) result = yield default_config ConfigLoader.instance_variable_set(:@default_configuration, orig_default_config) result end
.integrate_plugins_into_rubocop_config(rubocop_config, plugins)
[ GitHub ]# File 'lib/rubocop/plugin/configuration_integrator.rb', line 13
def integrate_plugins_into_rubocop_config(rubocop_config, plugins) default_config = ConfigLoader.default_configuration runner_context = create_context(rubocop_config) validate_plugins!(plugins, runner_context) plugin_config = combine_rubocop_configs(default_config, runner_context, plugins).to_h merge_plugin_config_into_all_cops!(default_config, plugin_config) merge_plugin_config_into_default_config!(default_config, plugin_config) end
.load_plugin_rubocop_config(plugin, runner_context) (private)
rubocop:disable-next Metrics/AbcSize
# File 'lib/rubocop/plugin/configuration_integrator.rb', line 103
def load_plugin_rubocop_config(plugin, runner_context) rules = plugin.rules(runner_context) case rules.type when :path config = ConfigLoader.load_file(rules.value, check: false) warn_about_obsolete_config(plugin, config) [config, rules.value] when :object path = plugin.method(:rules).source_location[0] [Config.create(rules.value, path, check: true), path] when :error = rules.value.respond_to?(:) ? rules.value. : rules.value raise "Plugin `#{plugin_name(plugin)}' failed to load with error: #{}" end end
.merge_all_cop_settings(existing_all_cops, new_all_cops, already_configured_keys) (private)
This is how we ensure "first-in wins": plugins can override AllCops settings that are set by RuboCop’s default configuration, but once a plugin sets an AllCop setting, they have exclusive first-in-wins rights to that setting.
The one exception to this are array fields, because we don’t want to
overwrite the AllCops defaults but rather munge the arrays (existing |
new) to allow plugins to add to the array, for example Include and
Exclude paths and patterns.
# File 'lib/rubocop/plugin/configuration_integrator.rb', line 149
def merge_all_cop_settings(existing_all_cops, new_all_cops, already_configured_keys) return [existing_all_cops, already_configured_keys] unless new_all_cops.is_a?(Hash) combined_all_cops = existing_all_cops.dup combined_configured_keys = already_configured_keys.dup new_all_cops.each do |key, value| if combined_all_cops[key].is_a?(Array) && value.is_a?(Array) combined_all_cops[key] |= value combined_configured_keys |= [key] elsif !combined_configured_keys.include?(key) combined_all_cops[key] = value combined_configured_keys << key end end [combined_all_cops, combined_configured_keys] end
.merge_plugin_config_into_all_cops!(rubocop_config, plugin_config) (private)
[ GitHub ]# File 'lib/rubocop/plugin/configuration_integrator.rb', line 78
def merge_plugin_config_into_all_cops!(rubocop_config, plugin_config) rubocop_config['AllCops'].merge!(plugin_config['AllCops']) end
.merge_plugin_config_into_default_config!(default_config, plugin_config) (private)
[ GitHub ]# File 'lib/rubocop/plugin/configuration_integrator.rb', line 82
def merge_plugin_config_into_default_config!(default_config, plugin_config) plugin_config.each do |key, value| default_config[key] = if default_config[key].is_a?(Hash) resolver.merge(default_config[key], value) else value end end end
.merge_plugin_config_with_default(plugin_config, plugin_config_path) (private)
unset_nil: false keeps AllCops keys declared with a nil value by a plugin
(e.g. TargetRailsVersion: ~ of rubocop-rails); .merge_all_cop_settings carries
such keys into each subsequent plugin’s config, where unset_nil: true would
delete them from the combined configuration. Preview is left to be applied when
a project configuration is resolved against the defaults.
# File 'lib/rubocop/plugin/configuration_integrator.rb', line 72
def merge_plugin_config_with_default(plugin_config, plugin_config_path) ConfigLoader.merge_with_default( plugin_config, plugin_config_path, unset_nil: false, resolve_preview: false ) end
.plugin_name(plugin) (private)
[ GitHub ]# File 'lib/rubocop/plugin/configuration_integrator.rb', line 137
def plugin_name(plugin) plugin.about&.name || plugin.inspect end
.resolver (private)
[ GitHub ]# File 'lib/rubocop/plugin/configuration_integrator.rb', line 168
def resolver @resolver ||= ConfigLoaderResolver.new end
.validate_plugins!(plugins, runner_context) (private)
# File 'lib/rubocop/plugin/configuration_integrator.rb', line 37
def validate_plugins!(plugins, runner_context) unsupported_plugins = plugins.reject { |plugin| plugin.supported?(runner_context) } return if unsupported_plugins.none? raise Plugin::NotSupportedError, unsupported_plugins end
.warn_about_obsolete_config(plugin, config) (private)
Plugin configuration is loaded without validation, so an obsolete key in a plugin’s defaults used to surface only later, against the user’s own file, once the two had been merged. Report it here, while the path is still the plugin’s, and name the plugin: the file lives inside an installed gem, so the fix is to report it upstream. It is a warning whatever the rule’s severity: a stale plugin is not the user’s mistake and must not stop the run.
# File 'lib/rubocop/plugin/configuration_integrator.rb', line 127
def warn_about_obsolete_config(plugin, config) = ConfigObsoletion.new(config). return if .empty? warn Rainbow(<<~WARNING).yellow Warning: obsolete configuration found in the `#{plugin_name(plugin)}` plugin: #{.join("\n")} WARNING end