File Coverage

blib/lib/Signature/Attribute/Checked.pm
Criterion Covered Total %
statement 6 7 85.7
branch n/a
condition n/a
subroutine 3 4 75.0
pod n/a
total 9 11 81.8


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Paul Evans, 2023 -- leonerd@leonerd.org.uk
5              
6             package Signature::Attribute::Checked 0.01;
7              
8 4     4   798083 use v5.14;
  4         33  
9 4     4   26 use warnings;
  4         8  
  4         506  
10              
11             require XSLoader;
12             XSLoader::load( __PACKAGE__, our $VERSION );
13              
14             =head1 NAME
15              
16             C - apply value constraint checks to subroutine parameters
17              
18             =head1 SYNOPSIS
19              
20             With L
21              
22             use v5.26;
23             use Sublike::Extended;
24             use Signature::Attribute::Checked;
25             use Types::Standard qw( Num );
26              
27             extended sub add ($x :Checked(Num), $y :Checked(Num)) {
28             return $x + $y;
29             }
30              
31             say add(10, 20); # this is fine
32              
33             say add("hello", "world"); # throws an exception
34              
35             =head1 DESCRIPTION
36              
37             This module provides a third-party subroutine parameter attribute via
38             L, which declares that values passed to a subroutine must
39             conform to a given constraint check.
40              
41             B The ability for sublike constructions to take third-party parameter
42             attributes is still new and highly experimental, and subject to much API
43             change in future. As a result, this module should be considered equally
44             experimental. Core perl's parser does not permit parameters to take
45             attributes. This ability must be requested specially; either by using
46             L, or perhaps enabled directly by some other sublike
47             keyword using the C infrastructure.
48              
49             Additionally, the behaviour provided by this module should be considered more
50             of a work-in-progress stepping stone. Ideally, constraint syntax ought
51             to be provided in a much more fundamental way by Perl itself, allowing it to
52             be used on C lexicals, class fields, and other places as well as
53             subroutine parameters. This module is more of a placeholder to allow some part
54             of that behaviour to be specified for subroutine parameters, while not getting
55             in the way of a more general, more powerful system being added in future.
56              
57             =head1 PARAMETER ATTRIBUTES
58              
59             =head2 :Checked
60              
61             extended sub f($x :Checked(EXPRESSION)) { ... }
62              
63             Declares that any value passed to the parameter at the time the subroutine is
64             called must conform to the constraint checker specified by the expression.
65             Attempts to pass a non-conforming value will throw an exception and the
66             subroutine body will not be invoked. Currently only scalar parameters are
67             supported.
68              
69             At compiletime, the string given by I is C'ed in scalar
70             context, and its result is stored as part of the subroutine's definition. The
71             expression must yield either an object reference, a code reference, or a
72             string containing the name of a package. In the case of an object or package,
73             a method called C must exist on it.
74              
75             If using a plain package name as a checker, be sure to quote package names so
76             it will not upset C.
77              
78             extended sub xyz ($x :Checked('CheckerPackage')) { ... }
79              
80             At runtime, this constraint checker is used every time an attempt is made to
81             call the function. The checker is used as the invocant for invoking a C
82             method, and the value for the parameter is passed as an argument. If the
83             method returns true, the call is allowed. If false, it is rejected with an
84             exception and the function body is not invoked.
85              
86             $ok = $checkerobj->check( $value ); # if an object
87              
88             $ok = $checkersub->( $value ); # if a code reference
89              
90             $ok = $checkerpkg->check( $value ); # if a package name
91              
92             (For performance reasons, the C method is actually resolved into a
93             function at compiletime when the C<:Checked> attribute is applied, and this
94             stored function is the one that is called at assignment time. If the method
95             itself is replaced later by globref assignment or other trickery, this updated
96             function will not be used.)
97              
98             As this is the interface supported by L, any constraint
99             object provided by that module is already supported here.
100              
101             use Types::Standard qw( Str Num );
102              
103             extended sub ghi ($x :Checked(Str), $y :Checked(Num)) { ... }
104              
105             It is not specified what order these checks are performed in. In particular,
106             if any parameter default expressions invoke any side-effects, it is
107             unspecified whether such side-effects will happen if a value passed for a
108             parameter fails its constraint check. Users should take care not to attempt to
109             invoke any side-effects during such expressions.
110              
111             Note further that these value checks are only performed once, at the time the
112             subroutine is invoked. Code within the body of the subroutine can freely
113             assign any other kind of value to the variable corresponding to a C<:Checked>
114             parameter without issue.
115              
116             extended sub foo ($n :Checked(Num)) {
117             $x = "seven"; # this is permitted
118             }
119              
120             =cut
121              
122             sub import
123             {
124 3     3   117 $^H{"Signature::Attribute::Checked/Checked"}++;
125             }
126              
127             sub unimport
128             {
129 0     0     delete $^H{"Signature::Attribute::Checked/Checked"};
130             }
131              
132             =head1 SEE ALSO
133              
134             =over 4
135              
136             =item *
137              
138             L - apply value constraint checks to C fields
139              
140             =back
141              
142             =head1 AUTHOR
143              
144             Paul Evans
145              
146             =cut
147              
148             0x55AA;