Sub-Multi-Tiny

 view release on metacpan or  search on metacpan

lib/Sub/Multi/Tiny.pm  view on Meta::CPAN

        _hlog { "Making $multi_package attr M" } 2;
        eval(_make_M($multi_package));
        die $@ if $@;
    }

    # Set up $subname() in $multi_package, which will be aliased to the
    # dispatcher.
    if(eval { no strict 'refs'; defined &{"$multi_package\::$subname"} }) {
        die "Cannot redefine $subname in $multi_package";
    } else {
        _hlog { "Making $multi_package\::$subname stub" } 2;
        do { no strict 'refs'; *{"$multi_package\::$subname"} = sub {} };
    }
} #import()

# Parse the argument list to the attribute handler
sub _parse_arglist {
    my ($spec, $funcname) = @_;
    _croak "Need a parameter spec for $funcname" unless $spec;
    _hlog { "Parsing args for $funcname: $spec" } 2;

    return Sub::Multi::Tiny::SigParse::Parse($spec);
} #_parse_arglist

# Create the source for the M attribute handler for a given package
sub _make_M {
    my $multi_package = shift;
    my $P = __PACKAGE__;
    my $code = _line_mark_string
        "package $multi_package;\n";

    # TODO See if making M an :ATTR(..., BEGIN) permits us to remove the
    # requirement to list all the parameters in the `use S::M::T` line

    $code .= _line_mark_string <<'EOT';
use Attribute::Handlers;
use Sub::Multi::Tiny::Util qw(_hlog);
##use Data::Dumper;

sub M :ATTR(CODE,RAWDATA) {
    _hlog { require Data::Dumper;
            'In ', __PACKAGE__, "::M: \n",
            Data::Dumper->Dump([\@_], ['attr_args']) } 2;

    my ($package, $symbol, $referent, $attr, $data, $phase,
        $filename, $linenum) = @_;
    my $funcname = "$package\::" . *{$symbol}{NAME};

    _hlog {     # Code from Attribute::Handlers, license perl_5
        ref($referent),
        $funcname,
        "($referent)", "was just declared",
        "and ascribed the ${attr} attribute",
        "with data ($data)",
        "in phase $phase",
        "in file $filename at line $linenum"
    } 2;
EOT

    # Trap out-of-sequence calls.  Currently you can't create a new multisub
    # via eval at runtime.  TODO use UNITCHECK instead to permit doing so?
    $code .= _line_mark_string <<EOT;
    die 'Dispatchers already created - please file a bug report'
        if $P\::_dispatchers_created();

    my \$multi_def = \$_multisubs{'$multi_package'};
EOT

    # Parse and validate the args
    $code .= _line_mark_string <<EOT;
    my \$hrSig = $P\::_parse_arglist(\$data, \$funcname);
    $P\::_check_and_inflate_sig(\$hrSig, \$multi_def,
        \$funcname, \$package, \$filename, \$linenum);
EOT

    $code .= _line_mark_string <<'EOT';
EOT

    # Save the implementation's info for use when making the dispatcher.
    $code .= _line_mark_string <<'EOT';
    my $info = {
        code => $referent,
        args => $hrSig->{parms},    # TODO remove eventually
        sig => $hrSig,

        # For error messages
        filename => $filename,
        linenum => $linenum,
        candidate_name => $funcname
    };
    push @{$multi_def->{impls}}, $info;

} #M
EOT

    _hlog { "M code:\n$code\n" } 2;
    return $code;
} #_make_M

# Validate a signature and convert text to usable objects
sub _check_and_inflate_sig {
    my ($signature, $multi_def, $funcname, $package, $filename, $linenum) = @_;
    my ($saw_positional, $saw_named);

    my $args = $signature->{parms};
    my $temp;
    foreach (@$args) {

        # Is the argument valid in this package?
        my $name = $_->{name};
        unless($multi_def->{possible_params}->{$name}) {
            die "Argument $name is not listed on the 'use Sub::Multi::Tiny' line (used by $funcname at $filename\:$linenum";
        }

        # Is the argument out of order?
        die "Positional arguments must precede named arguments"
            if $saw_named && !$_->{named};

        # Inflate type constraint, if any
        if($_->{type}) {
            _hlog { In => $package, "evaluating type '$_->{type}'" };



( run in 1.384 second using v1.01-cache-2.11-cpan-39bf76dae61 )