Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace deep_merge gem with own implementation #81

Merged
merged 5 commits into from Jan 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 0 additions & 1 deletion k8s-client.gemspec
Expand Up @@ -25,7 +25,6 @@ Gem::Specification.new do |spec|

spec.add_runtime_dependency "excon", "~> 0.62.0"
spec.add_runtime_dependency "dry-struct", "~> 0.5.0"
spec.add_runtime_dependency "deep_merge", "~> 1.2.1"
spec.add_runtime_dependency "recursive-open-struct", "~> 1.1.0"
spec.add_runtime_dependency 'hashdiff', '~> 0.3.7'
spec.add_runtime_dependency 'jsonpath', '~> 0.9.5'
Expand Down
5 changes: 2 additions & 3 deletions lib/k8s/client.rb
Expand Up @@ -4,19 +4,18 @@
require 'base64'
require 'yajl'

require 'k8s/util'

require 'k8s/api/metav1'
require 'k8s/api/version'

require 'k8s/config'
require 'k8s/logging'

require 'k8s/api_client'
require "k8s/error"
require 'k8s/resource'
require 'k8s/resource_client'
require 'k8s/stack'
require 'k8s/transport'
require 'k8s/util'

module K8s
# @param server [String] http/s URL
Expand Down
2 changes: 1 addition & 1 deletion lib/k8s/resource.rb
@@ -1,6 +1,5 @@
# frozen_string_literal: true

require 'deep_merge'
require 'recursive-open-struct'
require 'hashdiff'
require 'forwardable'
Expand All @@ -13,6 +12,7 @@ class Resource < RecursiveOpenStruct
include Comparable

using YAMLSafeLoadStream
using K8s::Util::HashDeepMerge

# @param data [String]
# @return [self]
Expand Down
52 changes: 52 additions & 0 deletions lib/k8s/util.rb
Expand Up @@ -3,6 +3,58 @@
module K8s
# Miscellaneous helpers
module Util
module HashDeepMerge
refine Hash do
# @param other [Hash]
# @param overwrite_arrays [Boolean] when encountering an array, replace the array with the new array
# @param union_arrays [Boolean] when encountering an array, use Array#union to combine with the existing array
# @param keep_existing [Boolean] prefer old value over new value
# @param merge_nil_values [Boolean] overwrite an existing value with a nil value
# @param merge_non_hash [Boolean] calls .merge on objects that respond to .merge
def deep_merge(other, overwrite_arrays: true, union_arrays: false, keep_existing: false, merge_nil_values: false, merge_non_hash: false)
merge(other) do |key, old_value, new_value|
case old_value
when Hash
raise "#{key} : #{new_value.class.name} can not be merged into a Hash" unless new_value.is_a?(Hash)

old_value.deep_merge(
new_value,
overwrite_arrays: overwrite_arrays,
union_arrays: union_arrays,
keep_existing: keep_existing,
merge_nil_values: merge_nil_values,
merge_non_hash: merge_non_hash
)
when Array
if overwrite_arrays
new_value
elsif union_arrays
raise "#{key} : #{new_value.class.name} can not be merged into an Array" unless new_value.is_a?(Array)

old_value | new_value
else
old_value + new_value
end
else
if keep_existing
old_value
elsif new_value.nil? && merge_nil_values
nil
elsif merge_non_hash && old_value.respond_to?(:merge)
old_value.merge(new_value)
else
new_value.nil? ? old_value : new_value
end
end
end
end

def deep_merge!(other, **options)
replace(deep_merge(other, **options))
end
end
end

PATH_TR_MAP = { '~' => '~0', '/' => '~1' }.freeze
PATH_REGEX = %r{(/|~(?!1))}.freeze

Expand Down
102 changes: 102 additions & 0 deletions spec/k8s/util_spec.rb
@@ -1,4 +1,106 @@
RSpec.describe K8s::Util do
describe K8s::Util::HashDeepMerge do
using K8s::Util::HashDeepMerge

it 'deep merges hashes inside hashes' do
expect(
{ 'foo' => { 'bar' => { 'baz' => 'dog' } } }.deep_merge(
{ 'foo' => { 'bar' => { 'buzz' => 'aldrin' } } }
)
).to eq(
{ 'foo' => { 'bar' => { 'baz' => 'dog', 'buzz' => 'aldrin' } } }
)
end

describe 'overwrite_arrays: true' do
it 'replaces arrays with new arrays' do
expect(
{ 'foo' => { 'bar' => [ 'baz' ] } }.deep_merge(
{ 'foo' => { 'bar' => [ 'dog' ] } }, overwrite_arrays: true
)
).to eq(
{ 'foo' => { 'bar' => [ 'dog' ] } }
)
end
end

describe 'overwrite_arrays: false, union_arrays: true' do
it 'creates array union with new array' do
expect(
{ 'foo' => { 'bar' => [ 'baz', 'cat' ] } }.deep_merge(
{ 'foo' => { 'bar' => [ 'dog', 'baz' ] } }, overwrite_arrays: false, union_arrays: true
)
).to eq(
{ 'foo' => { 'bar' => [ 'baz', 'cat', 'dog' ] } }
)
end
end

describe 'overwrite_arrays: false, union_arrays: false' do
it 'combines arrays' do
expect(
{ 'foo' => { 'bar' => [ 'baz' ] } }.deep_merge(
{ 'foo' => { 'bar' => [ 'dog', 'baz' ] } }, overwrite_arrays: false, union_arrays: false
)
).to eq(
{ 'foo' => { 'bar' => [ 'baz', 'dog', 'baz' ] } }
)
end
end

describe 'keep_existing:' do
context 'true' do
it 'keeps existing values' do
expect(
{ 'foo' => { 'bar' => 'baz' } }.deep_merge(
{ 'foo' => { 'bar' => 'dog' } }, keep_existing: true
)
).to eq(
{ 'foo' => { 'bar' => 'baz' } }
)
end
end

context 'false' do
it 'replaces existing values' do
expect(
{ 'foo' => { 'bar' => 'baz' } }.deep_merge(
{ 'foo' => { 'bar' => 'dog' } }, keep_existing: false
)
).to eq(
{ 'foo' => { 'bar' => 'dog' } }
)
end
end
end

describe 'merge_nil_values' do
context 'false' do
it 'does not replace existing values with nils' do
expect(
{ 'foo' => { 'bar' => 'baz' } }.deep_merge(
{ 'foo' => { 'bar' => nil } }, merge_nil_values: false
)
).to eq(
{ 'foo' => { 'bar' => 'baz' } }
)
end
end

context 'true' do
it 'replaces existing values with nils' do
expect(
{ 'foo' => { 'bar' => 'baz' } }.deep_merge(
{ 'foo' => { 'bar' => nil } }, merge_nil_values: true
)
).to eq(
{ 'foo' => { 'bar' => nil } }
)
end
end
end
end

describe '#compact_map' do
it "returns an empty array for an empty array" do
expect(described_class.compact_map([]) { |args| args.map(&:to_s) }).to eq []
Expand Down