Perl でハッシュをマージしたいなと思った。というか Catalyst で config メソッドはどうなっているのか見てみたら、Catalyst::Component の config メソッドで Catalyst::Utils::merge_hashes を呼び出している。merge_hashes($a, $b) としたときに、$a に $b をマージするためにいろいろとごにょごにょしているわけです。そのごにょごにょ(つまり Catalyst::Utils::merge_hashes)を単体で使いたいと思ったけど Catalyst 名前空間のモジュールは依存関係に含めるとちょっと厄介なイメージがあったので、単体で使えるモジュールが CPAN にないか探してみたらありました。
名前からしてズバリな感じです。
使い方は perldoc にあるように次の通り。
use Hash::Merge qw( merge );
my %a = (
'foo' => 1,
'bar' => [ qw( a b e ) ],
'querty' => { 'bob' => 'alice' },
);
my %b = (
'foo' => 2,
'bar' => [ qw(c d) ],
'querty' => { 'ted' => 'margeret' },
);
my %c = %{ merge( \%a, \%b ) };
とすると、デフォルトでは %a から %b に上書きする感じになって結果は次のようになります。
$VAR1 = 'bar';
$VAR2 = [
'a',
'b',
'e',
'c',
'd'
];
$VAR3 = 'querty';
$VAR4 = {
'bob' => 'alice',
'ted' => 'margeret'
};
$VAR5 = 'foo';
$VAR6 = 1;
ARRAYは結合してくれているし、SCALARは上書きしてくれているし、HASHはマージしてくれている。
で merge メソッドの第二引数を第一引数にかぶせたい場合もあるでしょう。そんなときには Hash::Merge::set_behavior メソッドを使います。
先ほどの上記のコードは以下のようになります。
use Hash::Merge qw( merge );
my %a = (
'foo' => 1,
'bar' => [ qw( a b e ) ],
'querty' => { 'bob' => 'alice' },
);
my %b = (
'foo' => 2,
'bar' => [ qw(c d) ],
'querty' => { 'ted' => 'margeret' },
);
Hash::Merge::set_behavior( 'RIGHT_PRECEDENT' );
my %c = %{ merge( \%a, \%b ) };
とすると結果は次の通りです。
$VAR1 = 'bar';
$VAR2 = [
'a',
'b',
'e',
'c',
'd'
];
$VAR3 = 'querty';
$VAR4 = {
'bob' => 'alice',
'ted' => 'margeret'
};
$VAR5 = 'foo';
$VAR6 = 2;
SCALAR である foo が %b の方を採用して 2 になっているのがわかりますね。
merge メソッドの引数の書き方を見れば分かるようにハッシュのリファレンスを渡していますし、merge メソッドの戻り値もハッシュのリファレンスなので次のように書く事もできます。
my $a = {
'foo' => 1,
};
my $b = {
'foo' => 2,
};
my $c = merge( $a, $b );
そうすれば結果は以下のようにになりますね。
$VAR1 = {
'bar' => [
'a',
'b',
'e',
'c',
'd'
],
'querty' => {
'bob' => 'alice',
'ted' => 'margeret'
},
'foo' => 2
};
これはいい。Hash::Mergeを採用してみることに決めました。


