The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Connector::Multi::Merge;

use strict;
use warnings;
use English;
use Config::Merge;
use Data::Dumper;

use Moose;

extends 'Connector::Builtin::Memory';

has '+LOCATION' => ( required => 1 );

sub _build_config {

    my $self = shift;

    # Skip the workflow directories
    my $cm    = Config::Merge->new( $self->LOCATION() );
    my $cmref = $cm->();
    my $tree = $self->cm2tree($cmref);

    return $tree;

}

# Traverse the tree read from Config::Merge and replace the "@" keys by
# scalar references 

sub cm2tree {
    my $self = shift;
    my $cm   = shift;

    if ( ref($cm) eq 'HASH' ) {
        my $ret = {};
        foreach my $key ( keys %{$cm} ) {
            if ( $key =~ m{ (?: \A @ (.*?) @ \z | \A @ (.*) | (.*?) @ \z ) }xms ) {
                my $match = $1 || $2 || $3;
                # make it a ref to an anonymous scalar so we know it's a symlink
                $ret->{$match} = \$cm->{$key};
            } else {
                $ret->{$key} = $self->cm2tree( $cm->{$key} )
            }
        }
        return $ret;
    }
    elsif ( ref($cm) eq 'ARRAY' ) {
        my $ret = [];
        my $i = 0;
        foreach my $entry ( @{$cm} ) {
            $ret->[ $i++ ] = $self->cm2tree($entry);
        }
        return $ret;
    }
    else {
        return $cm;
    }
}

1;

__DATA__


=head1 Name

Connector::Multi::Merge
 
=head1 Description

This is a glue connector to create the required reference syntax for 
Connector::Multi based on a backend configuration handled by Config::Merge.

LOCATION is passed over as path to Config::Merge and must point to the 
root node of the config directory.

Internally, the constructor walks down the whole tree and translates 
all keys starting or ending with the "@" character into references as 
understood by Connector::Multi.

=head1 CONFIGURATION

There is no special configuration besides the mandatory LOCATION property.

=head1 Example

   my $backend = Connector::Multi::Merge->new({
       LOCATION = /etc/myconfigtree/
   })
   
   my $multi = Connector::Multi->new({
       BASECONNECTOR => $backend
   })