Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
Attribute::Handlers::PUsereContributed PerlAttribute::Handlers::Prospective(3)

NAME
       Attribute::Handlers::Prospective	- Richer semantics for attribute
       handlers

VERSION
       This document describes version 0.01 of
       Attribute::Handlers::Prospective, released October 25, 2001.

SYNOPSIS
	       package MyClass;
	       require v5.6.1;
	       use Attribute::Handlers::Prospective;

	       sub Good	: ATTR(SCALAR) {
		       my ($package, $symbol, $referent, $attr,	$data, $phase) = @_;

		       # 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 INIT 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 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 AUTOATTR : ATTR {
		       # A handler named AUTOATTR is automagically invoked for
		       # any scalar, array, hash, or subroutine	with an	attribute
		       # for which no explicit handler is defined
		       # This is analogous to sub AUTOLOAD for method calls.
		       # Use $_[3] to determine	the actual name	of the attribute
		       ...
	       }

	       sub PREATTR : ATTR {
		       my ($package, $symbol, $referent, $attr,	$arglists, $phase) = @_;

		       # Any handler named PREATTR is automagically invoked before
		       # any other attribute handlers on the referent.
		       # $_[4] contains	an array of arrays, each of which is the
		       # complete argument list	that will be sent to each attribute
		       # ascribed to the referent
		       ...

	       sub POSTATTR : ATTR {
		       my ($package, $symbol, $referent, $attr,	$arglists, $phase) = @_;

		       # Any handler named POSTATTR is automagically invoked after
		       # any other attribute handlers on the referent.
		       # $_[4] contains	an array of arrays, each of which is the
		       # complete argument list	that was sent to each attribute
		       # ascribed to the referent
		       ...
	       }

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 "BEGIN", "CHECK",
       "INIT", run-time, or "END" block).

       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 ":ATTR". For example:

	       package LoudDecl;
	       use Attribute::Handlers::Prospective;

	       sub Loud	:ATTR {
		       my ($package, $symbol, $referent, $attr,	$data, $phase) = @_;
		       print STDERR
			       ref($referent), " ",
			       *{$symbol}{NAME}, " ",
			       "($referent) ", "was just declared ",
			       "and ascribed the ${attr} attribute ",
			       "with data ($data)\n",
			       "in phase $phase\n";
	       }

       This creates an handler for the attribute ":Loud" in the	class
       LoudDecl.  Thereafter, any subroutine declared with a ":Loud" attribute
       in the class LoudDecl:

	       package LoudDecl;

	       sub foo:	Loud {...}

       causes the above	handler	to be invoked, and passed:

       [0] the name of the package into	which it was declared;

       [1] a reference to the symbol table entry (typeglob) containing the
	   subroutine;

       [2] a reference to the subroutine;

       [3] the name of the attribute;

       [4] any data associated with that attribute;

       [5] the name of the phase in which the handler is being invoked.

       Likewise, declaring any variables with the ":Loud" attribute within the
       package:

	       package LoudDecl;

	       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	$_[2] will be a	reference to the variable).

       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).

       If a lexical variable is	given an attribute, there is no	symbol table
       to which	it belongs, so the symbol table	argument ($_[1]) is set	to the
       string 'LEXICAL(name)', where name is the name of the lexical
       (including its sigil). Likewise,	ascribing an attribute to an anonymous
       subroutine results in a symbol table argument of	'ANON'.

       The data	argument passes	in the value (if any) associated with the
       attribute. For example, if &foo had been	declared:

	       sub foo :Loud("turn it up to 11,	man!") {...}

       then the	string "turn it	up to 11, man!"	would be passed	as the last
       argument.

       Attribute::Handlers::Prospective	usually	treats the value(s) passed as
       the the data argument ($_[4]) as	standard Perl (but see "Non-
       interpretive attribute handlers").  The attribute's arguments are
       evaluated in an array context and passed	as an anonymous	array.

       For example, all	of these:

	       sub foo :Loud(till=>ears=>are=>bleeding)	{...}
	       sub foo :Loud(['till','ears','are','bleeding']) {...}
	       sub foo :Loud(qw/till ears are bleeding/) {...}

       causes it to pass "['till','ears','are','bleeding']" as the handler's
       data argument. If the data can't	be parsed as valid Perl, then a
       compilation error will occur.

       If no value is associated with the attribute, "undef" is	passed.

   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:

	       package OtherClass;

	       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 ":Loud" attributes).

   Type-specific attribute handlers
       If an attribute handler is declared and the ":ATTR" specifier is	given
       the name	of a built-in type ("SCALAR", "ARRAY", "HASH", "CODE", or
       "GLOB"),	the handler is only applied to declarations of that type. For
       example,	the following definition:

	       package LoudDecl;

	       sub RealLoud :ATTR(SCALAR) { print "Yeeeeow!" }

       creates an attribute handler that applies only to scalars:

	       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

       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::Prospective;

	       sub SeriousLoud :ATTR(ANY) { warn "Hearing loss imminent" }

       (I.e. "ATTR(ANY)" is a synonym for ":ATTR").

   Non-interpretive attribute handlers
       Occasionally it is preferable that the data argument of an attribute be
       treated as a string, rather than	as valid Perl.

       This can	be specified by	giving the "ATTR" attribute of an attribute
       handler the keyword "RAWDATA". For example:

	       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	an uninterpolated "q(...)" string:

	       my $power : Raw(1..100);	       # handlers receives "1..100"

   Phase-specific attribute handlers
       By default, attribute handlers are called just before execution (in an
       "INIT" 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.

       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:

	       sub Early    :ATTR(SCALAR,BEGIN)	{...}
	       sub Earlyish :ATTR(SCALAR,CHECK)	{...}
	       sub Normal   :ATTR(SCALAR,INIT) {...}
	       sub Active   :ATTR(SCALAR,RUN) {...}
	       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.

       Note that attribute handlers that are scheduled for the "BEGIN" phase
       are handled as soon as the attribute is detected	(i.e. before any
       subsequently defined "BEGIN" blocks are executed).

       Attribute handlers that are scheduled for the "RUN" phase are executed
       every time the code itself executes.

   Default attribute handlers
       Perl makes it possible to create	default	handlers for subroutine	calls,
       by defining a subroutine	named "AUTOLOAD". Likewise
       Attribute::Handlers::Prospective	makes it possible to set up default
       handlers	for attributes,	by defining an attribute handler named
       "AUTOATTR".

       For example:

	       package Real;

	       sub RealAttr : ATTR {
		       print "You ascribed a RealAttr attribute	to $_[2]\n";
	       }

	       sub AUTOATTR : ATTR {
		       warn "You tried to ascribe a :$_[3] attribute to	$_[2]\n",
			    "but there's no such attribute defined in class $_[0]\n",
			    "(Did you mean :RealAttr?)\n";
	       }

       Now, ascribing any other	attribute except ":RealAttr" to	a referent
       associated with the Real	package	provokes a warning.

       If the "AUTOATTR" hadn't	been defined, ascribing	any other attribute
       would have produced a fatal error.

       Note that the arguments an "AUTOATTR" receives are indentical to	those
       that would have been received by	the real attribute handler it's
       replacing.

   Pre-	and post-attribute handlers
       There are two other attribute handlers whose names mark them as
       special:	"PREATTR" and "POSTATTR". Any handler with one of these	names
       is treated as a prefix/postfix handler, and is called automatically on
       any referent that is ascribed one or more attributes.

       These handlers receive the same six arguments as	any other handler, the
       only difference being that their	$data argument ($_[4]) is an array of
       arrays.	Each of	those inner arrays is the complete argument list that
       each attribute in turn will receive.

       For example, to report each attribute scribed to	any scalar, we could
       write:

	       use Data::Dumper	'Dumper';

	       sub UNIVERSAL::PREATTR :	ATTR(SCALAR) {
		       my $name	= *{$_[1]}{NAME};
		       $name = "PACKAGE(\$$name)" unless $name =~ /^LEXICAL/;
		       print "$name was	ascribed:\n";
		       foreach $arglist	( @{$_[4]} ) {
			       print "$arglist->[3](", Dumper($arglist), ")\n"
		       }
	       }

       Note that changes to the	argument lists within the pre- and postfix
       handlers	do not propagate to the	actual attribute handler calls (though
       they may	do so in future	releases).

   Attributes as "tie" interfaces
       Attributes make an excellent and	intuitive interface through which to
       tie variables. For example:

	       use Attribute::Handlers::Prospective;
	       use Tie::Cycle;

	       sub UNIVERSAL::Cycle : ATTR(SCALAR, RUN)	{
		       my ($package, $symbol, $referent, $attr,	$data, $phase) = @_;
		       $data = [ $data ] unless	ref $data eq 'ARRAY';
		       tie $$referent, 'Tie::Cycle', $data;
	       }

	       # and thereafter...

	       package main;

	       my $next	: Cycle('A'..'Z');     # $next is now a	tied variable

	       while (<>) {
		       print $next;
	       }

       In fact,	this pattern is	so widely applicable that
       Attribute::Handlers::Prospective	provides a way to automate it:
       specifying 'autotie' in the "use	Attribute::Handlers::Prospective"
       statement. So, the previous example, could also be written:

	       use Attribute::Handlers::Prospective autotie => { Cycle => 'Tie::Cycle' };

	       # and thereafter...

	       package main;

	       my $next	: Cycle('A'..'Z');     # $next is now a	tied variable

	       while (<>) {
		       print $next;

       The argument after 'autotie' 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.

       Note that there is no longer any	need to	import the Tie::Cycle module
       -- Attribute::Handlers::Prospective takes care of that automagically.
       You can even pass arguments to the module's "import" subroutine,	by
       appending them to the class name. For example:

	       use Attribute::Handlers::Prospective
		       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::Prospective 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 facilitiate this, Attribute::Handlers::Prospective recognizes	a
       special "pseudo-class" -- "__CALLER__", which may be specified as the
       qualifier of an attribute:

	       package Tie::Me::Kangaroo:Down::Sport;

	       use Attribute::Handlers::Prospective autotie => { __CALLER__::Roo => __PACKAGE__	};

       This causes Attribute::Handlers::Prospective to define the "Roo"
       attribute in the	package	that imports the Tie::Me::Kangaroo:Down::Sport
       module.

       Passing the tied	object to "tie"

       Occasionally it is important to pass a reference	to the object being
       tied to the TIESCALAR, TIEHASH, etc. that ties it.

       The "autotie" mechanism supports	this too. The following	code:

	       use Attribute::Handlers::Prospective autotieref => { Selfish => Tie::Selfish };
	       my $var : Selfish(@args);

       has the same effect as:

	       tie my $var, 'Tie::Selfish', @args;

       But when	"autotieref" is	used instead of	"autotie":

	       use Attribute::Handlers::Prospective autotieref => { Selfish => Tie::Selfish };
	       my $var : Selfish(@args);

       the effect is to	pass the "tie" call an extra reference to the variable
       being tied:

	       tie my $var, 'Tie::Selfish', \$var, @args;

   Universal attributes
       Installing handlers into	UNIVERSAL, makes them...err..universal.	 For
       example:

	       package Descriptions;
	       use Attribute::Handlers::Prospective;

	       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]\n";
	       }

	       sub UNIVERSAL::Unit :ATTR {
		       print STDERR &name, " measured in $_[4]\n";
	       }

       Let's you write:

	       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.

DIAGNOSTICS
       "No such	%s attribute: %s"
	   And attribute was applied to	a referent for which there is no
	   corresponding attribute handler. Typically this means that the
	   attribute handler that was declared does not	handle the type	of
	   referent you	used.

       "Can't autotie a	%s"
	   You can only	declare	autoties for types "SCALAR", "ARRAY", "HASH",
	   and "GLOB". They're the only	things that Perl can tie.

       "Internal error"
	   Something is	rotten in the state of the program.  Send a bug
	   report.

AUTHOR
       Damian Conway (damian@conway.org)

BUGS
       There are undoubtedly serious bugs lurking somewhere in code this funky
       :-) Bug reports and other feedback are most welcome.

COPYRIGHT
		Copyright (c) 2001, 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.

perl v5.24.1			  2001-10-2Attribute::Handlers::Prospective(3)

NAME | VERSION | SYNOPSIS | DESCRIPTION | DIAGNOSTICS | AUTHOR | BUGS | COPYRIGHT

Want to link to this manual page? Use this URL:
<https://www.freebsd.org/cgi/man.cgi?query=Attribute::Handlers::Prospective&sektion=3&manpath=FreeBSD+12.1-RELEASE+and+Ports>

home | help