Minions
view release on metacpan or search on metacpan
lib/Minions.pm view on Meta::CPAN
package Minions;
use strict;
use 5.008_005;
use Carp;
use Hash::Util qw( lock_keys );
use List::MoreUtils qw( all );
use Module::Runtime qw( require_module );
use Params::Validate qw(:all);
use Package::Stash;
use Sub::Name;
use Exception::Class (
'Minions::Error::AssertionFailure' => { alias => 'assert_failed' },
'Minions::Error::InterfaceMismatch',
'Minions::Error::MethodDeclaration',
'Minions::Error::RoleConflict',
);
use Minions::_Guts;
our $VERSION = '1.000001';
$VERSION = eval $VERSION;
my $Class_count = 0;
my %Bound_implementation_of;
my %Interface_for;
my %Util_class;
sub import {
my ($class, %arg) = @_;
if ( my $bindings = $arg{bind} ) {
foreach my $class ( keys %$bindings ) {
$Bound_implementation_of{$class} = $bindings->{$class};
}
}
elsif ( my $methods = $arg{declare_interface} ) {
my $caller_pkg = (caller)[0];
$Interface_for{$caller_pkg} = $methods;
}
else {
$class->minionize(\%arg);
}
}
sub minionize {
my (undef, $spec) = @_;
my $cls_stash;
if ( ! $spec->{name} ) {
my $caller_pkg = (caller)[0];
if ( $caller_pkg eq __PACKAGE__ ) {
$caller_pkg = (caller 1)[0];
}
$cls_stash = Package::Stash->new($caller_pkg);
$spec = { %$spec, %{ $cls_stash->get_symbol('%__meta__') || {} } };
$spec->{name} = $caller_pkg;
}
$spec->{name} ||= "Minions::Class_${\ ++$Class_count }";
my @args = %$spec;
validate(@args, {
interface => { type => ARRAYREF | SCALAR },
implementation => { type => SCALAR | HASHREF },
construct_with => { type => HASHREF, optional => 1 },
class_methods => { type => HASHREF, optional => 1 },
build_args => { type => CODEREF, optional => 1 },
name => { type => SCALAR, optional => 1 },
no_attribute_vars => { type => BOOLEAN, optional => 1 },
});
$cls_stash ||= Package::Stash->new($spec->{name});
my $obj_stash;
if ( ! ref $spec->{implementation} ) {
my $pkg = $Bound_implementation_of{ $spec->{name} } || $spec->{implementation};
$pkg ne $spec->{name}
or confess "$spec->{name} cannot be its own implementation.";
my $stash = _get_stash($pkg);
my $meta = $stash->get_symbol('%__meta__');
$spec->{implementation} = {
package => $pkg,
methods => $stash->get_all_symbols('CODE'),
has => {
%{ $meta->{has} || { } },
},
};
$spec->{roles} = $meta->{roles};
$spec->{traitlibs} = $meta->{traitlibs};
my $is_semiprivate = _interface($meta, 'semiprivate');
foreach my $sub ( keys %{ $spec->{implementation}{methods} } ) {
if ( $is_semiprivate->{$sub} ) {
$spec->{implementation}{semiprivate}{$sub} = delete $spec->{implementation}{methods}{$sub};
}
}
}
$obj_stash = Package::Stash->new("$spec->{name}::__Minions");
_prep_interface($spec);
_compose_roles($spec);
_compose_traitlibs($spec);
my $private_stash = Package::Stash->new("$spec->{name}::__Private");
$cls_stash->add_symbol('$__Obj_pkg', $obj_stash->name);
$cls_stash->add_symbol('$__Private_pkg', $private_stash->name);
$cls_stash->add_symbol('%__meta__', $spec) if @_ > 0;
_make_util_class($spec);
( run in 2.513 seconds using v1.01-cache-2.11-cpan-364913b4093 )