Commit 3299a970 authored by Bob Van Landuyt's avatar Bob Van Landuyt

Handle all cases for merging a hierarchy

The possible cases are:
 - [Array, Array]
 - [Array, Hash]
 - [Array, GroupHierarchy]
 - [Hash,Hash]
 - [Hash, GroupHierarchy]
 - [GroupHierarchy, GroupHierarchy]
parent 3e6dd7d8
...@@ -33,7 +33,7 @@ module GroupHierarchy ...@@ -33,7 +33,7 @@ module GroupHierarchy
hierarchies = Array.wrap(hierarchies) hierarchies = Array.wrap(hierarchies)
return if hierarchies.empty? return if hierarchies.empty?
unless hierarchies.all? { |other_base| other_base.is_a?(GroupHierarchy) } unless hierarchies.all? { |hierarchy| hierarchy.is_a?(GroupHierarchy) }
raise ArgumentError.new('element is not a hierarchy') raise ArgumentError.new('element is not a hierarchy')
end end
...@@ -50,26 +50,46 @@ module GroupHierarchy ...@@ -50,26 +50,46 @@ module GroupHierarchy
def self.merge_values(first_child, second_child) def self.merge_values(first_child, second_child)
# When the first is an array, we need to go over every element to see if # When the first is an array, we need to go over every element to see if
# we can merge deeper. # we can merge deeper. If no match is found, we add the element to the array
if first_child.is_a?(Array) #
first_child.map do |element| # Handled cases:
if element.is_a?(Hash) && element.keys.any? { |k| second_child.keys.include?(k) } # [Array, Hash]
element.deep_merge(second_child) { |key, first, second| merge_values(first, second) } if first_child.is_a?(Array) && second_child.is_a?(Hash)
else merge_hash_into_array(first_child, second_child)
element elsif first_child.is_a?(Hash) && second_child.is_a?(Array)
end merge_hash_into_array(second_child, first_child)
end
# If both of them are hashes, we can deep_merge with the same logic # If both of them are hashes, we can deep_merge with the same logic
#
# Handled cases:
# [Hash, Hash]
elsif first_child.is_a?(Hash) && second_child.is_a?(Hash) elsif first_child.is_a?(Hash) && second_child.is_a?(Hash)
first_child.deep_merge(second_child) { |key, first, second| merge_values(first, second) } first_child.deep_merge(second_child) { |key, first, second| merge_values(first, second) }
# If only one of them is a hash, we can check if the other child is already # If only one of them is a hash, and one of them is a GroupHierachy-object
# included, we don't need to do anything when it is. # we can check if its already in the hash. If so, we don't need to do anything
#
# Handled cases
# [Hash, GroupHierarchy]
elsif first_child.is_a?(Hash) && first_child.keys.include?(second_child) elsif first_child.is_a?(Hash) && first_child.keys.include?(second_child)
first_child first_child
elsif second_child.is_a?(Hash) && second_child.keys.include?(first_child) elsif second_child.is_a?(Hash) && second_child.keys.include?(first_child)
second_child second_child
# If one or both elements are a GroupHierarchy, we wrap create an array
# combining them.
#
# Handled cases:
# [GroupHierarchy, Array], [GroupHierarchy, GroupHierarchy], [Array, Array]
else else
Array.wrap(first_child) + Array.wrap(second_child) Array.wrap(first_child) + Array.wrap(second_child)
end end
end end
def self.merge_hash_into_array(array, new_hash)
if mergeable_index = array.index { |element| element.is_a?(Hash) && (element.keys & new_hash.keys).any? }
array[mergeable_index] = merge_values(array[mergeable_index], new_hash)
else
array << new_hash
end
array
end
end end
...@@ -62,6 +62,17 @@ describe GroupHierarchy, :nested_groups do ...@@ -62,6 +62,17 @@ describe GroupHierarchy, :nested_groups do
expect(described_class.merge_hierarchies(groups, parent)).to eq(expected_hierarchy) expect(described_class.merge_hierarchies(groups, parent)).to eq(expected_hierarchy)
end end
it 'handles building a tree out of order' do
other_subgroup = create(:group, parent: parent)
other_subgroup2 = create(:group, parent: parent)
other_subsub_group = create(:group, parent: other_subgroup)
groups = [subsub_group, other_subgroup2, other_subsub_group]
expected_hierarchy = { parent => [{ subgroup => subsub_group }, other_subgroup2, { other_subgroup => other_subsub_group }] }
expect(described_class.merge_hierarchies(groups)).to eq(expected_hierarchy)
end
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment