YAMLのマージ

30分プログラム、その220。id:mzp:20080107:collectで作ったYAMLをマージするためのプログラム。
yaml-merge -key=some_key a.yaml b.yamlとすると、a.yamlとb.yamlを併せて出力する。ただし、このときa.yamlとb.yamlに同じエントリが存在した場合は、b.yamlのエントリを優先する。
また、YAMLの内容は、

---
id: foo
body: aaaaa...
---
id: bar
body: bbbbb...

のような連想リストっぽい内容を想定してる。直接ハッシュで書かないのは、YAMLが見づらい気がするので。

これはマージじゃなくてパッチと名付けたほうがよかった気がちょっとしてる。

使い方

$ cat base.yaml
---
category:
  - Python
title: cat -n
url: http://d.hatena.ne.jp/mzp/20080101/cat

$ cat delta.yaml
---
category:
  - Python
title: cat -n
url: http://d.hatena.ne.jp/mzp/20080101/cat
---
category:
  - Python
title: SQLiteをPythonで
url: http://d.hatena.ne.jp/mzp/20080102/sqlite


$ yaml-merge --key=url base.yaml delta.yaml
---
category:
  - Python
title: cat -n
url: http://d.hatena.ne.jp/mzp/20080101/cat
---
category:
  - Python
title: SQLiteをPythonで
url: http://d.hatena.ne.jp/mzp/20080102/sqlite

ソースコード

#! /usr/bin/perl
# -*- mode:perl; coding:utf-8 -*-
#
# yaml-merge.pl -
#
# Copyright(C) 2008 by mzp
# Author: MIZUNO Hiroki / mzpppp at gmail dot com
# http://howdyworld.org
#
# Timestamp: 2008/01/10 14:23:11
#
# This program is free software; you can redistribute it and/or
# modify it under MIT Lincence.
#

use strict;
use warnings;
use Getopt::Long;
use Data::Dumper;
use YAML qw(LoadFile Dump);

# convert assoc array to hash
sub to_hash($@){
  my ($key,@assoc) = @_;
  my %hash;

  for (@assoc) {
    $hash{$_->{$key}} = $_;
  }
  %hash;
}

sub to_array(%){
  my (%hash) = @_;
  map { $hash{$_}} sort keys %hash;
}

my $key;
GetOptions('key|k=s'=>\$key);
$key or die "usage: $0 --key=<key> <base-yaml> <delta-yaml>";

my ($base,$delta) = @ARGV;
my @base  = LoadFile $base;
my @delta = LoadFile $delta;

# if @base and @delta have same key, we select @delta entry.
my %merged = ( to_hash($key,@base), to_hash($key,@delta) );

print Dump(to_array(%merged));