DBIO
view release on metacpan or search on metacpan
lib/DBIO/PopulateMore.pm view on Meta::CPAN
package DBIO::PopulateMore;
# ABSTRACT: Enhanced populate with cross-source references
use strict;
use warnings;
use Scalar::Util qw(refaddr weaken);
use namespace::clean;
my $MATCH_CONDITION = qr/^!(\w+:.+)$/;
sub populate_more {
my ($self, $arg, @rest) = @_;
$self->throw_exception("Argument is required.")
unless $arg;
my @args = (ref $arg && ref $arg eq 'ARRAY') ? @$arg : ($arg, @rest);
my @definitions;
while (@args) {
my $next = shift @args;
if (ref $next && ref $next eq 'HASH') {
push @definitions, $next;
} else {
my $value = shift @args;
push @definitions, { $next => $value };
}
}
my %rs_index;
my %seen;
weaken(my $weak_self = $self);
my $visit;
my $dispatch;
# Visitor: recursively walk data structures, inflating !-prefixed values
$visit = sub {
my ($target) = @_;
if (ref $target eq 'ARRAY') {
my $addr = refaddr $target;
return $seen{$addr} if defined $seen{$addr};
my $new = $seen{$addr} = [];
@$new = map { $visit->($_) } @$target;
return $new;
} elsif (ref $target eq 'HASH') {
my $addr = refaddr $target;
return $seen{$addr} if defined $seen{$addr};
my $new = $seen{$addr} = {};
%$new = map { $_ => $visit->($target->{$_}) } keys %$target;
return $new;
} elsif (defined $target && $target =~ $MATCH_CONDITION) {
return $dispatch->($1);
} else {
return $target;
}
};
# Dispatcher: route !Name:args to the correct inflator
$dispatch = sub {
my ($arg) = @_;
my ($name, $command) = ($arg =~ /^(\w+):(\S.*)$/);
if ($name eq 'Index') {
return $rs_index{$command}
|| $weak_self->throw_exception("Bad Index in fixture: $command");
} elsif ($name eq 'Env') {
return $ENV{$command}
// $ENV{uc $command}
// $weak_self->throw_exception("No match for $command in \%ENV");
} elsif ($name eq 'Find') {
my ($source, $id) = split(/\./, $command, 2);
my $rs = $weak_self->resultset($source)
or $weak_self->throw_exception("Can't find resultset for $source");
if ($id =~ /^\[(.+)\]$/) {
my %keys = map { split(/=/, $_, 2) } split(/,/, $1);
$id = \%keys;
}
return $rs->find($id)
|| $weak_self->throw_exception("Can't find result for '$id' in '$source'");
} else {
$weak_self->throw_exception("Unknown inflator: $name");
}
};
for my $definition (@definitions) {
my ($source, $info) = %$definition;
my @fields = ref $info->{fields} eq 'ARRAY'
? @{$info->{fields}}
: ($info->{fields});
my $data = $visit->($info->{data});
( run in 0.435 second using v1.01-cache-2.11-cpan-995e09ba956 )