Resource-Silo
view release on metacpan or search on metacpan
lib/Resource/Silo/Metadata.pm view on Meta::CPAN
$spec{preload} = [undef]; # a dummy argument so that preload itself has unified code
}
};
if (!defined $spec{argument}) {
$spec{orig_argument} = '';
$spec{argument} = \&_is_empty;
} elsif (ref $spec{argument} eq $REGEXP) {
my $rex = qr(^(?:$spec{argument})$);
$spec{orig_argument} = $spec{argument};
$spec{argument} = sub { $_[0] =~ $rex };
} elsif ((reftype $spec{argument} // '') eq $CODE) {
# do nothing, we're fine
} else {
croak "resource '$name': 'argument' must be a regexp or a function";
}
$spec{cleanup_order} //= 0;
croak "resource '$name': 'cleanup_order' must be a number"
unless looks_like_number($spec{cleanup_order});
croak "resource '$name': 'check' must be a function"
if defined $spec{check} and (reftype $spec{check} // '') ne $CODE;
croak "resource '$name': 'coerce' must be a function"
if defined $spec{coerce} and (reftype $spec{coerce} // '') ne $CODE;
croak "resource '$name': 'cleanup' must be a function"
if defined $spec{cleanup} and (reftype $spec{cleanup} // '') ne $CODE;
croak "resource '$name': 'fork_cleanup' must be a function"
if defined $spec{fork_cleanup} and (reftype $spec{fork_cleanup} // '') ne $CODE;
croak "resource '$name': 'fork_cleanup' and 'fork_safe' are mutually exclusive"
if $spec{fork_cleanup} and $spec{fork_safe};
$spec{fork_cleanup} //= $spec{cleanup};
$spec{origin} = Carp::shortmess("declared");
$spec{origin} =~ s/\D+$//s;
my @forward_deps = grep { !$self->{resource}{$_} || $self->{pending_deps}->contains($_) }
keys %{ $spec{allowdeps} || {} };
if (@forward_deps) {
my $loop = $self->{pending_deps}->find_loop($name, \@forward_deps);
if ($loop) {
my $msg = "resource '$name': circular dependency detected: ".
join " -> ", map { $self->elaborate_name($_) } @$loop;
croak $msg;
}
}
# Move code generation into Resource::Silo::Container
# so that exceptions via croak() are attributed correctly.
{
no strict 'refs'; ## no critic Strictures
*{"${target}::$name"} =
Resource::Silo::Container::_silo_make_accessor($name, \%spec);
}
if (@forward_deps) {
$self->{pending_deps}->add_edges([$name], \@forward_deps);
} else {
# resource is independent, notify dependents if any
$self->{pending_deps}->drop_sink_cascade($name);
};
$self->{resource}{$name} = \%spec;
push @{ $self->{preload} }, $name if $spec{preload};
return $self;
};
sub _make_init_class {
my ($self, $name, $spec) = @_;
my $class = $spec->{class};
$spec->{dependencies} //= {};
croak "resource '$name': 'class' doesn't look like a package name: '$class'"
unless $class =~ $MOD_REX;
defined $spec->{$_} and croak "resource '$name': 'class' is incompatible with '$_'"
for qw(init argument);
croak "resource '$name': 'class' requires 'dependencies' to be a hash"
unless ref $spec->{dependencies} eq 'HASH';
my %deps = %{ $spec->{dependencies} };
push @{ $spec->{require} }, $class;
my %pass_args;
my @realdeps;
my @body = ("my \$c = shift;", "$class->new(" );
# format: constructor_arg => [ resource_name, resource_arg ]
foreach my $key (keys %deps) {
my $entry = $deps{$key};
if (ref $entry eq 'SCALAR') {
# pass a literal value to the constructor
$pass_args{$key} = $$entry;
next;
};
if (defined $entry and !ref $entry) {
# allow bareword, and alias `foo => 1` to `foo => ['foo']
$entry = $key if $entry eq '1';
$entry = [ $entry ];
};
croak "resource '$name': dependency '$key' has wrong format"
unless (
ref $entry eq 'ARRAY'
and @$entry <= 2
and ($entry->[0] // '') =~ $ID_REX
);
push @realdeps, $entry->[0];
push @body, length ($entry->[1] // '')
? sprintf( "\t'%s' => \$c->%s('%s'),",
quotemeta $key, $entry->[0], quotemeta $entry->[1] )
: sprintf( "\t'%s' => \$c->%s,", quotemeta $key, $entry->[0] );
};
push @body, "\t\%pass_args"
if %pass_args;
push @body, ");";
( run in 1.566 second using v1.01-cache-2.11-cpan-13bb782fe5a )