From 85d692e9d1e841f0734cd3d79bcf3c8a31f36c0b Mon Sep 17 00:00:00 2001 From: zzak Date: Wed, 13 Nov 2024 14:46:32 +0900 Subject: [PATCH] Make `deep_merge` a soft-requirement The goal here is to remove deep_merge and rely entirely on ActiveSupport's `Hash#deep_merge` implementation. This does mean that if you want to keep the existing behavior, or rely on DeepMerge's specific options, you need to add the following to your Gemfile: ```ruby gem 'deep_merge', '~> 1.2', '>= 1.2.1' ``` --- config.gemspec | 1 - gemfiles/sinatra.gemfile | 1 + lib/config.rb | 13 +++++++++++- lib/config/options.rb | 44 ++++++++++++++++++++++++---------------- spec/config_spec.rb | 15 ++++++++++++++ spec/options_spec.rb | 35 ++++++++++++++++++++++++++++++++ 6 files changed, 89 insertions(+), 20 deletions(-) diff --git a/config.gemspec b/config.gemspec index dfb0c2dc..b896fddb 100644 --- a/config.gemspec +++ b/config.gemspec @@ -27,7 +27,6 @@ Gem::Specification.new do |s| s.require_paths = ['lib'] s.required_ruby_version = '>= 2.6.0' - s.add_dependency 'deep_merge', '~> 1.2', '>= 1.2.1' s.add_dependency 'ostruct' s.add_development_dependency 'dry-validation', *Config::DryValidationRequirements::VERSIONS diff --git a/gemfiles/sinatra.gemfile b/gemfiles/sinatra.gemfile index 11496e63..4aefc588 100644 --- a/gemfiles/sinatra.gemfile +++ b/gemfiles/sinatra.gemfile @@ -3,5 +3,6 @@ source "https://rubygems.org" gem "sinatra", "2.0.8.1" +gem "deep_merge", "~> 1.2", ">= 1.2.1" gemspec path: "../" diff --git a/lib/config.rb b/lib/config.rb index e98d1e70..3c0be394 100644 --- a/lib/config.rb +++ b/lib/config.rb @@ -6,7 +6,18 @@ require 'config/sources/hash_source' require 'config/sources/env_source' require 'config/validation/schema' -require 'deep_merge/core' + +begin + gem 'deep_merge', '~> 1.2', '>= 1.2.1' + require 'deep_merge/core' +rescue LoadError + warn <<~WARNING + The `deep_merge` gem is not available. Trying to use ActiveSupport's Hash#deep_merge instead. + If you want to continue using 'deep_merge' gem, please add it to your Gemfile: + gem 'deep_merge', '~> 1.2', '>= 1.2.1' + WARNING + require 'active_support/core_ext/hash/deep_merge' +end module Config extend Config::Validation::Schema diff --git a/lib/config/options.rb b/lib/config/options.rb index 07944b73..d0a2847d 100644 --- a/lib/config/options.rb +++ b/lib/config/options.rb @@ -40,15 +40,19 @@ def reload! if conf.empty? conf = source_conf else - DeepMerge.deep_merge!( - source_conf, - conf, - preserve_unmergeables: false, - knockout_prefix: Config.knockout_prefix, - overwrite_arrays: Config.overwrite_arrays, - merge_nil_values: Config.merge_nil_values, - merge_hash_arrays: Config.merge_hash_arrays - ) + if defined?(DeepMerge) + DeepMerge.deep_merge!( + source_conf, + conf, + preserve_unmergeables: false, + knockout_prefix: Config.knockout_prefix, + overwrite_arrays: Config.overwrite_arrays, + merge_nil_values: Config.merge_nil_values, + merge_hash_arrays: Config.merge_hash_arrays + ) + else + conf = conf.deep_merge!(source_conf) + end end end @@ -98,15 +102,19 @@ def as_json(options = nil) def merge!(hash) current = to_hash - DeepMerge.deep_merge!( - hash.dup, - current, - preserve_unmergeables: false, - knockout_prefix: Config.knockout_prefix, - overwrite_arrays: Config.overwrite_arrays, - merge_nil_values: Config.merge_nil_values, - merge_hash_arrays: Config.merge_hash_arrays - ) + if defined?(DeepMerge) + DeepMerge.deep_merge!( + hash.dup, + current, + preserve_unmergeables: false, + knockout_prefix: Config.knockout_prefix, + overwrite_arrays: Config.overwrite_arrays, + merge_nil_values: Config.merge_nil_values, + merge_hash_arrays: Config.merge_hash_arrays + ) + else + current.deep_merge!(hash) + end marshal_load(__convert(current).marshal_dump) self end diff --git a/spec/config_spec.rb b/spec/config_spec.rb index 505c6081..ebc61c7c 100644 --- a/spec/config_spec.rb +++ b/spec/config_spec.rb @@ -331,6 +331,11 @@ end it 'should not overwrite values with nil' do + unless defined?(DeepMerge) + skip <<~REASON + DeepMerge is not available in the current context. This test only applies when the `deep_merge` gem is available. + REASON + end old_value = config.inner.something1 config.merge!(hash_with_nil) expect(config.inner.something1).to eq(old_value) @@ -418,6 +423,11 @@ end it 'should remove elements from settings' do + unless defined?(DeepMerge) + skip <<~REASON + DeepMerge is not available in the current context. This test only applies when the `deep_merge` gem is available. + REASON + end expect(config.array1).to eq(['item4', 'item5', 'item6']) expect(config.array2.inner).to eq(['item4', 'item5', 'item6']) expect(config.array3).to eq('') @@ -474,6 +484,11 @@ end it 'should merge arrays from multiple configs' do + unless defined?(DeepMerge) + skip <<~REASON + DeepMerge is not available in the current context. This test only applies when the `deep_merge` gem is available. + REASON + end expect(config.arraylist1.size).to eq(6) expect(config.arraylist2.inner.size).to eq(6) end diff --git a/spec/options_spec.rb b/spec/options_spec.rb index 03f7b94b..f74d9ace 100644 --- a/spec/options_spec.rb +++ b/spec/options_spec.rb @@ -112,6 +112,11 @@ end it 'should overwrite the previous values' do + unless defined?(DeepMerge) + skip <<~REASON + DeepMerge is not available in the current context. This test only applies when the `deep_merge` gem is available. + REASON + end expect(config['tvrage']['service_url']).to eq('http://url2') end @@ -124,6 +129,11 @@ end it 'should overwrite the previous values' do + unless defined?(DeepMerge) + skip <<~REASON + DeepMerge is not available in the current context. This test only applies when the `deep_merge` gem is available. + REASON + end expect(config['tvrage']['service_url']).to eq('http://url3') end end @@ -144,6 +154,11 @@ end it 'should add keys from the added file' do + unless defined?(DeepMerge) + skip <<~REASON + DeepMerge is not available in the current context. This test only applies when the `deep_merge` gem is available. + REASON + end expect(config['tvrage']['service_url']).to eq('http://services.tvrage.com') end @@ -154,6 +169,11 @@ end it 'should overwrite the previous values' do + unless defined?(DeepMerge) + skip <<~REASON + DeepMerge is not available in the current context. This test only applies when the `deep_merge` gem is available. + REASON + end expect(config['tvrage']['service_url']).to eq('http://services.tvrage.com') end end @@ -168,6 +188,11 @@ end it 'should be overwritten by the following values' do + unless defined?(DeepMerge) + skip <<~REASON + DeepMerge is not available in the current context. This test only applies when the `deep_merge` gem is available. + REASON + end expect(config['tvrage']['service_url']).to eq('http://services.tvrage.com') end @@ -246,6 +271,11 @@ } } it 'should merge the arrays' do + unless defined?(DeepMerge) + skip <<~REASON + DeepMerge is not available in the current context. This test only applies when the `deep_merge` gem is available. + REASON + end config = Config.load_files("#{fixture_path}/deep_merge3/config1.yml", "#{fixture_path}/deep_merge3/config2.yml") expect(config.array.length).to eq(1) @@ -261,6 +291,11 @@ } } it 'should merge the arrays' do + unless defined?(DeepMerge) + skip <<~REASON + DeepMerge is not available in the current context. This test only applies when the `deep_merge` gem is available. + REASON + end config = Config.load_files("#{fixture_path}/deep_merge3/config1.yml", "#{fixture_path}/deep_merge3/config2.yml") expect(config.array.length).to eq(2)