diff --git a/CHANGELOG.md b/CHANGELOG.md index eec3ce1acc7..892ad6b9cb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ * Do not annotate message with cop name in JSON output. ([@elebow][]) * [#6914](https://github.com/rubocop-hq/rubocop/issues/6914): [Fix #6914] Fix an error for `Rails/RedundantAllowNil` when with interpolations. ([@Blue-Pix][]) * [#6941](https://github.com/rubocop-hq/rubocop/issues/6941): Add missing absence validations to `Rails/Validation`. ([@jmanian][]) +* [#6926](https://github.com/rubocop-hq/rubocop/issues/6926): [Fix #6926] Allow nil values to unset config defaults. ([@dduugg][]) ### Changes diff --git a/lib/rubocop/config_loader_resolver.rb b/lib/rubocop/config_loader_resolver.rb index fbf8fefc448..85be7da02ff 100644 --- a/lib/rubocop/config_loader_resolver.rb +++ b/lib/rubocop/config_loader_resolver.rb @@ -71,9 +71,8 @@ def merge_with_default(config, config_file) config = handle_disabled_by_default(config, default_configuration) end - Config.new(merge(default_configuration, config, - inherit_mode: config['inherit_mode'] || {}), - config_file) + opts = { inherit_mode: config['inherit_mode'] || {}, unset_nil: true } + Config.new(merge(default_configuration, config, opts), config_file) end # Return a recursive merge of two hashes. That is, a normal hash merge, @@ -85,7 +84,9 @@ def merge(base_hash, derived_hash, **opts) result = base_hash.merge(derived_hash) keys_appearing_in_both = base_hash.keys & derived_hash.keys keys_appearing_in_both.each do |key| - if base_hash[key].is_a?(Hash) + if opts[:unset_nil] && derived_hash[key].nil? + result.delete(key) + elsif base_hash[key].is_a?(Hash) result[key] = merge(base_hash[key], derived_hash[key], **opts) elsif should_union?(base_hash, key, opts[:inherit_mode]) result[key] = base_hash[key] | derived_hash[key] diff --git a/spec/rubocop/config_loader_spec.rb b/spec/rubocop/config_loader_spec.rb index e22ca817d38..87b4cf63c36 100644 --- a/spec/rubocop/config_loader_spec.rb +++ b/spec/rubocop/config_loader_spec.rb @@ -277,6 +277,45 @@ end end + context 'when a file inherits and overrides a hash with nil' do + let(:file_path) { '.rubocop.yml' } + + before do + create_file('.rubocop_parent.yml', <<-YAML.strip_indent) + Style/InverseMethods: + InverseMethods: + :any?: :none? + :even?: :odd? + :==: :!= + :=~: :!~ + :<: :>= + :>: :<= + YAML + + create_file('.rubocop.yml', <<-YAML.strip_indent) + inherit_from: .rubocop_parent.yml + + Style/InverseMethods: + InverseMethods: + :<: ~ + :>: ~ + :foo: :bar + YAML + end + + it 'removes hash keys with nil values' do + inverse_methods = + configuration_from_file['Style/InverseMethods']['InverseMethods'] + expect(inverse_methods).to eq( + '==': :!=, + '=~': :!~, + any?: :none?, + even?: :odd?, + foo: :bar + ) + end + end + context 'when inherit_mode is set to merge for Exclude' do let(:file_path) { '.rubocop.yml' }