aboutsummaryrefslogtreecommitdiff
path: root/lib/Hash/Merge.pm6
blob: 8f41c07917ba4dcd18497beb4763a353e7885207 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#! /usr/bin/env false

use v6.d;

unit module Hash::Merge;

#| Merge any number of Hashes together.
sub merge-hashes (
	#| Any number of Hashes to merge together.
	*@hashes,

	--> Hash
) is export {
	my %result = @hashes.shift;

	# Nothing to do if we only got 1 argument
	return %result unless @hashes.elems;

	for ^@hashes.elems {
		%result = merge-hash(%result, @hashes.shift);
	}

	%result;
}

#| Merge two hashes together.
sub merge-hash (
	#| The original Hash to merge the second Hash into.
	%first,

	#| The second hash, which will be merged into the first Hash.
	%second,

	#| Boolean to set whether Associative objects should be merged on their
	#| own. When set to False, Associative objects in %second will
	#| overwrite those from %first.
	Bool:D :$deep = True,

	#| Boolean to set whether Positional objects should be appended. When
	#| set to False, Positional objects in %second will overwrite those
	#| from %first.
	Bool:D :$positional-append = True,

	--> Hash
) is export {
	my %result = %first;

	for %second.keys -> $key {
		# If the key doesn't exist yet in %first, it can be inserted without worry.
		if (%first{$key}:!exists) {
			%result{$key} = %second{$key};
			next;
		}

		given (%first{$key}) {
			# Associative objects need to be merged deeply.
			when Associative {
				%result{$key} = $deep
					?? merge-hash(%first{$key}, %second{$key}, :$deep, :$positional-append)
					!! %second{$key}
			}
			# Positional objects can be merged or overwritten depending on $append-array.
			when Positional {
				%result{$key} = $positional-append
					?? (|%first{$key}, |%second{$key})
					!! %second{$key}
			}
			# Anything else will just overwrite.
			default {
				%result{$key} = %second{$key};
			}
		}
	}

	%result;
}

# vim: ft=perl6 ts=4 sw=4 et