1N/Apackage attributes;
1N/A
1N/Aour $VERSION = 0.06;
1N/A
1N/A@EXPORT_OK = qw(get reftype);
1N/A@EXPORT = ();
1N/A%EXPORT_TAGS = (ALL => [@EXPORT, @EXPORT_OK]);
1N/A
1N/Ause strict;
1N/A
1N/Asub croak {
1N/A require Carp;
1N/A goto &Carp::croak;
1N/A}
1N/A
1N/Asub carp {
1N/A require Carp;
1N/A goto &Carp::carp;
1N/A}
1N/A
1N/A## forward declaration(s) rather than wrapping the bootstrap call in BEGIN{}
1N/A#sub reftype ($) ;
1N/A#sub _fetch_attrs ($) ;
1N/A#sub _guess_stash ($) ;
1N/A#sub _modify_attrs ;
1N/A#sub _warn_reserved () ;
1N/A#
1N/A# The extra trips through newATTRSUB in the interpreter wipe out any savings
1N/A# from avoiding the BEGIN block. Just do the bootstrap now.
1N/ABEGIN { bootstrap attributes }
1N/A
1N/Asub import {
1N/A @_ > 2 && ref $_[2] or do {
1N/A require Exporter;
1N/A goto &Exporter::import;
1N/A };
1N/A my (undef,$home_stash,$svref,@attrs) = @_;
1N/A
1N/A my $svtype = uc reftype($svref);
1N/A my $pkgmeth;
1N/A $pkgmeth = UNIVERSAL::can($home_stash, "MODIFY_${svtype}_ATTRIBUTES")
1N/A if defined $home_stash && $home_stash ne '';
1N/A my @badattrs;
1N/A if ($pkgmeth) {
1N/A my @pkgattrs = _modify_attrs($svref, @attrs);
1N/A @badattrs = $pkgmeth->($home_stash, $svref, @attrs);
1N/A if (!@badattrs && @pkgattrs) {
1N/A return unless _warn_reserved;
1N/A @pkgattrs = grep { m/\A[[:lower:]]+(?:\z|\()/ } @pkgattrs;
1N/A if (@pkgattrs) {
1N/A for my $attr (@pkgattrs) {
1N/A $attr =~ s/\(.+\z//s;
1N/A }
1N/A my $s = ((@pkgattrs == 1) ? '' : 's');
1N/A carp "$svtype package attribute$s " .
1N/A "may clash with future reserved word$s: " .
1N/A join(' : ' , @pkgattrs);
1N/A }
1N/A }
1N/A }
1N/A else {
1N/A @badattrs = _modify_attrs($svref, @attrs);
1N/A }
1N/A if (@badattrs) {
1N/A croak "Invalid $svtype attribute" .
1N/A (( @badattrs == 1 ) ? '' : 's') .
1N/A ": " .
1N/A join(' : ', @badattrs);
1N/A }
1N/A}
1N/A
1N/Asub get ($) {
1N/A @_ == 1 && ref $_[0] or
1N/A croak 'Usage: '.__PACKAGE__.'::get $ref';
1N/A my $svref = shift;
1N/A my $svtype = uc reftype $svref;
1N/A my $stash = _guess_stash $svref;
1N/A $stash = caller unless defined $stash;
1N/A my $pkgmeth;
1N/A $pkgmeth = UNIVERSAL::can($stash, "FETCH_${svtype}_ATTRIBUTES")
1N/A if defined $stash && $stash ne '';
1N/A return $pkgmeth ?
1N/A (_fetch_attrs($svref), $pkgmeth->($stash, $svref)) :
1N/A (_fetch_attrs($svref))
1N/A ;
1N/A}
1N/A
1N/Asub require_version { goto &UNIVERSAL::VERSION }
1N/A
1N/A1;
1N/A__END__
1N/A#The POD goes here
1N/A
1N/A=head1 NAME
1N/A
1N/Aattributes - get/set subroutine or variable attributes
1N/A
1N/A=head1 SYNOPSIS
1N/A
1N/A sub foo : method ;
1N/A my ($x,@y,%z) : Bent = 1;
1N/A my $s = sub : method { ... };
1N/A
1N/A use attributes (); # optional, to get subroutine declarations
1N/A my @attrlist = attributes::get(\&foo);
1N/A
1N/A use attributes 'get'; # import the attributes::get subroutine
1N/A my @attrlist = get \&foo;
1N/A
1N/A=head1 DESCRIPTION
1N/A
1N/ASubroutine declarations and definitions may optionally have attribute lists
1N/Aassociated with them. (Variable C<my> declarations also may, but see the
1N/Awarning below.) Perl handles these declarations by passing some information
1N/Aabout the call site and the thing being declared along with the attribute
1N/Alist to this module. In particular, the first example above is equivalent to
1N/Athe following:
1N/A
1N/A use attributes __PACKAGE__, \&foo, 'method';
1N/A
1N/AThe second example in the synopsis does something equivalent to this:
1N/A
1N/A use attributes ();
1N/A my ($x,@y,%z);
1N/A attributes::->import(__PACKAGE__, \$x, 'Bent');
1N/A attributes::->import(__PACKAGE__, \@y, 'Bent');
1N/A attributes::->import(__PACKAGE__, \%z, 'Bent');
1N/A ($x,@y,%z) = 1;
1N/A
1N/AYes, that's a lot of expansion.
1N/A
1N/AB<WARNING>: attribute declarations for variables are still evolving.
1N/AThe semantics and interfaces of such declarations could change in
1N/Afuture versions. They are present for purposes of experimentation
1N/Awith what the semantics ought to be. Do not rely on the current
1N/Aimplementation of this feature.
1N/A
1N/AThere are only a few attributes currently handled by Perl itself (or
1N/Adirectly by this module, depending on how you look at it.) However,
1N/Apackage-specific attributes are allowed by an extension mechanism.
1N/A(See L<"Package-specific Attribute Handling"> below.)
1N/A
1N/AThe setting of subroutine attributes happens at compile time.
1N/AVariable attributes in C<our> declarations are also applied at compile time.
1N/AHowever, C<my> variables get their attributes applied at run-time.
1N/AThis means that you have to I<reach> the run-time component of the C<my>
1N/Abefore those attributes will get applied. For example:
1N/A
1N/A my $x : Bent = 42 if 0;
1N/A
1N/Awill neither assign 42 to $x I<nor> will it apply the C<Bent> attribute
1N/Ato the variable.
1N/A
1N/AAn attempt to set an unrecognized attribute is a fatal error. (The
1N/Aerror is trappable, but it still stops the compilation within that
1N/AC<eval>.) Setting an attribute with a name that's all lowercase
1N/Aletters that's not a built-in attribute (such as "foo") will result in
1N/Aa warning with B<-w> or C<use warnings 'reserved'>.
1N/A
1N/A=head2 Built-in Attributes
1N/A
1N/AThe following are the built-in attributes for subroutines:
1N/A
1N/A=over 4
1N/A
1N/A=item locked
1N/A
1N/AB<5.005 threads only! The use of the "locked" attribute currently
1N/Aonly makes sense if you are using the deprecated "Perl 5.005 threads"
1N/Aimplementation of threads.>
1N/A
1N/ASetting this attribute is only meaningful when the subroutine or
1N/Amethod is to be called by multiple threads. When set on a method
1N/Asubroutine (i.e., one marked with the B<method> attribute below),
1N/APerl ensures that any invocation of it implicitly locks its first
1N/Aargument before execution. When set on a non-method subroutine,
1N/APerl ensures that a lock is taken on the subroutine itself before
1N/Aexecution. The semantics of the lock are exactly those of one
1N/Aexplicitly taken with the C<lock> operator immediately after the
1N/Asubroutine is entered.
1N/A
1N/A=item method
1N/A
1N/AIndicates that the referenced subroutine is a method.
1N/AThis has a meaning when taken together with the B<locked> attribute,
1N/Aas described there. It also means that a subroutine so marked
1N/Awill not trigger the "Ambiguous call resolved as CORE::%s" warning.
1N/A
1N/A=item lvalue
1N/A
1N/AIndicates that the referenced subroutine is a valid lvalue and can
1N/Abe assigned to. The subroutine must return a modifiable value such
1N/Aas a scalar variable, as described in L<perlsub>.
1N/A
1N/A=back
1N/A
1N/AFor global variables there is C<unique> attribute: see L<perlfunc/our>.
1N/A
1N/A=head2 Available Subroutines
1N/A
1N/AThe following subroutines are available for general use once this module
1N/Ahas been loaded:
1N/A
1N/A=over 4
1N/A
1N/A=item get
1N/A
1N/AThis routine expects a single parameter--a reference to a
1N/Asubroutine or variable. It returns a list of attributes, which may be
1N/Aempty. If passed invalid arguments, it uses die() (via L<Carp::croak|Carp>)
1N/Ato raise a fatal exception. If it can find an appropriate package name
1N/Afor a class method lookup, it will include the results from a
1N/AC<FETCH_I<type>_ATTRIBUTES> call in its return list, as described in
1N/AL<"Package-specific Attribute Handling"> below.
1N/AOtherwise, only L<built-in attributes|"Built-in Attributes"> will be returned.
1N/A
1N/A=item reftype
1N/A
1N/AThis routine expects a single parameter--a reference to a subroutine or
1N/Avariable. It returns the built-in type of the referenced variable,
1N/Aignoring any package into which it might have been blessed.
1N/AThis can be useful for determining the I<type> value which forms part of
1N/Athe method names described in L<"Package-specific Attribute Handling"> below.
1N/A
1N/A=back
1N/A
1N/ANote that these routines are I<not> exported by default.
1N/A
1N/A=head2 Package-specific Attribute Handling
1N/A
1N/AB<WARNING>: the mechanisms described here are still experimental. Do not
1N/Arely on the current implementation. In particular, there is no provision
1N/Afor applying package attributes to 'cloned' copies of subroutines used as
1N/Aclosures. (See L<perlref/"Making References"> for information on closures.)
1N/APackage-specific attribute handling may change incompatibly in a future
1N/Arelease.
1N/A
1N/AWhen an attribute list is present in a declaration, a check is made to see
1N/Awhether an attribute 'modify' handler is present in the appropriate package
1N/A(or its @ISA inheritance tree). Similarly, when C<attributes::get> is
1N/Acalled on a valid reference, a check is made for an appropriate attribute
1N/A'fetch' handler. See L<"EXAMPLES"> to see how the "appropriate package"
1N/Adetermination works.
1N/A
1N/AThe handler names are based on the underlying type of the variable being
1N/Adeclared or of the reference passed. Because these attributes are
1N/Aassociated with subroutine or variable declarations, this deliberately
1N/Aignores any possibility of being blessed into some package. Thus, a
1N/Asubroutine declaration uses "CODE" as its I<type>, and even a blessed
1N/Ahash reference uses "HASH" as its I<type>.
1N/A
1N/AThe class methods invoked for modifying and fetching are these:
1N/A
1N/A=over 4
1N/A
1N/A=item FETCH_I<type>_ATTRIBUTES
1N/A
1N/AThis method receives a single argument, which is a reference to the
1N/Avariable or subroutine for which package-defined attributes are desired.
1N/AThe expected return value is a list of associated attributes.
1N/AThis list may be empty.
1N/A
1N/A=item MODIFY_I<type>_ATTRIBUTES
1N/A
1N/AThis method is called with two fixed arguments, followed by the list of
1N/Aattributes from the relevant declaration. The two fixed arguments are
1N/Athe relevant package name and a reference to the declared subroutine or
1N/Avariable. The expected return value is a list of attributes which were
1N/Anot recognized by this handler. Note that this allows for a derived class
1N/Ato delegate a call to its base class, and then only examine the attributes
1N/Awhich the base class didn't already handle for it.
1N/A
1N/AThe call to this method is currently made I<during> the processing of the
1N/Adeclaration. In particular, this means that a subroutine reference will
1N/Aprobably be for an undefined subroutine, even if this declaration is
1N/Aactually part of the definition.
1N/A
1N/A=back
1N/A
1N/ACalling C<attributes::get()> from within the scope of a null package
1N/Adeclaration C<package ;> for an unblessed variable reference will
1N/Anot provide any starting package name for the 'fetch' method lookup.
1N/AThus, this circumstance will not result in a method call for package-defined
1N/Aattributes. A named subroutine knows to which symbol table entry it belongs
1N/A(or originally belonged), and it will use the corresponding package.
1N/AAn anonymous subroutine knows the package name into which it was compiled
1N/A(unless it was also compiled with a null package declaration), and so it
1N/Awill use that package name.
1N/A
1N/A=head2 Syntax of Attribute Lists
1N/A
1N/AAn attribute list is a sequence of attribute specifications, separated by
1N/Awhitespace or a colon (with optional whitespace).
1N/AEach attribute specification is a simple
1N/Aname, optionally followed by a parenthesised parameter list.
1N/AIf such a parameter list is present, it is scanned past as for the rules
1N/Afor the C<q()> operator. (See L<perlop/"Quote and Quote-like Operators">.)
1N/AThe parameter list is passed as it was found, however, and not as per C<q()>.
1N/A
1N/ASome examples of syntactically valid attribute lists:
1N/A
1N/A switch(10,foo(7,3)) : expensive
1N/A Ugly('\(") :Bad
1N/A _5x5
1N/A locked method
1N/A
1N/ASome examples of syntactically invalid attribute lists (with annotation):
1N/A
1N/A switch(10,foo() # ()-string not balanced
1N/A Ugly('(') # ()-string not balanced
1N/A 5x5 # "5x5" not a valid identifier
1N/A Y2::north # "Y2::north" not a simple identifier
1N/A foo + bar # "+" neither a colon nor whitespace
1N/A
1N/A=head1 EXPORTS
1N/A
1N/A=head2 Default exports
1N/A
1N/ANone.
1N/A
1N/A=head2 Available exports
1N/A
1N/AThe routines C<get> and C<reftype> are exportable.
1N/A
1N/A=head2 Export tags defined
1N/A
1N/AThe C<:ALL> tag will get all of the above exports.
1N/A
1N/A=head1 EXAMPLES
1N/A
1N/AHere are some samples of syntactically valid declarations, with annotation
1N/Aas to how they resolve internally into C<use attributes> invocations by
1N/Aperl. These examples are primarily useful to see how the "appropriate
1N/Apackage" is found for the possible method lookups for package-defined
1N/Aattributes.
1N/A
1N/A=over 4
1N/A
1N/A=item 1.
1N/A
1N/ACode:
1N/A
1N/A package Canine;
1N/A package Dog;
1N/A my Canine $spot : Watchful ;
1N/A
1N/AEffect:
1N/A
1N/A use attributes ();
1N/A attributes::->import(Canine => \$spot, "Watchful");
1N/A
1N/A=item 2.
1N/A
1N/ACode:
1N/A
1N/A package Felis;
1N/A my $cat : Nervous;
1N/A
1N/AEffect:
1N/A
1N/A use attributes ();
1N/A attributes::->import(Felis => \$cat, "Nervous");
1N/A
1N/A=item 3.
1N/A
1N/ACode:
1N/A
1N/A package X;
1N/A sub foo : locked ;
1N/A
1N/AEffect:
1N/A
1N/A use attributes X => \&foo, "locked";
1N/A
1N/A=item 4.
1N/A
1N/ACode:
1N/A
1N/A package X;
1N/A sub Y::x : locked { 1 }
1N/A
1N/AEffect:
1N/A
1N/A use attributes Y => \&Y::x, "locked";
1N/A
1N/A=item 5.
1N/A
1N/ACode:
1N/A
1N/A package X;
1N/A sub foo { 1 }
1N/A
1N/A package Y;
1N/A BEGIN { *bar = \&X::foo; }
1N/A
1N/A package Z;
1N/A sub Y::bar : locked ;
1N/A
1N/AEffect:
1N/A
1N/A use attributes X => \&X::foo, "locked";
1N/A
1N/A=back
1N/A
1N/AThis last example is purely for purposes of completeness. You should not
1N/Abe trying to mess with the attributes of something in a package that's
1N/Anot your own.
1N/A
1N/A=head1 SEE ALSO
1N/A
1N/AL<perlsub/"Private Variables via my()"> and
1N/AL<perlsub/"Subroutine Attributes"> for details on the basic declarations;
1N/AL<attrs> for the obsolescent form of subroutine attribute specification
1N/Awhich this module replaces;
1N/AL<perlfunc/use> for details on the normal invocation mechanism.
1N/A
1N/A=cut
1N/A