summaryrefslogtreecommitdiff
path: root/Master/tlpkg/tlperl/lib/Attribute/Handlers.pm
diff options
context:
space:
mode:
Diffstat (limited to 'Master/tlpkg/tlperl/lib/Attribute/Handlers.pm')
-rw-r--r--Master/tlpkg/tlperl/lib/Attribute/Handlers.pm501
1 files changed, 252 insertions, 249 deletions
diff --git a/Master/tlpkg/tlperl/lib/Attribute/Handlers.pm b/Master/tlpkg/tlperl/lib/Attribute/Handlers.pm
index b0cb8e21af6..36f6e2e81c9 100644
--- a/Master/tlpkg/tlperl/lib/Attribute/Handlers.pm
+++ b/Master/tlpkg/tlperl/lib/Attribute/Handlers.pm
@@ -4,7 +4,7 @@ use Carp;
use warnings;
use strict;
use vars qw($VERSION $AUTOLOAD);
-$VERSION = '0.89'; # remember to update version in POD!
+$VERSION = '0.93'; # remember to update version in POD!
# $DB::single=1;
my %symcache;
@@ -266,68 +266,68 @@ Attribute::Handlers - Simpler definition of attribute handlers
=head1 VERSION
-This document describes version 0.89 of Attribute::Handlers,
-released April 5, 2010.
+This document describes version 0.93 of Attribute::Handlers,
+released July 20, 2011.
=head1 SYNOPSIS
- package MyClass;
- require 5.006;
- use Attribute::Handlers;
- no warnings 'redefine';
+ package MyClass;
+ require 5.006;
+ use Attribute::Handlers;
+ no warnings 'redefine';
- sub Good : ATTR(SCALAR) {
- my ($package, $symbol, $referent, $attr, $data) = @_;
+ sub Good : ATTR(SCALAR) {
+ my ($package, $symbol, $referent, $attr, $data) = @_;
- # Invoked for any scalar variable with a :Good attribute,
- # provided the variable was declared in MyClass (or
- # a derived class) or typed to MyClass.
+ # Invoked for any scalar variable with a :Good attribute,
+ # provided the variable was declared in MyClass (or
+ # a derived class) or typed to MyClass.
- # Do whatever to $referent here (executed in CHECK phase).
- ...
- }
+ # Do whatever to $referent here (executed in CHECK phase).
+ ...
+ }
- sub Bad : ATTR(SCALAR) {
- # Invoked for any scalar variable with a :Bad attribute,
- # provided the variable was declared in MyClass (or
- # a derived class) or typed to MyClass.
- ...
- }
+ sub Bad : ATTR(SCALAR) {
+ # Invoked for any scalar variable with a :Bad attribute,
+ # provided the variable was declared in MyClass (or
+ # a derived class) or typed to MyClass.
+ ...
+ }
- sub Good : ATTR(ARRAY) {
- # Invoked for any array variable with a :Good attribute,
- # provided the variable was declared in MyClass (or
- # a derived class) or typed to MyClass.
- ...
- }
+ sub Good : ATTR(ARRAY) {
+ # Invoked for any array variable with a :Good attribute,
+ # provided the variable was declared in MyClass (or
+ # a derived class) or typed to MyClass.
+ ...
+ }
- sub Good : ATTR(HASH) {
- # Invoked for any hash variable with a :Good attribute,
- # provided the variable was declared in MyClass (or
- # a derived class) or typed to MyClass.
- ...
- }
+ sub Good : ATTR(HASH) {
+ # Invoked for any hash variable with a :Good attribute,
+ # provided the variable was declared in MyClass (or
+ # a derived class) or typed to MyClass.
+ ...
+ }
- sub Ugly : ATTR(CODE) {
- # Invoked for any subroutine declared in MyClass (or a
- # derived class) with an :Ugly attribute.
- ...
- }
+ sub Ugly : ATTR(CODE) {
+ # Invoked for any subroutine declared in MyClass (or a
+ # derived class) with an :Ugly attribute.
+ ...
+ }
- sub Omni : ATTR {
- # Invoked for any scalar, array, hash, or subroutine
- # with an :Omni attribute, provided the variable or
- # subroutine was declared in MyClass (or a derived class)
- # or the variable was typed to MyClass.
- # Use ref($_[2]) to determine what kind of referent it was.
- ...
- }
+ sub Omni : ATTR {
+ # Invoked for any scalar, array, hash, or subroutine
+ # with an :Omni attribute, provided the variable or
+ # subroutine was declared in MyClass (or a derived class)
+ # or the variable was typed to MyClass.
+ # Use ref($_[2]) to determine what kind of referent it was.
+ ...
+ }
- use Attribute::Handlers autotie => { Cycle => Tie::Cycle };
+ use Attribute::Handlers autotie => { Cycle => Tie::Cycle };
- my $next : Cycle(['A'..'Z']);
+ my $next : Cycle(['A'..'Z']);
=head1 DESCRIPTION
@@ -349,7 +349,8 @@ attribute C<:ATTR>. For example:
use Attribute::Handlers;
sub Loud :ATTR {
- my ($package, $symbol, $referent, $attr, $data, $phase, $filename, $linenum) = @_;
+ my ($package, $symbol, $referent, $attr, $data, $phase,
+ $filename, $linenum) = @_;
print STDERR
ref($referent), " ",
*{$symbol}{NAME}, " ",
@@ -364,9 +365,9 @@ This creates a handler for the attribute C<:Loud> in the class LoudDecl.
Thereafter, any subroutine declared with a C<:Loud> attribute in the class
LoudDecl:
- package LoudDecl;
-
- sub foo: Loud {...}
+ package LoudDecl;
+
+ sub foo: Loud {...}
causes the above handler to be invoked, and passed:
@@ -409,11 +410,11 @@ the line number in this file.
Likewise, declaring any variables with the C<:Loud> attribute within the
package:
- package LoudDecl;
+ package LoudDecl;
- my $foo :Loud;
- my @foo :Loud;
- my %foo :Loud;
+ my $foo :Loud;
+ my @foo :Loud;
+ my %foo :Loud;
will cause the handler to be called with a similar argument list (except,
of course, that C<$_[2]> will be a reference to the variable).
@@ -436,7 +437,7 @@ then a reference to an array containing the string
C<"turn it up to 11, man!"> would be passed as the last argument.
Attribute::Handlers makes strenuous efforts to convert
-the data argument (C<$_[4]>) to a useable form before passing it to
+the data argument (C<$_[4]>) to a usable form before passing it to
the handler (but see L<"Non-interpretive attribute handlers">).
If those efforts succeed, the interpreted data is passed in an array
reference; if they fail, the raw data is passed as a string.
@@ -444,7 +445,7 @@ For example, all of these:
sub foo :Loud(till=>ears=>are=>bleeding) {...}
sub foo :Loud(qw/till ears are bleeding/) {...}
- sub foo :Loud(qw/my, ears, are, bleeding/) {...}
+ sub foo :Loud(qw/till, ears, are, bleeding/) {...}
sub foo :Loud(till,ears,are,bleeding) {...}
causes it to pass C<['till','ears','are','bleeding']> as the handler's
@@ -474,11 +475,11 @@ Regardless of the package in which it is declared, if a lexical variable is
ascribed an attribute, the handler that is invoked is the one belonging to
the package to which it is typed. For example, the following declarations:
- package OtherClass;
+ package OtherClass;
- my LoudDecl $loudobj : Loud;
- my LoudDecl @loudobjs : Loud;
- my LoudDecl %loudobjex : Loud;
+ my LoudDecl $loudobj : Loud;
+ my LoudDecl @loudobjs : Loud;
+ my LoudDecl %loudobjex : Loud;
causes the LoudDecl::Loud handler to be invoked (even if OtherClass also
defines a handler for C<:Loud> attributes).
@@ -491,40 +492,40 @@ given the name of a built-in type (C<SCALAR>, C<ARRAY>, C<HASH>, or C<CODE>),
the handler is only applied to declarations of that type. For example,
the following definition:
- package LoudDecl;
+ package LoudDecl;
- sub RealLoud :ATTR(SCALAR) { print "Yeeeeow!" }
+ sub RealLoud :ATTR(SCALAR) { print "Yeeeeow!" }
creates an attribute handler that applies only to scalars:
- package Painful;
- use base LoudDecl;
+ package Painful;
+ use base LoudDecl;
- my $metal : RealLoud; # invokes &LoudDecl::RealLoud
- my @metal : RealLoud; # error: unknown attribute
- my %metal : RealLoud; # error: unknown attribute
- sub metal : RealLoud {...} # error: unknown attribute
+ my $metal : RealLoud; # invokes &LoudDecl::RealLoud
+ my @metal : RealLoud; # error: unknown attribute
+ my %metal : RealLoud; # error: unknown attribute
+ sub metal : RealLoud {...} # error: unknown attribute
You can, of course, declare separate handlers for these types as well
(but you'll need to specify C<no warnings 'redefine'> to do it quietly):
- package LoudDecl;
- use Attribute::Handlers;
- no warnings 'redefine';
+ package LoudDecl;
+ use Attribute::Handlers;
+ no warnings 'redefine';
- sub RealLoud :ATTR(SCALAR) { print "Yeeeeow!" }
- sub RealLoud :ATTR(ARRAY) { print "Urrrrrrrrrr!" }
- sub RealLoud :ATTR(HASH) { print "Arrrrrgggghhhhhh!" }
- sub RealLoud :ATTR(CODE) { croak "Real loud sub torpedoed" }
+ sub RealLoud :ATTR(SCALAR) { print "Yeeeeow!" }
+ sub RealLoud :ATTR(ARRAY) { print "Urrrrrrrrrr!" }
+ sub RealLoud :ATTR(HASH) { print "Arrrrrgggghhhhhh!" }
+ sub RealLoud :ATTR(CODE) { croak "Real loud sub torpedoed" }
You can also explicitly indicate that a single handler is meant to be
used for all types of referents like so:
- package LoudDecl;
- use Attribute::Handlers;
+ package LoudDecl;
+ use Attribute::Handlers;
- sub SeriousLoud :ATTR(ANY) { warn "Hearing loss imminent" }
+ sub SeriousLoud :ATTR(ANY) { warn "Hearing loss imminent" }
(I.e. C<ATTR(ANY)> is a synonym for C<:ATTR>).
@@ -532,20 +533,20 @@ used for all types of referents like so:
=head2 Non-interpretive attribute handlers
Occasionally the strenuous efforts Attribute::Handlers makes to convert
-the data argument (C<$_[4]>) to a useable form before passing it to
+the data argument (C<$_[4]>) to a usable form before passing it to
the handler get in the way.
You can turn off that eagerness-to-help by declaring
an attribute handler with the keyword C<RAWDATA>. For example:
- sub Raw : ATTR(RAWDATA) {...}
- sub Nekkid : ATTR(SCALAR,RAWDATA) {...}
- sub Au::Naturale : ATTR(RAWDATA,ANY) {...}
+ sub Raw : ATTR(RAWDATA) {...}
+ sub Nekkid : ATTR(SCALAR,RAWDATA) {...}
+ sub Au::Naturale : ATTR(RAWDATA,ANY) {...}
Then the handler makes absolutely no attempt to interpret the data it
receives and simply passes it as a string:
- my $power : Raw(1..100); # handlers receives "1..100"
+ my $power : Raw(1..100); # handlers receives "1..100"
=head2 Phase-specific attribute handlers
@@ -559,11 +560,11 @@ other points in the program's compilation or execution, by explicitly
stating the phase (or phases) in which you wish the attribute handler to
be called. For example:
- sub Early :ATTR(SCALAR,BEGIN) {...}
- sub Normal :ATTR(SCALAR,CHECK) {...}
- sub Late :ATTR(SCALAR,INIT) {...}
- sub Final :ATTR(SCALAR,END) {...}
- sub Bookends :ATTR(SCALAR,BEGIN,END) {...}
+ sub Early :ATTR(SCALAR,BEGIN) {...}
+ sub Normal :ATTR(SCALAR,CHECK) {...}
+ sub Late :ATTR(SCALAR,INIT) {...}
+ sub Final :ATTR(SCALAR,END) {...}
+ sub Bookends :ATTR(SCALAR,BEGIN,END) {...}
As the last example indicates, a handler may be set up to be (re)called in
two or more phases. The phase name is passed as the handler's final argument.
@@ -578,24 +579,24 @@ subsequently defined C<BEGIN> blocks are executed).
Attributes make an excellent and intuitive interface through which to tie
variables. For example:
- use Attribute::Handlers;
- use Tie::Cycle;
-
- sub UNIVERSAL::Cycle : ATTR(SCALAR) {
- my ($package, $symbol, $referent, $attr, $data, $phase) = @_;
- $data = [ $data ] unless ref $data eq 'ARRAY';
- tie $$referent, 'Tie::Cycle', $data;
- }
-
- # and thereafter...
-
- package main;
+ use Attribute::Handlers;
+ use Tie::Cycle;
+
+ sub UNIVERSAL::Cycle : ATTR(SCALAR) {
+ my ($package, $symbol, $referent, $attr, $data, $phase) = @_;
+ $data = [ $data ] unless ref $data eq 'ARRAY';
+ tie $$referent, 'Tie::Cycle', $data;
+ }
- my $next : Cycle('A'..'Z'); # $next is now a tied variable
+ # and thereafter...
- while (<>) {
- print $next;
- }
+ package main;
+
+ my $next : Cycle('A'..'Z'); # $next is now a tied variable
+
+ while (<>) {
+ print $next;
+ }
Note that, because the C<Cycle> attribute receives its arguments in the
C<$data> variable, if the attribute is given a list of arguments, C<$data>
@@ -604,16 +605,16 @@ single argument directly. Since Tie::Cycle requires its cycling values to
be passed as an array reference, this means that we need to wrap
non-array-reference arguments in an array constructor:
- $data = [ $data ] unless ref $data eq 'ARRAY';
+ $data = [ $data ] unless ref $data eq 'ARRAY';
Typically, however, things are the other way around: the tieable class expects
its arguments as a flattened list, so the attribute looks like:
- sub UNIVERSAL::Cycle : ATTR(SCALAR) {
- my ($package, $symbol, $referent, $attr, $data, $phase) = @_;
- my @data = ref $data eq 'ARRAY' ? @$data : $data;
- tie $$referent, 'Tie::Whatever', @data;
- }
+ sub UNIVERSAL::Cycle : ATTR(SCALAR) {
+ my ($package, $symbol, $referent, $attr, $data, $phase) = @_;
+ my @data = ref $data eq 'ARRAY' ? @$data : $data;
+ tie $$referent, 'Tie::Whatever', @data;
+ }
This software pattern is so widely applicable that Attribute::Handlers
@@ -621,16 +622,17 @@ provides a way to automate it: specifying C<'autotie'> in the
C<use Attribute::Handlers> statement. So, the cycling example,
could also be written:
- use Attribute::Handlers autotie => { Cycle => 'Tie::Cycle' };
+ use Attribute::Handlers autotie => { Cycle => 'Tie::Cycle' };
- # and thereafter...
+ # and thereafter...
- package main;
+ package main;
- my $next : Cycle(['A'..'Z']); # $next is now a tied variable
+ my $next : Cycle(['A'..'Z']); # $next is now a tied variable
- while (<>) {
- print $next;
+ while (<>) {
+ print $next;
+ }
Note that we now have to pass the cycling values as an array reference,
since the C<autotie> mechanism passes C<tie> a list of arguments as a list
@@ -646,28 +648,29 @@ Attribute::Handlers takes care of that automagically. You can even pass
arguments to the module's C<import> subroutine, by appending them to the
class name. For example:
- use Attribute::Handlers
- autotie => { Dir => 'Tie::Dir qw(DIR_UNLINK)' };
+ use Attribute::Handlers
+ autotie => { Dir => 'Tie::Dir qw(DIR_UNLINK)' };
If the attribute name is unqualified, the attribute is installed in the
current package. Otherwise it is installed in the qualifier's package:
- package Here;
-
- use Attribute::Handlers autotie => {
- Other::Good => Tie::SecureHash, # tie attr installed in Other::
- Bad => Tie::Taxes, # tie attr installed in Here::
- UNIVERSAL::Ugly => Software::Patent # tie attr installed everywhere
- };
+ package Here;
+
+ use Attribute::Handlers autotie => {
+ Other::Good => Tie::SecureHash, # tie attr installed in Other::
+ Bad => Tie::Taxes, # tie attr installed in Here::
+ UNIVERSAL::Ugly => Software::Patent # tie attr installed everywhere
+ };
Autoties are most commonly used in the module to which they actually tie,
and need to export their attributes to any module that calls them. To
facilitate this, Attribute::Handlers recognizes a special "pseudo-class" --
C<__CALLER__>, which may be specified as the qualifier of an attribute:
- package Tie::Me::Kangaroo:Down::Sport;
-
- use Attribute::Handlers autotie => { '__CALLER__::Roo' => __PACKAGE__ };
+ package Tie::Me::Kangaroo:Down::Sport;
+
+ use Attribute::Handlers autotie =>
+ { '__CALLER__::Roo' => __PACKAGE__ };
This causes Attribute::Handlers to define the C<Roo> attribute in the package
that imports the Tie::Me::Kangaroo:Down::Sport module.
@@ -682,166 +685,166 @@ to the TIESCALAR, TIEHASH, etc. that ties it.
The C<autotie> mechanism supports this too. The following code:
- use Attribute::Handlers autotieref => { Selfish => Tie::Selfish };
- my $var : Selfish(@args);
+ use Attribute::Handlers autotieref => { Selfish => Tie::Selfish };
+ my $var : Selfish(@args);
has the same effect as:
- tie my $var, 'Tie::Selfish', @args;
+ tie my $var, 'Tie::Selfish', @args;
But when C<"autotieref"> is used instead of C<"autotie">:
- use Attribute::Handlers autotieref => { Selfish => Tie::Selfish };
- my $var : Selfish(@args);
+ use Attribute::Handlers autotieref => { Selfish => Tie::Selfish };
+ my $var : Selfish(@args);
the effect is to pass the C<tie> call an extra reference to the variable
being tied:
- tie my $var, 'Tie::Selfish', \$var, @args;
+ tie my $var, 'Tie::Selfish', \$var, @args;
=head1 EXAMPLES
-If the class shown in L<SYNOPSIS> were placed in the MyClass.pm
+If the class shown in L</SYNOPSIS> were placed in the MyClass.pm
module, then the following code:
- package main;
- use MyClass;
+ package main;
+ use MyClass;
- my MyClass $slr :Good :Bad(1**1-1) :Omni(-vorous);
+ my MyClass $slr :Good :Bad(1**1-1) :Omni(-vorous);
- package SomeOtherClass;
- use base MyClass;
+ package SomeOtherClass;
+ use base MyClass;
- sub tent { 'acle' }
+ sub tent { 'acle' }
- sub fn :Ugly(sister) :Omni('po',tent()) {...}
- my @arr :Good :Omni(s/cie/nt/);
- my %hsh :Good(q/bye/) :Omni(q/bus/);
+ sub fn :Ugly(sister) :Omni('po',tent()) {...}
+ my @arr :Good :Omni(s/cie/nt/);
+ my %hsh :Good(q/bye/) :Omni(q/bus/);
would cause the following handlers to be invoked:
- # my MyClass $slr :Good :Bad(1**1-1) :Omni(-vorous);
-
- MyClass::Good:ATTR(SCALAR)( 'MyClass', # class
- 'LEXICAL', # no typeglob
- \$slr, # referent
- 'Good', # attr name
- undef # no attr data
- 'CHECK', # compiler phase
- );
-
- MyClass::Bad:ATTR(SCALAR)( 'MyClass', # class
- 'LEXICAL', # no typeglob
- \$slr, # referent
- 'Bad', # attr name
- 0 # eval'd attr data
- 'CHECK', # compiler phase
- );
-
- MyClass::Omni:ATTR(SCALAR)( 'MyClass', # class
- 'LEXICAL', # no typeglob
- \$slr, # referent
- 'Omni', # attr name
- '-vorous' # eval'd attr data
- 'CHECK', # compiler phase
- );
-
-
- # sub fn :Ugly(sister) :Omni('po',tent()) {...}
-
- MyClass::UGLY:ATTR(CODE)( 'SomeOtherClass', # class
- \*SomeOtherClass::fn, # typeglob
- \&SomeOtherClass::fn, # referent
- 'Ugly', # attr name
- 'sister' # eval'd attr data
- 'CHECK', # compiler phase
- );
-
- MyClass::Omni:ATTR(CODE)( 'SomeOtherClass', # class
- \*SomeOtherClass::fn, # typeglob
- \&SomeOtherClass::fn, # referent
- 'Omni', # attr name
- ['po','acle'] # eval'd attr data
- 'CHECK', # compiler phase
- );
-
-
- # my @arr :Good :Omni(s/cie/nt/);
-
- MyClass::Good:ATTR(ARRAY)( 'SomeOtherClass', # class
- 'LEXICAL', # no typeglob
- \@arr, # referent
- 'Good', # attr name
- undef # no attr data
- 'CHECK', # compiler phase
- );
-
- MyClass::Omni:ATTR(ARRAY)( 'SomeOtherClass', # class
- 'LEXICAL', # no typeglob
- \@arr, # referent
- 'Omni', # attr name
- "" # eval'd attr data
- 'CHECK', # compiler phase
- );
-
-
- # my %hsh :Good(q/bye) :Omni(q/bus/);
-
- MyClass::Good:ATTR(HASH)( 'SomeOtherClass', # class
- 'LEXICAL', # no typeglob
- \%hsh, # referent
- 'Good', # attr name
- 'q/bye' # raw attr data
- 'CHECK', # compiler phase
- );
-
- MyClass::Omni:ATTR(HASH)( 'SomeOtherClass', # class
- 'LEXICAL', # no typeglob
- \%hsh, # referent
- 'Omni', # attr name
- 'bus' # eval'd attr data
- 'CHECK', # compiler phase
- );
+ # my MyClass $slr :Good :Bad(1**1-1) :Omni(-vorous);
+
+ MyClass::Good:ATTR(SCALAR)( 'MyClass', # class
+ 'LEXICAL', # no typeglob
+ \$slr, # referent
+ 'Good', # attr name
+ undef # no attr data
+ 'CHECK', # compiler phase
+ );
+
+ MyClass::Bad:ATTR(SCALAR)( 'MyClass', # class
+ 'LEXICAL', # no typeglob
+ \$slr, # referent
+ 'Bad', # attr name
+ 0 # eval'd attr data
+ 'CHECK', # compiler phase
+ );
+
+ MyClass::Omni:ATTR(SCALAR)( 'MyClass', # class
+ 'LEXICAL', # no typeglob
+ \$slr, # referent
+ 'Omni', # attr name
+ '-vorous' # eval'd attr data
+ 'CHECK', # compiler phase
+ );
+
+
+ # sub fn :Ugly(sister) :Omni('po',tent()) {...}
+
+ MyClass::UGLY:ATTR(CODE)( 'SomeOtherClass', # class
+ \*SomeOtherClass::fn, # typeglob
+ \&SomeOtherClass::fn, # referent
+ 'Ugly', # attr name
+ 'sister' # eval'd attr data
+ 'CHECK', # compiler phase
+ );
+
+ MyClass::Omni:ATTR(CODE)( 'SomeOtherClass', # class
+ \*SomeOtherClass::fn, # typeglob
+ \&SomeOtherClass::fn, # referent
+ 'Omni', # attr name
+ ['po','acle'] # eval'd attr data
+ 'CHECK', # compiler phase
+ );
+
+
+ # my @arr :Good :Omni(s/cie/nt/);
+
+ MyClass::Good:ATTR(ARRAY)( 'SomeOtherClass', # class
+ 'LEXICAL', # no typeglob
+ \@arr, # referent
+ 'Good', # attr name
+ undef # no attr data
+ 'CHECK', # compiler phase
+ );
+
+ MyClass::Omni:ATTR(ARRAY)( 'SomeOtherClass', # class
+ 'LEXICAL', # no typeglob
+ \@arr, # referent
+ 'Omni', # attr name
+ "" # eval'd attr data
+ 'CHECK', # compiler phase
+ );
+
+
+ # my %hsh :Good(q/bye) :Omni(q/bus/);
+
+ MyClass::Good:ATTR(HASH)( 'SomeOtherClass', # class
+ 'LEXICAL', # no typeglob
+ \%hsh, # referent
+ 'Good', # attr name
+ 'q/bye' # raw attr data
+ 'CHECK', # compiler phase
+ );
+
+ MyClass::Omni:ATTR(HASH)( 'SomeOtherClass', # class
+ 'LEXICAL', # no typeglob
+ \%hsh, # referent
+ 'Omni', # attr name
+ 'bus' # eval'd attr data
+ 'CHECK', # compiler phase
+ );
Installing handlers into UNIVERSAL, makes them...err..universal.
For example:
- package Descriptions;
- use Attribute::Handlers;
+ package Descriptions;
+ use Attribute::Handlers;
- my %name;
- sub name { return $name{$_[2]}||*{$_[1]}{NAME} }
+ my %name;
+ sub name { return $name{$_[2]}||*{$_[1]}{NAME} }
- sub UNIVERSAL::Name :ATTR {
- $name{$_[2]} = $_[4];
- }
+ sub UNIVERSAL::Name :ATTR {
+ $name{$_[2]} = $_[4];
+ }
- sub UNIVERSAL::Purpose :ATTR {
- print STDERR "Purpose of ", &name, " is $_[4]\n";
- }
+ sub UNIVERSAL::Purpose :ATTR {
+ print STDERR "Purpose of ", &name, " is $_[4]\n";
+ }
- sub UNIVERSAL::Unit :ATTR {
- print STDERR &name, " measured in $_[4]\n";
- }
+ sub UNIVERSAL::Unit :ATTR {
+ print STDERR &name, " measured in $_[4]\n";
+ }
Let's you write:
- use Descriptions;
+ use Descriptions;
- my $capacity : Name(capacity)
- : Purpose(to store max storage capacity for files)
- : Unit(Gb);
+ my $capacity : Name(capacity)
+ : Purpose(to store max storage capacity for files)
+ : Unit(Gb);
- package Other;
+ package Other;
- sub foo : Purpose(to foo all data before barring it) { }
+ sub foo : Purpose(to foo all data before barring it) { }
- # etc.
+ # etc.
=head1 UTILITY FUNCTIONS
@@ -851,7 +854,7 @@ This module offers a single utility function, C<findsym()>.
=item findsym
- my $symbol = Attribute::Handlers::findsym($package, $referent);
+ my $symbol = Attribute::Handlers::findsym($package, $referent);
The function looks in the symbol table of C<$package> for the typeglob for
C<$referent>, which is a reference to a variable or subroutine (SCALAR, ARRAY,