summaryrefslogtreecommitdiffstats
path: root/upstream/mageia-cauldron/man3pm/Attribute::Handlers.3pm
diff options
context:
space:
mode:
Diffstat (limited to 'upstream/mageia-cauldron/man3pm/Attribute::Handlers.3pm')
-rw-r--r--upstream/mageia-cauldron/man3pm/Attribute::Handlers.3pm758
1 files changed, 758 insertions, 0 deletions
diff --git a/upstream/mageia-cauldron/man3pm/Attribute::Handlers.3pm b/upstream/mageia-cauldron/man3pm/Attribute::Handlers.3pm
new file mode 100644
index 00000000..eb46aece
--- /dev/null
+++ b/upstream/mageia-cauldron/man3pm/Attribute::Handlers.3pm
@@ -0,0 +1,758 @@
+.\" -*- mode: troff; coding: utf-8 -*-
+.\" Automatically generated by Pod::Man 5.01 (Pod::Simple 3.43)
+.\"
+.\" Standard preamble:
+.\" ========================================================================
+.de Sp \" Vertical space (when we can't use .PP)
+.if t .sp .5v
+.if n .sp
+..
+.de Vb \" Begin verbatim text
+.ft CW
+.nf
+.ne \\$1
+..
+.de Ve \" End verbatim text
+.ft R
+.fi
+..
+.\" \*(C` and \*(C' are quotes in nroff, nothing in troff, for use with C<>.
+.ie n \{\
+. ds C` ""
+. ds C' ""
+'br\}
+.el\{\
+. ds C`
+. ds C'
+'br\}
+.\"
+.\" Escape single quotes in literal strings from groff's Unicode transform.
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\"
+.\" If the F register is >0, we'll generate index entries on stderr for
+.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
+.\" entries marked with X<> in POD. Of course, you'll have to process the
+.\" output yourself in some meaningful fashion.
+.\"
+.\" Avoid warning from groff about undefined register 'F'.
+.de IX
+..
+.nr rF 0
+.if \n(.g .if rF .nr rF 1
+.if (\n(rF:(\n(.g==0)) \{\
+. if \nF \{\
+. de IX
+. tm Index:\\$1\t\\n%\t"\\$2"
+..
+. if !\nF==2 \{\
+. nr % 0
+. nr F 2
+. \}
+. \}
+.\}
+.rr rF
+.\" ========================================================================
+.\"
+.IX Title "Attribute::Handlers 3pm"
+.TH Attribute::Handlers 3pm 2023-11-28 "perl v5.38.2" "Perl Programmers Reference Guide"
+.\" For nroff, turn off justification. Always turn off hyphenation; it makes
+.\" way too many mistakes in technical documents.
+.if n .ad l
+.nh
+.SH NAME
+Attribute::Handlers \- Simpler definition of attribute handlers
+.SH VERSION
+.IX Header "VERSION"
+This document describes version 1.03 of Attribute::Handlers.
+.SH SYNOPSIS
+.IX Header "SYNOPSIS"
+.Vb 4
+\& package MyClass;
+\& require 5.006;
+\& use Attribute::Handlers;
+\& no warnings \*(Aqredefine\*(Aq;
+\&
+\&
+\& 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.
+\&
+\& # 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 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 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.
+\& ...
+\& }
+\&
+\&
+\& use Attribute::Handlers autotie => { Cycle => Tie::Cycle };
+\&
+\& my $next : Cycle([\*(AqA\*(Aq..\*(AqZ\*(Aq]);
+.Ve
+.SH DESCRIPTION
+.IX Header "DESCRIPTION"
+This module, when inherited by a package, allows that package's class to
+define attribute handler subroutines for specific attributes. Variables
+and subroutines subsequently defined in that package, or in packages
+derived from that package may be given attributes with the same names as
+the attribute handler subroutines, which will then be called in one of
+the compilation phases (i.e. in a \f(CW\*(C`BEGIN\*(C'\fR, \f(CW\*(C`CHECK\*(C'\fR, \f(CW\*(C`INIT\*(C'\fR, or \f(CW\*(C`END\*(C'\fR
+block). (\f(CW\*(C`UNITCHECK\*(C'\fR blocks don't correspond to a global compilation
+phase, so they can't be specified here.)
+.PP
+To create a handler, define it as a subroutine with the same name as
+the desired attribute, and declare the subroutine itself with the
+attribute \f(CW\*(C`:ATTR\*(C'\fR. For example:
+.PP
+.Vb 2
+\& package LoudDecl;
+\& use Attribute::Handlers;
+\&
+\& sub Loud :ATTR {
+\& my ($package, $symbol, $referent, $attr, $data, $phase,
+\& $filename, $linenum) = @_;
+\& print STDERR
+\& ref($referent), " ",
+\& *{$symbol}{NAME}, " ",
+\& "($referent) ", "was just declared ",
+\& "and ascribed the ${attr} attribute ",
+\& "with data ($data)\en",
+\& "in phase $phase\en",
+\& "in file $filename at line $linenum\en";
+\& }
+.Ve
+.PP
+This creates a handler for the attribute \f(CW\*(C`:Loud\*(C'\fR in the class LoudDecl.
+Thereafter, any subroutine declared with a \f(CW\*(C`:Loud\*(C'\fR attribute in the class
+LoudDecl:
+.PP
+.Vb 1
+\& package LoudDecl;
+\&
+\& sub foo: Loud {...}
+.Ve
+.PP
+causes the above handler to be invoked, and passed:
+.IP [0] 4
+.IX Item "[0]"
+the name of the package into which it was declared;
+.IP [1] 4
+.IX Item "[1]"
+a reference to the symbol table entry (typeglob) containing the subroutine;
+.IP [2] 4
+.IX Item "[2]"
+a reference to the subroutine;
+.IP [3] 4
+.IX Item "[3]"
+the name of the attribute;
+.IP [4] 4
+.IX Item "[4]"
+any data associated with that attribute;
+.IP [5] 4
+.IX Item "[5]"
+the name of the phase in which the handler is being invoked;
+.IP [6] 4
+.IX Item "[6]"
+the filename in which the handler is being invoked;
+.IP [7] 4
+.IX Item "[7]"
+the line number in this file.
+.PP
+Likewise, declaring any variables with the \f(CW\*(C`:Loud\*(C'\fR attribute within the
+package:
+.PP
+.Vb 1
+\& package LoudDecl;
+\&
+\& my $foo :Loud;
+\& my @foo :Loud;
+\& my %foo :Loud;
+.Ve
+.PP
+will cause the handler to be called with a similar argument list (except,
+of course, that \f(CW$_[2]\fR will be a reference to the variable).
+.PP
+The package name argument will typically be the name of the class into
+which the subroutine was declared, but it may also be the name of a derived
+class (since handlers are inherited).
+.PP
+If a lexical variable is given an attribute, there is no symbol table to
+which it belongs, so the symbol table argument (\f(CW$_[1]\fR) is set to the
+string \f(CW\*(AqLEXICAL\*(Aq\fR in that case. Likewise, ascribing an attribute to
+an anonymous subroutine results in a symbol table argument of \f(CW\*(AqANON\*(Aq\fR.
+.PP
+The data argument passes in the value (if any) associated with the
+attribute. For example, if \f(CW&foo\fR had been declared:
+.PP
+.Vb 1
+\& sub foo :Loud("turn it up to 11, man!") {...}
+.Ve
+.PP
+then a reference to an array containing the string
+\&\f(CW"turn it up to 11, man!"\fR would be passed as the last argument.
+.PP
+Attribute::Handlers makes strenuous efforts to convert
+the data argument (\f(CW$_[4]\fR) to a usable form before passing it to
+the handler (but see "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.
+For example, all of these:
+.PP
+.Vb 4
+\& sub foo :Loud(till=>ears=>are=>bleeding) {...}
+\& sub foo :Loud(qw/till ears are bleeding/) {...}
+\& sub foo :Loud(qw/till, ears, are, bleeding/) {...}
+\& sub foo :Loud(till,ears,are,bleeding) {...}
+.Ve
+.PP
+causes it to pass \f(CW\*(C`[\*(Aqtill\*(Aq,\*(Aqears\*(Aq,\*(Aqare\*(Aq,\*(Aqbleeding\*(Aq]\*(C'\fR as the handler's
+data argument. While:
+.PP
+.Vb 1
+\& sub foo :Loud([\*(Aqtill\*(Aq,\*(Aqears\*(Aq,\*(Aqare\*(Aq,\*(Aqbleeding\*(Aq]) {...}
+.Ve
+.PP
+causes it to pass \f(CW\*(C`[ [\*(Aqtill\*(Aq,\*(Aqears\*(Aq,\*(Aqare\*(Aq,\*(Aqbleeding\*(Aq] ]\*(C'\fR; the array
+reference specified in the data being passed inside the standard
+array reference indicating successful interpretation.
+.PP
+However, if the data can't be parsed as valid Perl, then
+it is passed as an uninterpreted string. For example:
+.PP
+.Vb 2
+\& sub foo :Loud(my,ears,are,bleeding) {...}
+\& sub foo :Loud(qw/my ears are bleeding) {...}
+.Ve
+.PP
+cause the strings \f(CW\*(Aqmy,ears,are,bleeding\*(Aq\fR and
+\&\f(CW\*(Aqqw/my ears are bleeding\*(Aq\fR respectively to be passed as the
+data argument.
+.PP
+If no value is associated with the attribute, \f(CW\*(C`undef\*(C'\fR is passed.
+.SS "Typed lexicals"
+.IX Subsection "Typed lexicals"
+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:
+.PP
+.Vb 1
+\& package OtherClass;
+\&
+\& my LoudDecl $loudobj : Loud;
+\& my LoudDecl @loudobjs : Loud;
+\& my LoudDecl %loudobjex : Loud;
+.Ve
+.PP
+causes the LoudDecl::Loud handler to be invoked (even if OtherClass also
+defines a handler for \f(CW\*(C`:Loud\*(C'\fR attributes).
+.SS "Type-specific attribute handlers"
+.IX Subsection "Type-specific attribute handlers"
+If an attribute handler is declared and the \f(CW\*(C`:ATTR\*(C'\fR specifier is
+given the name of a built-in type (\f(CW\*(C`SCALAR\*(C'\fR, \f(CW\*(C`ARRAY\*(C'\fR, \f(CW\*(C`HASH\*(C'\fR, or \f(CW\*(C`CODE\*(C'\fR),
+the handler is only applied to declarations of that type. For example,
+the following definition:
+.PP
+.Vb 1
+\& package LoudDecl;
+\&
+\& sub RealLoud :ATTR(SCALAR) { print "Yeeeeow!" }
+.Ve
+.PP
+creates an attribute handler that applies only to scalars:
+.PP
+.Vb 2
+\& 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
+.Ve
+.PP
+You can, of course, declare separate handlers for these types as well
+(but you'll need to specify \f(CW\*(C`no warnings \*(Aqredefine\*(Aq\*(C'\fR to do it quietly):
+.PP
+.Vb 3
+\& package LoudDecl;
+\& use Attribute::Handlers;
+\& no warnings \*(Aqredefine\*(Aq;
+\&
+\& 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" }
+.Ve
+.PP
+You can also explicitly indicate that a single handler is meant to be
+used for all types of referents like so:
+.PP
+.Vb 2
+\& package LoudDecl;
+\& use Attribute::Handlers;
+\&
+\& sub SeriousLoud :ATTR(ANY) { warn "Hearing loss imminent" }
+.Ve
+.PP
+(I.e. \f(CWATTR(ANY)\fR is a synonym for \f(CW\*(C`:ATTR\*(C'\fR).
+.SS "Non-interpretive attribute handlers"
+.IX Subsection "Non-interpretive attribute handlers"
+Occasionally the strenuous efforts Attribute::Handlers makes to convert
+the data argument (\f(CW$_[4]\fR) to a usable form before passing it to
+the handler get in the way.
+.PP
+You can turn off that eagerness-to-help by declaring
+an attribute handler with the keyword \f(CW\*(C`RAWDATA\*(C'\fR. For example:
+.PP
+.Vb 3
+\& sub Raw : ATTR(RAWDATA) {...}
+\& sub Nekkid : ATTR(SCALAR,RAWDATA) {...}
+\& sub Au::Naturale : ATTR(RAWDATA,ANY) {...}
+.Ve
+.PP
+Then the handler makes absolutely no attempt to interpret the data it
+receives and simply passes it as a string:
+.PP
+.Vb 1
+\& my $power : Raw(1..100); # handlers receives "1..100"
+.Ve
+.SS "Phase-specific attribute handlers"
+.IX Subsection "Phase-specific attribute handlers"
+By default, attribute handlers are called at the end of the compilation
+phase (in a \f(CW\*(C`CHECK\*(C'\fR block). This seems to be optimal in most cases because
+most things that can be defined are defined by that point but nothing has
+been executed.
+.PP
+However, it is possible to set up attribute handlers that are called at
+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:
+.PP
+.Vb 5
+\& 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) {...}
+.Ve
+.PP
+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.
+.PP
+Note that attribute handlers that are scheduled for the \f(CW\*(C`BEGIN\*(C'\fR phase
+are handled as soon as the attribute is detected (i.e. before any
+subsequently defined \f(CW\*(C`BEGIN\*(C'\fR blocks are executed).
+.ie n .SS "Attributes as ""tie"" interfaces"
+.el .SS "Attributes as \f(CWtie\fP interfaces"
+.IX Subsection "Attributes as tie interfaces"
+Attributes make an excellent and intuitive interface through which to tie
+variables. For example:
+.PP
+.Vb 2
+\& use Attribute::Handlers;
+\& use Tie::Cycle;
+\&
+\& sub UNIVERSAL::Cycle : ATTR(SCALAR) {
+\& my ($package, $symbol, $referent, $attr, $data, $phase) = @_;
+\& $data = [ $data ] unless ref $data eq \*(AqARRAY\*(Aq;
+\& tie $$referent, \*(AqTie::Cycle\*(Aq, $data;
+\& }
+\&
+\& # and thereafter...
+\&
+\& package main;
+\&
+\& my $next : Cycle(\*(AqA\*(Aq..\*(AqZ\*(Aq); # $next is now a tied variable
+\&
+\& while (<>) {
+\& print $next;
+\& }
+.Ve
+.PP
+Note that, because the \f(CW\*(C`Cycle\*(C'\fR attribute receives its arguments in the
+\&\f(CW$data\fR variable, if the attribute is given a list of arguments, \f(CW$data\fR
+will consist of a single array reference; otherwise, it will consist of the
+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:
+.PP
+.Vb 1
+\& $data = [ $data ] unless ref $data eq \*(AqARRAY\*(Aq;
+.Ve
+.PP
+Typically, however, things are the other way around: the tieable class expects
+its arguments as a flattened list, so the attribute looks like:
+.PP
+.Vb 5
+\& sub UNIVERSAL::Cycle : ATTR(SCALAR) {
+\& my ($package, $symbol, $referent, $attr, $data, $phase) = @_;
+\& my @data = ref $data eq \*(AqARRAY\*(Aq ? @$data : $data;
+\& tie $$referent, \*(AqTie::Whatever\*(Aq, @data;
+\& }
+.Ve
+.PP
+This software pattern is so widely applicable that Attribute::Handlers
+provides a way to automate it: specifying \f(CW\*(Aqautotie\*(Aq\fR in the
+\&\f(CW\*(C`use Attribute::Handlers\*(C'\fR statement. So, the cycling example,
+could also be written:
+.PP
+.Vb 1
+\& use Attribute::Handlers autotie => { Cycle => \*(AqTie::Cycle\*(Aq };
+\&
+\& # and thereafter...
+\&
+\& package main;
+\&
+\& my $next : Cycle([\*(AqA\*(Aq..\*(AqZ\*(Aq]); # $next is now a tied variable
+\&
+\& while (<>) {
+\& print $next;
+\& }
+.Ve
+.PP
+Note that we now have to pass the cycling values as an array reference,
+since the \f(CW\*(C`autotie\*(C'\fR mechanism passes \f(CW\*(C`tie\*(C'\fR a list of arguments as a list
+(as in the Tie::Whatever example), \fInot\fR as an array reference (as in
+the original Tie::Cycle example at the start of this section).
+.PP
+The argument after \f(CW\*(Aqautotie\*(Aq\fR is a reference to a hash in which each key is
+the name of an attribute to be created, and each value is the class to which
+variables ascribed that attribute should be tied.
+.PP
+Note that there is no longer any need to import the Tie::Cycle module \-\-
+Attribute::Handlers takes care of that automagically. You can even pass
+arguments to the module's \f(CW\*(C`import\*(C'\fR subroutine, by appending them to the
+class name. For example:
+.PP
+.Vb 2
+\& use Attribute::Handlers
+\& autotie => { Dir => \*(AqTie::Dir qw(DIR_UNLINK)\*(Aq };
+.Ve
+.PP
+If the attribute name is unqualified, the attribute is installed in the
+current package. Otherwise it is installed in the qualifier's package:
+.PP
+.Vb 1
+\& 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
+\& };
+.Ve
+.PP
+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" \-\-
+\&\f(CW\*(C`_\|_CALLER_\|_\*(C'\fR, which may be specified as the qualifier of an attribute:
+.PP
+.Vb 1
+\& package Tie::Me::Kangaroo::Down::Sport;
+\&
+\& use Attribute::Handlers autotie =>
+\& { \*(Aq_\|_CALLER_\|_::Roo\*(Aq => _\|_PACKAGE_\|_ };
+.Ve
+.PP
+This causes Attribute::Handlers to define the \f(CW\*(C`Roo\*(C'\fR attribute in the package
+that imports the Tie::Me::Kangaroo::Down::Sport module.
+.PP
+Note that it is important to quote the _\|_CALLER_\|_::Roo identifier because
+a bug in perl 5.8 will refuse to parse it and cause an unknown error.
+.PP
+\fIPassing the tied object to \fR\f(CI\*(C`tie\*(C'\fR
+.IX Subsection "Passing the tied object to tie"
+.PP
+Occasionally it is important to pass a reference to the object being tied
+to the TIESCALAR, TIEHASH, etc. that ties it.
+.PP
+The \f(CW\*(C`autotie\*(C'\fR mechanism supports this too. The following code:
+.PP
+.Vb 2
+\& use Attribute::Handlers autotieref => { Selfish => Tie::Selfish };
+\& my $var : Selfish(@args);
+.Ve
+.PP
+has the same effect as:
+.PP
+.Vb 1
+\& tie my $var, \*(AqTie::Selfish\*(Aq, @args;
+.Ve
+.PP
+But when \f(CW"autotieref"\fR is used instead of \f(CW"autotie"\fR:
+.PP
+.Vb 2
+\& use Attribute::Handlers autotieref => { Selfish => Tie::Selfish };
+\& my $var : Selfish(@args);
+.Ve
+.PP
+the effect is to pass the \f(CW\*(C`tie\*(C'\fR call an extra reference to the variable
+being tied:
+.PP
+.Vb 1
+\& tie my $var, \*(AqTie::Selfish\*(Aq, \e$var, @args;
+.Ve
+.SH EXAMPLES
+.IX Header "EXAMPLES"
+If the class shown in "SYNOPSIS" were placed in the MyClass.pm
+module, then the following code:
+.PP
+.Vb 2
+\& package main;
+\& use MyClass;
+\&
+\& my MyClass $slr :Good :Bad(1**1\-1) :Omni(\-vorous);
+\&
+\& package SomeOtherClass;
+\& use base MyClass;
+\&
+\& sub tent { \*(Aqacle\*(Aq }
+\&
+\& sub fn :Ugly(sister) :Omni(\*(Aqpo\*(Aq,tent()) {...}
+\& my @arr :Good :Omni(s/cie/nt/);
+\& my %hsh :Good(q/bye/) :Omni(q/bus/);
+.Ve
+.PP
+would cause the following handlers to be invoked:
+.PP
+.Vb 1
+\& # my MyClass $slr :Good :Bad(1**1\-1) :Omni(\-vorous);
+\&
+\& MyClass::Good:ATTR(SCALAR)( \*(AqMyClass\*(Aq, # class
+\& \*(AqLEXICAL\*(Aq, # no typeglob
+\& \e$slr, # referent
+\& \*(AqGood\*(Aq, # attr name
+\& undef # no attr data
+\& \*(AqCHECK\*(Aq, # compiler phase
+\& );
+\&
+\& MyClass::Bad:ATTR(SCALAR)( \*(AqMyClass\*(Aq, # class
+\& \*(AqLEXICAL\*(Aq, # no typeglob
+\& \e$slr, # referent
+\& \*(AqBad\*(Aq, # attr name
+\& 0 # eval\*(Aqd attr data
+\& \*(AqCHECK\*(Aq, # compiler phase
+\& );
+\&
+\& MyClass::Omni:ATTR(SCALAR)( \*(AqMyClass\*(Aq, # class
+\& \*(AqLEXICAL\*(Aq, # no typeglob
+\& \e$slr, # referent
+\& \*(AqOmni\*(Aq, # attr name
+\& \*(Aq\-vorous\*(Aq # eval\*(Aqd attr data
+\& \*(AqCHECK\*(Aq, # compiler phase
+\& );
+\&
+\&
+\& # sub fn :Ugly(sister) :Omni(\*(Aqpo\*(Aq,tent()) {...}
+\&
+\& MyClass::UGLY:ATTR(CODE)( \*(AqSomeOtherClass\*(Aq, # class
+\& \e*SomeOtherClass::fn, # typeglob
+\& \e&SomeOtherClass::fn, # referent
+\& \*(AqUgly\*(Aq, # attr name
+\& \*(Aqsister\*(Aq # eval\*(Aqd attr data
+\& \*(AqCHECK\*(Aq, # compiler phase
+\& );
+\&
+\& MyClass::Omni:ATTR(CODE)( \*(AqSomeOtherClass\*(Aq, # class
+\& \e*SomeOtherClass::fn, # typeglob
+\& \e&SomeOtherClass::fn, # referent
+\& \*(AqOmni\*(Aq, # attr name
+\& [\*(Aqpo\*(Aq,\*(Aqacle\*(Aq] # eval\*(Aqd attr data
+\& \*(AqCHECK\*(Aq, # compiler phase
+\& );
+\&
+\&
+\& # my @arr :Good :Omni(s/cie/nt/);
+\&
+\& MyClass::Good:ATTR(ARRAY)( \*(AqSomeOtherClass\*(Aq, # class
+\& \*(AqLEXICAL\*(Aq, # no typeglob
+\& \e@arr, # referent
+\& \*(AqGood\*(Aq, # attr name
+\& undef # no attr data
+\& \*(AqCHECK\*(Aq, # compiler phase
+\& );
+\&
+\& MyClass::Omni:ATTR(ARRAY)( \*(AqSomeOtherClass\*(Aq, # class
+\& \*(AqLEXICAL\*(Aq, # no typeglob
+\& \e@arr, # referent
+\& \*(AqOmni\*(Aq, # attr name
+\& "" # eval\*(Aqd attr data
+\& \*(AqCHECK\*(Aq, # compiler phase
+\& );
+\&
+\&
+\& # my %hsh :Good(q/bye) :Omni(q/bus/);
+\&
+\& MyClass::Good:ATTR(HASH)( \*(AqSomeOtherClass\*(Aq, # class
+\& \*(AqLEXICAL\*(Aq, # no typeglob
+\& \e%hsh, # referent
+\& \*(AqGood\*(Aq, # attr name
+\& \*(Aqq/bye\*(Aq # raw attr data
+\& \*(AqCHECK\*(Aq, # compiler phase
+\& );
+\&
+\& MyClass::Omni:ATTR(HASH)( \*(AqSomeOtherClass\*(Aq, # class
+\& \*(AqLEXICAL\*(Aq, # no typeglob
+\& \e%hsh, # referent
+\& \*(AqOmni\*(Aq, # attr name
+\& \*(Aqbus\*(Aq # eval\*(Aqd attr data
+\& \*(AqCHECK\*(Aq, # compiler phase
+\& );
+.Ve
+.PP
+Installing handlers into UNIVERSAL, makes them...err..universal.
+For example:
+.PP
+.Vb 2
+\& package Descriptions;
+\& use Attribute::Handlers;
+\&
+\& my %name;
+\& sub name { return $name{$_[2]}||*{$_[1]}{NAME} }
+\&
+\& sub UNIVERSAL::Name :ATTR {
+\& $name{$_[2]} = $_[4];
+\& }
+\&
+\& sub UNIVERSAL::Purpose :ATTR {
+\& print STDERR "Purpose of ", &name, " is $_[4]\en";
+\& }
+\&
+\& sub UNIVERSAL::Unit :ATTR {
+\& print STDERR &name, " measured in $_[4]\en";
+\& }
+.Ve
+.PP
+Let's you write:
+.PP
+.Vb 1
+\& use Descriptions;
+\&
+\& my $capacity : Name(capacity)
+\& : Purpose(to store max storage capacity for files)
+\& : Unit(Gb);
+\&
+\&
+\& package Other;
+\&
+\& sub foo : Purpose(to foo all data before barring it) { }
+\&
+\& # etc.
+.Ve
+.SH "UTILITY FUNCTIONS"
+.IX Header "UTILITY FUNCTIONS"
+This module offers a single utility function, \f(CWfindsym()\fR.
+.IP findsym 4
+.IX Item "findsym"
+.Vb 1
+\& my $symbol = Attribute::Handlers::findsym($package, $referent);
+.Ve
+.Sp
+The function looks in the symbol table of \f(CW$package\fR for the typeglob for
+\&\f(CW$referent\fR, which is a reference to a variable or subroutine (SCALAR, ARRAY,
+HASH, or CODE). If it finds the typeglob, it returns it. Otherwise, it returns
+undef. Note that \f(CW\*(C`findsym\*(C'\fR memoizes the typeglobs it has previously
+successfully found, so subsequent calls with the same arguments should be
+much faster.
+.SH DIAGNOSTICS
+.IX Header "DIAGNOSTICS"
+.ie n .IP """Bad attribute type: ATTR(%s)""" 4
+.el .IP "\f(CWBad attribute type: ATTR(%s)\fR" 4
+.IX Item "Bad attribute type: ATTR(%s)"
+An attribute handler was specified with an \f(CW:ATTR(\fR\f(CIref_type\fR\f(CW)\fR, but the
+type of referent it was defined to handle wasn't one of the five permitted:
+\&\f(CW\*(C`SCALAR\*(C'\fR, \f(CW\*(C`ARRAY\*(C'\fR, \f(CW\*(C`HASH\*(C'\fR, \f(CW\*(C`CODE\*(C'\fR, or \f(CW\*(C`ANY\*(C'\fR.
+.ie n .IP """Attribute handler %s doesn\*(Aqt handle %s attributes""" 4
+.el .IP "\f(CWAttribute handler %s doesn\*(Aqt handle %s attributes\fR" 4
+.IX Item "Attribute handler %s doesnt handle %s attributes"
+A handler for attributes of the specified name \fIwas\fR defined, but not
+for the specified type of declaration. Typically encountered when trying
+to apply a \f(CW\*(C`VAR\*(C'\fR attribute handler to a subroutine, or a \f(CW\*(C`SCALAR\*(C'\fR
+attribute handler to some other type of variable.
+.ie n .IP """Declaration of %s attribute in package %s may clash with future reserved word""" 4
+.el .IP "\f(CWDeclaration of %s attribute in package %s may clash with future reserved word\fR" 4
+.IX Item "Declaration of %s attribute in package %s may clash with future reserved word"
+A handler for an attributes with an all-lowercase name was declared. An
+attribute with an all-lowercase name might have a meaning to Perl
+itself some day, even though most don't yet. Use a mixed-case attribute
+name, instead.
+.ie n .IP """Can\*(Aqt have two ATTR specifiers on one subroutine""" 4
+.el .IP "\f(CWCan\*(Aqt have two ATTR specifiers on one subroutine\fR" 4
+.IX Item "Cant have two ATTR specifiers on one subroutine"
+You just can't, okay?
+Instead, put all the specifications together with commas between them
+in a single \f(CWATTR(\fR\f(CIspecification\fR\f(CW)\fR.
+.ie n .IP """Can\*(Aqt autotie a %s""" 4
+.el .IP "\f(CWCan\*(Aqt autotie a %s\fR" 4
+.IX Item "Cant autotie a %s"
+You can only declare autoties for types \f(CW"SCALAR"\fR, \f(CW"ARRAY"\fR, and
+\&\f(CW"HASH"\fR. They're the only things (apart from typeglobs \-\- which are
+not declarable) that Perl can tie.
+.ie n .IP """Internal error: %s symbol went missing""" 4
+.el .IP "\f(CWInternal error: %s symbol went missing\fR" 4
+.IX Item "Internal error: %s symbol went missing"
+Something is rotten in the state of the program. An attributed
+subroutine ceased to exist between the point it was declared and the point
+at which its attribute handler(s) would have been called.
+.ie n .IP """Won\*(Aqt be able to apply END handler""" 4
+.el .IP "\f(CWWon\*(Aqt be able to apply END handler\fR" 4
+.IX Item "Wont be able to apply END handler"
+You have defined an END handler for an attribute that is being applied
+to a lexical variable. Since the variable may not be available during END
+this won't happen.
+.SH AUTHOR
+.IX Header "AUTHOR"
+Damian Conway (damian@conway.org). The maintainer of this module is now Rafael
+Garcia-Suarez (rgarciasuarez@gmail.com).
+.PP
+Maintainer of the CPAN release is Steffen Mueller (smueller@cpan.org).
+Contact him with technical difficulties with respect to the packaging of the
+CPAN module.
+.SH BUGS
+.IX Header "BUGS"
+There are undoubtedly serious bugs lurking somewhere in code this funky :\-)
+Bug reports and other feedback are most welcome.
+.SH "COPYRIGHT AND LICENSE"
+.IX Header "COPYRIGHT AND LICENSE"
+.Vb 3
+\& Copyright (c) 2001\-2014, Damian Conway. All Rights Reserved.
+\& This module is free software. It may be used, redistributed
+\& and/or modified under the same terms as Perl itself.
+.Ve