lib/attr/gather/aggregators/deep_merge.rb in attr-gather-1.4.0 vs lib/attr/gather/aggregators/deep_merge.rb in attr-gather-1.5.1
- old
+ new
@@ -11,15 +11,22 @@
class DeepMerge < Base
# Initialize a new DeepMerge aggregator
#
# @param reverse [Boolean] deep merge results in reverse order
# @param merge_input [Boolean] merge the result with the initial input
+ # @param array_strategy [Symbol] strategy for handling arrays, one of (:concat, :overwrite)
#
# @api private
- def initialize(reverse: false, merge_input: true, **)
+ def initialize(reverse: false, merge_input: true, array_strategy: :concat, **)
+ unless ARRAY_STRATEGY.include?(array_strategy)
+ raise ArgumentError, 'array_strategy must be one of: :concat, :overwrite'
+ end
+
@reverse = reverse
@merge_input = merge_input
+ @array_strategy = array_strategy
+
super
end
def call(input, execution_results)
execution_results = execution_results.reverse_each if reverse?
@@ -29,21 +36,40 @@
end
end
private
- def reverse?
- @reverse
- end
+ ARRAY_STRATEGY = %i[concat overwrite].freeze
+ private_constant :ARRAY_STRATEGY
+
def deep_merge(hash, other)
- Hash[hash].merge(other) do |_, orig, new|
+ hash.to_h.merge(other) do |_, orig, new|
if orig.respond_to?(:to_hash) && new.respond_to?(:to_hash)
- deep_merge(Hash[orig], Hash[new])
+ deep_merge(orig.to_h, new.to_h)
+ elsif concattable?(orig, new)
+ orig + new
else
new
end
end
+ end
+
+ def concattable?(orig, new)
+ return false unless @array_strategy == :concat
+
+ concattable_class?(orig) && concattable_class?(new)
+ end
+
+ def concattable_class?(obj)
+ return true if obj.is_a?(Array)
+ return true if obj.is_a?(Set)
+
+ false
+ end
+
+ def reverse?
+ @reverse
end
end
end
end
end