[Pkg-puppet-devel] [facter] 173/352: (FACT-237) Implement deep_merge for composing facts
Stig Sandbeck Mathisen
ssm at debian.org
Sun Apr 6 22:21:43 UTC 2014
This is an automated email from the git hooks/post-receive script.
ssm pushed a commit to branch master
in repository facter.
commit 733d2af2abad516df124b7c0cf43eb2124825867
Author: Adrien Thebo <git at somethingsinistral.net>
Date: Mon Jan 6 10:38:09 2014 -0800
(FACT-237) Implement deep_merge for composing facts
---
lib/facter/util/values.rb | 37 +++++++++++++++++++
spec/unit/util/values_spec.rb | 85 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 122 insertions(+)
diff --git a/lib/facter/util/values.rb b/lib/facter/util/values.rb
index d691987..938f6fe 100644
--- a/lib/facter/util/values.rb
+++ b/lib/facter/util/values.rb
@@ -4,6 +4,43 @@ module Facter
module Values
module_function
+ # Perform a deep merge of two nested data structures.
+ #
+ # @param left [Object]
+ # @param right [Object]
+ # @param path [Array<String>] The traversal path followed when merging nested hashes
+ #
+ # @return [Object] The merged data structure.
+ def deep_merge(left, right, path = [], &block)
+ ret = nil
+
+ if left.is_a? Hash and right.is_a? Hash
+ ret = left.merge(right) do |key, left_val, right_val|
+ path.push(key)
+ merged = deep_merge(left_val, right_val, path)
+ path.pop
+ merged
+ end
+ elsif left.is_a? Array and right.is_a? Array
+ ret = left.dup.concat(right)
+ elsif right.nil?
+ ret = left
+ elsif left.nil?
+ ret = right
+ elsif left.nil? and right.nil?
+ ret = nil
+ else
+ msg = "Cannot merge #{left.inspect}:#{left.class} and #{right.inspect}:#{right.class}"
+ if not path.empty?
+ msg << " at root"
+ msg << path.map { |part| "[#{part.inspect}]" }.join
+ end
+ raise ArgumentError, msg
+ end
+
+ ret
+ end
+
def convert(value)
value = value.to_s if value.is_a?(Symbol)
value = value.downcase if value.is_a?(String)
diff --git a/spec/unit/util/values_spec.rb b/spec/unit/util/values_spec.rb
new file mode 100644
index 0000000..570386a
--- /dev/null
+++ b/spec/unit/util/values_spec.rb
@@ -0,0 +1,85 @@
+require 'spec_helper'
+require 'facter/util/values'
+
+describe Facter::Util::Values do
+ describe 'deep_merge' do
+ it "non-destructively concatenates arrays" do
+ first = %w[foo bar]
+ second = %w[baz quux]
+
+ expect(described_class.deep_merge(first, second)).to eq %w[foo bar baz quux]
+ expect(first).to eq %w[foo bar]
+ expect(second).to eq %w[baz quux]
+ end
+
+ it "returns the left value if the right value is nil" do
+ expect(described_class.deep_merge("left", nil)).to eq "left"
+ end
+
+ it "returns the right value if the left value is nil" do
+ expect(described_class.deep_merge(nil, "right")).to eq "right"
+ end
+
+ it "returns nil if both values are nil" do
+ expect(described_class.deep_merge(nil, nil)).to be_nil
+ end
+
+ describe "with hashes" do
+ it "merges when keys do not overlap" do
+
+ first = {:foo => 'bar'}
+ second = {:baz => 'quux'}
+
+ expect(described_class.deep_merge(first, second)).to eq(:foo => 'bar', :baz => 'quux')
+ expect(first).to eq(:foo => 'bar')
+ expect(second).to eq(:baz => 'quux')
+ end
+
+ it "concatenates arrays when both keys are arrays" do
+ first = {:foo => %w[bar]}
+ second = {:foo => %w[baz quux]}
+
+ expect(described_class.deep_merge(first, second)).to eq(:foo => %w[bar baz quux])
+ expect(first).to eq(:foo => %w[bar])
+ expect(second).to eq(:foo => %w[baz quux])
+ end
+
+ it "merges hashes when both keys are hashes" do
+ first = {:foo => {:pb => 'lead', :ag => 'silver'}}
+ second = {:foo => {:au => 'gold', :na => 'sodium'}}
+
+ expect(described_class.deep_merge(first, second)).to eq(
+ :foo => {
+ :pb => 'lead',
+ :ag => 'silver',
+ :au => 'gold',
+ :na => 'sodium'
+ }
+ )
+ end
+
+ it "prints the data structure path if an error is raised" do
+ first = {:foo => {:bar => {:baz => {:quux => true}}}}
+ second = {:foo => {:bar => {:baz => {:quux => false}}}}
+
+ expect {
+ described_class.deep_merge(first, second)
+ }.to raise_error(ArgumentError, /Cannot merge .*at .*foo.*bar.*baz.*quux/)
+ end
+ end
+
+ describe "with unmergable scalar values" do
+ [
+ [true, false],
+ [1, 2],
+ ['up', 'down']
+ ].each do |(left, right)|
+ it "raises an error when merging #{left}:#{left.class} and #{right}:#{right.class}" do
+ expect {
+ described_class.deep_merge(left, right)
+ }.to raise_error(ArgumentError, /Cannot merge #{left.inspect}:#{left.class} and #{right.inspect}:#{right.class}/)
+ end
+ end
+ end
+ end
+end
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-puppet/facter.git
More information about the Pkg-puppet-devel
mailing list