Attribute-Storage
view release on metacpan or search on metacpan
lib/Attribute/Storage.pm view on Meta::CPAN
Normally it is an error to attempt to apply the same attribute more than once
to the same target. Sometimes however, it would make sense for an attribute
to be applied many times. If the C<ATTR()> list is given the C<MULTI> flag,
then applying it more than once will be allowed. Each invocation of the
handling code will be given the previous value that was returned, or C<undef>
for the first time. It is up to the code to perform whatever merging logic is
required.
sub Description :ATTR(CODE,MULTI,RAWDATA)
{
my $package = shift;
my ( $olddesc, $more ) = @_;
return defined $olddesc ? "$olddesc$more\n" : "$more\n";
}
sub Argument :ATTR(CODE,MULTI)
{
my $package = shift;
my ( $args, $argname ) = @_;
push @$args, $argname;
return $args;
}
sub Option :ATTR(CODE,MULTI)
{
my $package = shift;
my ( $opts, $optname ) = @_;
$opts and exists $opts->{$optname} and
croak "Already have the $optname option";
$opts->{$optname}++;
return $opts;
}
...
sub do_copy
:Description(Copy from SOURCE to DESTINATION)
:Description(Optionally preserves attributes)
:Argument("SOURCE")
:Argument("DESTINATION")
:Option("attrs")
:Option("verbose")
{
...
}
=cut
sub handle_attr_ATTR
{
my ( $pkg, $ref, undef, $opts ) = @_;
my $attrs = _get_attr_hash( $ref, 1 );
my %type;
foreach ( split m/\s*,\s*/, $opts ) {
m/^(?:CODE|SCALAR|ARRAY|HASH)$/ and
( $type{lc $_} = 1 ), next;
m/^RAWDATA$/ and
( $type{raw} = 1 ), next;
m/^MULTI$/ and
( $type{multi} = 1 ), next;
m/^NAME$/ and
( $type{name} = 1 ), next;
croak "Unrecognised attribute option $_";
}
if( $type{name} ) {
# TODO: maybe this could be made to work but it seems to require a lot
# of hunting around in the symbol table or lexical pad to work out the
# name when given only a reference. Probably not worth it?
$type{lc $_} and croak "Cannot apply NAME to :ATTR($_)" for qw( SCALAR ARRAY HASH );
}
$attrs->{ATTR} = \%type;
return 0;
}
sub handle_attr
{
my ( $pkg, $ref, $attrname, $opts ) = @_;
my $cv = $pkg->can( $attrname ) or return 1;
my $cvattrs = _get_attr_hash( $cv, 0 ) or return 1;
my $type = $cvattrs->{ATTR} or return 1;
my $reftype = ref $ref;
$reftype =~ m/^(?:CODE|SCALAR|ARRAY|HASH)$/ && $type->{lc $reftype} or
croak "Cannot apply :$attrname to $reftype reference";
my @opts;
if( $type->{raw} ) {
@opts = ( $opts );
}
else {
@opts = do {
no strict;
defined $opts ? eval $opts : ();
};
if( $@ ) {
my ( $msg ) = $@ =~ m/^(.*) at \(eval \d+\) line \d+\.$/;
croak "Unable to parse $attrname - $msg";
}
}
my $attrs = _get_attr_hash( $ref, 1 );
if( $type->{name} ) {
unshift @opts, svref_2object( $ref )->GV->NAME;
( run in 0.849 second using v1.01-cache-2.11-cpan-af0e5977854 )