line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package MooseX::Params; |
2
|
|
|
|
|
|
|
{ |
3
|
|
|
|
|
|
|
$MooseX::Params::VERSION = '0.010'; |
4
|
|
|
|
|
|
|
} |
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
# ABSTRACT: Subroutine signature declaration via attributes |
7
|
|
|
|
|
|
|
|
8
|
7
|
|
|
7
|
|
605412
|
use strict; |
|
7
|
|
|
|
|
16
|
|
|
7
|
|
|
|
|
233
|
|
9
|
7
|
|
|
7
|
|
37
|
use warnings; |
|
7
|
|
|
|
|
14
|
|
|
7
|
|
|
|
|
172
|
|
10
|
7
|
|
|
7
|
|
167
|
use 5.010; |
|
7
|
|
|
|
|
25
|
|
|
7
|
|
|
|
|
238
|
|
11
|
7
|
|
|
7
|
|
4147
|
use MooseX::Params::Util; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
use MooseX::Params::TypeConstraints; |
13
|
|
|
|
|
|
|
use Carp qw(croak); |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
sub import |
16
|
|
|
|
|
|
|
{ |
17
|
|
|
|
|
|
|
my @attrs = qw(Args BuildArgs CheckArgs Returns ReturnsScalar); |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
my @handlers; |
20
|
|
|
|
|
|
|
foreach my $attribute (@attrs) |
21
|
|
|
|
|
|
|
{ |
22
|
|
|
|
|
|
|
push @handlers, "CODE:$attribute", |
23
|
|
|
|
|
|
|
MooseX::Params::Util::prepare_attribute_handler($attribute); |
24
|
|
|
|
|
|
|
} |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
require Attribute::Lexical; |
27
|
|
|
|
|
|
|
Attribute::Lexical->import(@handlers); |
28
|
|
|
|
|
|
|
} |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
### ATTRIBUTES ### |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
sub Args |
33
|
|
|
|
|
|
|
{ |
34
|
|
|
|
|
|
|
my ($method, $data) = @_; |
35
|
|
|
|
|
|
|
my $parameters = MooseX::Params::Util::inflate_parameters($method->package_name, $data); |
36
|
|
|
|
|
|
|
$method->parameters($parameters); |
37
|
|
|
|
|
|
|
} |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
sub BuildArgs |
40
|
|
|
|
|
|
|
{ |
41
|
|
|
|
|
|
|
my ($method, $data) = @_; |
42
|
|
|
|
|
|
|
$data = "_buildargs_" . $method->name unless $data; |
43
|
|
|
|
|
|
|
$method->buildargs($data); |
44
|
|
|
|
|
|
|
} |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
sub CheckArgs |
47
|
|
|
|
|
|
|
{ |
48
|
|
|
|
|
|
|
my ($method, $data) = @_; |
49
|
|
|
|
|
|
|
$data = "_checkargs_" . $method->name unless $data; |
50
|
|
|
|
|
|
|
$method->checkargs($data); |
51
|
|
|
|
|
|
|
} |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
sub Returns |
54
|
|
|
|
|
|
|
{ |
55
|
|
|
|
|
|
|
my ($method, $data) = @_; |
56
|
|
|
|
|
|
|
croak "Empty return value constraint not allowed" unless $data; |
57
|
|
|
|
|
|
|
$method->returns($data); |
58
|
|
|
|
|
|
|
} |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
sub ReturnsScalar |
61
|
|
|
|
|
|
|
{ |
62
|
|
|
|
|
|
|
my ($method, $data) = @_; |
63
|
|
|
|
|
|
|
$method->returns_scalar($data); |
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
1; |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
__END__ |
70
|
|
|
|
|
|
|
=pod |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
=for :stopwords Peter Shangov TODO invocant isa metaroles metarole multimethods sourcecode |
73
|
|
|
|
|
|
|
backwards buildargs checkargs slurpy preprocess |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
=head1 NAME |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
MooseX::Params - Subroutine signature declaration via attributes |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
=head1 VERSION |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
version 0.010 |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
=head1 SYNOPSIS |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
# use Moose types for validation |
86
|
|
|
|
|
|
|
# positional arguments are by default required |
87
|
|
|
|
|
|
|
sub add :Args(Int first, Int second) { |
88
|
|
|
|
|
|
|
return $_{first} + $_{second}; |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
say add(2, 3); # 5 |
92
|
|
|
|
|
|
|
say add(2); # error |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
# @_ still works: you can ignore %_ if you want to |
95
|
|
|
|
|
|
|
sub add2 :Args(Int first, Int second) { |
96
|
|
|
|
|
|
|
my ($first, $second) = @_; |
97
|
|
|
|
|
|
|
return $first + $second; |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
say add2(2, 3); # 5 |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
# '&' before a type constraint enables coercion |
103
|
|
|
|
|
|
|
subtype 'HexNum', as 'Str', where { /[a-f0-9]/i }; |
104
|
|
|
|
|
|
|
coerce 'Int', from 'HexNum', via { hex $_ }; |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
sub add3 :Args(&Int first, &Int second) { |
107
|
|
|
|
|
|
|
return $_{first} + $_{second}; |
108
|
|
|
|
|
|
|
} |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
say add3('A', 'B'); # 21 |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
# slurpy arguments consume the remainder of @_ |
113
|
|
|
|
|
|
|
sub sum :Args(ArrayRef *values) { |
114
|
|
|
|
|
|
|
my $sum = 0; |
115
|
|
|
|
|
|
|
my @values = @{$_{values}}; |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
foreach my $value (@values) { |
118
|
|
|
|
|
|
|
$sum += $value; |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
return $sum; |
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
say sum(2, 3, 4, 5); # 14 |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
# 'all' is optional: |
126
|
|
|
|
|
|
|
# if not present search the text within a file and return 1 if found, 0 if not |
127
|
|
|
|
|
|
|
# if present search the text and return number of lines in which text is found |
128
|
|
|
|
|
|
|
sub search :Args(text, fh, all?) { |
129
|
|
|
|
|
|
|
my $cnt = 0; |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
while (my $line = $_{fh}->getline) { |
132
|
|
|
|
|
|
|
if ( index($line, $_{text}) > -1 ) { |
133
|
|
|
|
|
|
|
return 1 if not $_{all}; |
134
|
|
|
|
|
|
|
$cnt++; |
135
|
|
|
|
|
|
|
} |
136
|
|
|
|
|
|
|
} |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
return $cnt; |
139
|
|
|
|
|
|
|
} |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
# named arguments |
142
|
|
|
|
|
|
|
sub foo :Args(a, :b) { |
143
|
|
|
|
|
|
|
return $_{a} + $_{b} * 2; |
144
|
|
|
|
|
|
|
} |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
# say foo( 3, b => 2 ); # 7 |
147
|
|
|
|
|
|
|
# say foo(4, 9); # error |
148
|
|
|
|
|
|
|
# say foo(2); # error |
149
|
|
|
|
|
|
|
# say foo(2, 3, 4); # error |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
# parameters are immutable, assign to a variable to edit |
152
|
|
|
|
|
|
|
sub trim :Args(Str string) { |
153
|
|
|
|
|
|
|
my $string = $_{string}; |
154
|
|
|
|
|
|
|
$string =~ s/^\s*//; |
155
|
|
|
|
|
|
|
$string =~ s/\s*$//; |
156
|
|
|
|
|
|
|
return $string; |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
# parameters can have simple defaults |
160
|
|
|
|
|
|
|
sub find_clothes :Args(:size = 'medium', :color = 'white') { ... } |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
# or builders for more complex tasks |
163
|
|
|
|
|
|
|
sub find_clothes :Args( |
164
|
|
|
|
|
|
|
:size = _build_param_size, |
165
|
|
|
|
|
|
|
:color = _build_param_color, |
166
|
|
|
|
|
|
|
:height = 170 ) |
167
|
|
|
|
|
|
|
{ ... } |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
sub _build_param_color { |
170
|
|
|
|
|
|
|
return (qw(red green blue))[ int( rand 3 ) ]; |
171
|
|
|
|
|
|
|
} |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
# you can access all other parameters within a builder |
174
|
|
|
|
|
|
|
sub _build_param_size { |
175
|
|
|
|
|
|
|
return $_{height} > 200 ? 'large' : 'medium'; |
176
|
|
|
|
|
|
|
} |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
# preprocess @_ with buildargs |
179
|
|
|
|
|
|
|
sub process_template |
180
|
|
|
|
|
|
|
:Args(input, output, params) |
181
|
|
|
|
|
|
|
:BuildArgs(_buildargs_process_template) |
182
|
|
|
|
|
|
|
{ |
183
|
|
|
|
|
|
|
say "open $_{input}"; |
184
|
|
|
|
|
|
|
say "replace " . Dumper $_{params}; |
185
|
|
|
|
|
|
|
say "save $_{output}"; |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
# if 'output' is not provided, deduct it from input filename |
189
|
|
|
|
|
|
|
sub _buildargs_process_template { |
190
|
|
|
|
|
|
|
if (@_ == 2) { |
191
|
|
|
|
|
|
|
my ($input, $params) = @_; |
192
|
|
|
|
|
|
|
my $output = $input; |
193
|
|
|
|
|
|
|
substr($output, -4, 4, "html"); |
194
|
|
|
|
|
|
|
return $input, $output, $params; |
195
|
|
|
|
|
|
|
} else { |
196
|
|
|
|
|
|
|
return @_; |
197
|
|
|
|
|
|
|
} |
198
|
|
|
|
|
|
|
} |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
my %data = ( |
201
|
|
|
|
|
|
|
fname => "Foo", |
202
|
|
|
|
|
|
|
lname => "Bar", |
203
|
|
|
|
|
|
|
); |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
process_template("index.tmpl", \%data); |
206
|
|
|
|
|
|
|
# open index.tmpl |
207
|
|
|
|
|
|
|
# replace {"lname" => "Bar", "fname" => "Foo"} |
208
|
|
|
|
|
|
|
# save index.html |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
process_template("from.tmpl", "to.html", \%data); |
211
|
|
|
|
|
|
|
# open from.tmpl |
212
|
|
|
|
|
|
|
# replace {"lname" => "Bar", "fname" => "Foo"} |
213
|
|
|
|
|
|
|
# save to.html |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
# additional validation with checkargs |
216
|
|
|
|
|
|
|
sub process_person |
217
|
|
|
|
|
|
|
:Args(:first_name!, :last_name!, :country!, :ssn?) |
218
|
|
|
|
|
|
|
:CheckArgs # shortcut for :CheckArgs(_checkargs_${subname}) |
219
|
|
|
|
|
|
|
{ ... } |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
sub _checkargs_process_person { |
222
|
|
|
|
|
|
|
if ( $_{country} eq 'USA' ) { |
223
|
|
|
|
|
|
|
die 'All US residents must have an SSN' unless $_{ssn}; |
224
|
|
|
|
|
|
|
} |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
# return value validation |
228
|
|
|
|
|
|
|
sub sum :Args(a, b) :Returns(Num) { ... } |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
# validate non-scalar return values |
231
|
|
|
|
|
|
|
sub get_data :Returns(Array) { qw(foo bar baz) } |
232
|
|
|
|
|
|
|
my ($foo, $bar, $baz) = get_data(); |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
# force special behavior in sclar context |
235
|
|
|
|
|
|
|
sub get_winners :Returns(Array) :ReturnsScalar(First) { |
236
|
|
|
|
|
|
|
my @ordered_winners = ...; |
237
|
|
|
|
|
|
|
return @ordered_winners; |
238
|
|
|
|
|
|
|
} |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
my $first_place = get_winners(); |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
# in a class |
243
|
|
|
|
|
|
|
package User; |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
use Moose; |
246
|
|
|
|
|
|
|
use MooseX::Params; |
247
|
|
|
|
|
|
|
use DateTime; |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
extends 'Person'; |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
has 'password' => ( |
252
|
|
|
|
|
|
|
is => 'rw', |
253
|
|
|
|
|
|
|
isa => 'Str', |
254
|
|
|
|
|
|
|
); |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
has 'last_login' => ( |
257
|
|
|
|
|
|
|
is => 'rw', |
258
|
|
|
|
|
|
|
isa => 'DateTime', |
259
|
|
|
|
|
|
|
); |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
# note the shortcut invocant syntax |
262
|
|
|
|
|
|
|
sub login :Args(self: Str pw) :Returns(Bool) { |
263
|
|
|
|
|
|
|
return 0 if $_{pw} ne $_{self}->password; |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
$_{self}->last_login( DateTime->now() ); |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
return 1; |
268
|
|
|
|
|
|
|
} |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
=head1 DESCRIPTION |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
This module provides an attributes-based interface for parameter processing in Perl 5. For the original rationale see L<http://mechanicalrevolution.com/blog/parameter_apocalypse.html>. |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
The proposed interface is based on three cornerstone propositions: |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
=over 4 |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
=item * |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
Parameters are first-class entities that deserve their own meta protocol. A common meta protocol may be used by different implementations (e.g. this library, L<MooseX::Params::Validate>, L<MooseX::Method::Sigantures>) and allow them to coexist better. It is also the necessary foundation for more advanced features such as multimethods and extended role validation. |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
=item * |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
Parameters should benefit from the same power and flexibility that L<Moose> attributes have. This module implements most of this functionality, including laziness. |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
=item * |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
The global variable C<%_> is used as a placeholder for processed parameters. It is considered by the author of this module as an intuitive alternative to manual unpacking of C<@_> while staying within the limits of traditional Perl syntax. |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
=back |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
=head1 USE WITH CARE |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
This is still an experimental module and is subject to backwards incompatible changes. It is barely tested and most certainly has serious lurking bugs, has a lot of room for performance optimizations, and its error reporting could be vastly improved. |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
=head1 BACKWARDS INCOMPATIBLE CHANGES |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
Version 0.005 removes the interface based on the C<method> keyword, and retains only the attributes-based interface. Also, C<$self> is no longer localized inside methods, you must use C<$_{self}> instead. |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
=head1 SIGNATURE SYNTAX |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
Signatures are declared with the C<:Args> attribute. All parsed parameters are made available inside your subroutine within the special C<%_> hash. All elements of C<%_> are read-only, and an attempt to modify them will throw an exception. An attempt to use a hash element which is not a valid parameter name for this subroutine will also throw an exception. C<@_> is not affected by the use of signatures, so you can still use it to manually unpack arguments if you want to. |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
=head2 Parameter names |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
Parameter names can by any valid perl identifiers, and they are separated by commas. |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
sub rank :Args(first, second, third) { |
309
|
|
|
|
|
|
|
say "$_{first} is first, $_{second} is second, and $_{third} is third"; |
310
|
|
|
|
|
|
|
} |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
=head2 Invocant |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
Method signatures can specify their invocant as the first parameter, followed by a colon: |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
sub rank :Args(self: first, second, third) { |
317
|
|
|
|
|
|
|
my $competition = $_{self}->competition; |
318
|
|
|
|
|
|
|
... |
319
|
|
|
|
|
|
|
} |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
=head2 Type constraints |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
Moose type constraints may be used for validation. |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
sub rank :Args(Str first, Str second, Str third) { ... } |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
An ampersand before a type enables coercion for this type. |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
subtype 'Name' ...; |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
coerce 'Name', from 'Str', via { ... }; |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
sub rank :Args(&Name first, &Name second, &Name third) { ... } |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
=head2 Positional and named parameters |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
Parameters are by default positional. |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
sub rank :Args(first, second, third) { ... } |
340
|
|
|
|
|
|
|
# rank('Peter', 'George', 'John') |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
Named parameters are prefixed by a colon. |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
sub rank :Args(:first, :second, :third) { ... } |
345
|
|
|
|
|
|
|
# rank( first => 'Peter', second => 'George', third => 'John') |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
Named parameters may be passed by one name and accessed by another. |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
sub rank :Args(:gold(first), :silver(second), :bronze(third)) { |
350
|
|
|
|
|
|
|
say "$_{first} is first, $_{second} is second, and $_{third} is third"; |
351
|
|
|
|
|
|
|
} |
352
|
|
|
|
|
|
|
# rank( gold => 'Peter', silver => 'George', bronze => 'John') |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
Positional and named parameters may be mixed, but positional parameters must come first. |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
sub rank :Args(first, :second, :third) { |
357
|
|
|
|
|
|
|
say "$_{first} is first, $_{second} is second, and $_{third} is third"; |
358
|
|
|
|
|
|
|
} |
359
|
|
|
|
|
|
|
# rank( 'Peter', second => 'George', third => 'John') |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
=head2 Required parameters |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
An exclamation mark (C<!>) after the name denotes a required parameter, and a question mark (C<?>) denotes an optional parameter. |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
sub rank :Args(first!, second?, third?) { ... } |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
Positional parameters are by default required, and named parameters are by default optional. |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
=head2 Slurpy parameters |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
A parameter prefixed by an asterisk (C<*>) is slurpy, i.e. it consumes the remainder of the argument list. Slurpy parameters must come last in the signature. |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
sub rank :Args(ArrayRef *winners) { |
374
|
|
|
|
|
|
|
say "$_{winners}[0] is first, $_{winners}[1] is second, and $_{winners}[2] is third"; |
375
|
|
|
|
|
|
|
} |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
=head2 Default values |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
A parameter may be given a simple default value, which can be either a quoted string or an unsigned integer. |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
sub rank :Args(first = 'Peter', second = 'George', third = 'John') { ... } |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
You may use either single or double quotes to quote a string, but they will always be interpreted as if single quotes were used. |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
=head2 Builders |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
Where a default value is not sufficient, parameters may specify builders instead. A builder is a subroutine whose return value will be used as default value for the parameter. |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
sub rank :Args(ArrayRef *winners = calculate_winners) { ... } |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
sub calculate_winners { ... } |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
The name of the builder may be optionally followed by a pair of parenthesis. |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
sub rank :Args(ArrayRef *winners = calculate_winners()) { ... } |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
All builders are executed lazily, i.e. the first time the parameter is accessed. If a parameter name is followed by an equal sign, but neither a default value nor a builder is specified, it is assumed that the parameter has a builder named C<_build_param_${name}>. In this case the equal sign may also be placed before the name of the parameter. |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
sub rank :Args(ArrayRef *winners=) { ... } |
400
|
|
|
|
|
|
|
# is equivalent to |
401
|
|
|
|
|
|
|
sub rank :Args(ArrayRef =*winners) { ... } |
402
|
|
|
|
|
|
|
# is equivalent to |
403
|
|
|
|
|
|
|
sub rank :Args(ArrayRef *winners = _build_param_winners) { ... } |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
sub _build_param_winners { ... } |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
Within a parameter builder, you can access all other parameters in the C<%_> hash. |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
sub connect :Args(=:dbh, :host, :port, :database) { ... } |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
sub _build_param_dbh { |
412
|
|
|
|
|
|
|
return DBI->connect("dbi:mysql:host=$_{host};port=$_{port};database=$_{database}"); |
413
|
|
|
|
|
|
|
} |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
=head1 BUILDARGS AND CHECKARGS |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
=head2 BuildArgs |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
The C<BuildArgs> attribute allows you to specify a subroutine that will be used to preprocess your arguments before they are validated against the supplied signature. It can be used as to create poor man's multimethods by coercing different types of arguments to a single signature. It is somewhat similar to what Moose's C<BUILDARGS> does for class constructors. |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
sub rank |
422
|
|
|
|
|
|
|
:Args(:first :second :third) |
423
|
|
|
|
|
|
|
:BuildArgs(_buildargs_rank) |
424
|
|
|
|
|
|
|
{ ... } |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
# allow positional parameters as well |
427
|
|
|
|
|
|
|
sub _buildargs_rank { |
428
|
|
|
|
|
|
|
if (@_ == 3) { |
429
|
|
|
|
|
|
|
return first => $_[0], second => $_[1], third => $_[2]; |
430
|
|
|
|
|
|
|
} else { |
431
|
|
|
|
|
|
|
return @_; |
432
|
|
|
|
|
|
|
} |
433
|
|
|
|
|
|
|
} |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
If C<BuildArgs> is specified without a subroutine name, C<_buildargs_${subname}> will be assumed. |
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
sub rank :Args(...) :BuildArgs { ... } |
438
|
|
|
|
|
|
|
# is equivalent to |
439
|
|
|
|
|
|
|
sub rank :Args(...) :BuildArgs(_buildargs_rank) { ... } |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
=head2 CheckArgs |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
The C<CheckArgs> attribute allows you to specify a subroutine that will be used to perform additional validation after the arguments are validated against the supplied signature. It can be used to perform more complex validations that cannot be expressed in a simple signature. It is somewhat similar to what Moose's C<BUILD> does for class constructors. Inside a C<CheckArgs> subroutine you can access the processed parameters in the C<%_> hash. |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
sub rank |
446
|
|
|
|
|
|
|
:Args(:first :second :third) |
447
|
|
|
|
|
|
|
:CheckArgs(_checkargs_rank) |
448
|
|
|
|
|
|
|
{ ... } |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
# make sure names do not repeat |
451
|
|
|
|
|
|
|
sub _checkargs_rank { |
452
|
|
|
|
|
|
|
if ( |
453
|
|
|
|
|
|
|
($_{first} eq $_{second}) or |
454
|
|
|
|
|
|
|
($_{first} eq $_{third} ) or |
455
|
|
|
|
|
|
|
($_{second} eq $_{third} ) |
456
|
|
|
|
|
|
|
) { die "One player can only take one place!"; } |
457
|
|
|
|
|
|
|
} |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
If C<CheckArgs> is specified without a subroutine name, C<_checkargs_${subname}> will be assumed. |
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
sub rank :Args(...) :CheckArgs { ... } |
462
|
|
|
|
|
|
|
# is equivalent to |
463
|
|
|
|
|
|
|
sub rank :Args(...) :CheckArgs(_checkargs_rank) { ... } |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
=head1 RETURN VALUE VALIDATION |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
=head2 Returns |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
C<MooseX::Params> provids a basic mechanism for return value validation via the C<Returns> attribute. |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
sub add :Args(a, b) :Returns(Num) { return $_{a} + $_{b} } |
472
|
|
|
|
|
|
|
my $five = add(2,3); |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
Any Moose type name may be used as an arbument to C<Returns>. If your subroutine returns a list of values, you will need to use the special parametric types C<Array> and C<Hash>. They behave identically to C<ArrayRef> and C<HashRef>, except that they work with lists instead of references: |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
sub myreverse :Args(*items) :Returns(Array) { return reverse @{ $_{items} } } |
477
|
|
|
|
|
|
|
my @list = qw(foo bar baz); |
478
|
|
|
|
|
|
|
my @reversed = myreverse(@list); |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
Note that C<wantarray> inside subroutines that use C<Returns> will always return true (see below). |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
=head2 ReturnsScalar |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
Return value validation does not play well with context magic. If you return different values depending on context, validation will break. Therefore, subroutines that use C<Returns> are always evaluated in list context to obrain their return value. The C<ResultScalar> attribute allows you to explicitly change how your subroutine will behave in scalar context. It accepts one of four options: |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
=over |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
=item Count (default) |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
In scalar context return the number of items in the return value list. |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
=item First |
493
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
In scalar context return the first item in the return value list. |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
=item Last |
497
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
In scalar context return the last item in the return value list. |
499
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
=item ArrayRef |
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
In scalar context return a reference to the return value list. |
503
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
=back |
505
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
sub results :Returns(Array[MyApp::Object]) :ReturnsScalar(ArrayRef) { ... } |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
=head1 META CLASSES |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
C<MooseX::Params> provides method and parameter metaroles, please see their sourcecode for details: |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
=over 4 |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
=item * |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
L<MooseX::Params::Meta::Method> |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
=item * |
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
L<MooseX::Params::Meta::Parameter> |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
=back |
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
=head1 TODO |
525
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
=over 4 |
527
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
=item * |
529
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
return value validation (C<Returns> and C<ReturnsScalar>) |
531
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
=item * |
533
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
subroutine traits (C<Does>) |
535
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
=item * |
537
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
better error checking and reporting |
539
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
=item * |
541
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
improved performance |
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
=item * |
545
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
lightweight implementation without meta and magic |
547
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
=back |
549
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
Whether or not these features will be implemented depends mostly on the community response to the proposed API. Currently the best way to contribute to this module would be to provide feedback and commentary - the L<Moose> mailing list will be a good place for this. |
551
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
=head1 BUGS |
553
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
Plenty. Some of the known ones are: |
555
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
=over 4 |
557
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
=item * |
559
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
No checking for surplus arguments |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
=item * |
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
C<foreach my $value (@{$_{arrayref}})> attempts to modify C<$_{arrayref}> and triggers an exception |
565
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
=item * |
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
May be incompatible with other modules that provide attributes, including L<Perl6::Export::Attrs> |
569
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
=item * |
571
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
C<MooseX::Params::Meta::Method> is a class, should be a role |
573
|
|
|
|
|
|
|
|
574
|
|
|
|
|
|
|
=back |
575
|
|
|
|
|
|
|
|
576
|
|
|
|
|
|
|
=head1 SEE ALSO |
577
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
=over 4 |
579
|
|
|
|
|
|
|
|
580
|
|
|
|
|
|
|
=item * |
581
|
|
|
|
|
|
|
|
582
|
|
|
|
|
|
|
L<MooseX::Params::Validate> |
583
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
=item * |
585
|
|
|
|
|
|
|
|
586
|
|
|
|
|
|
|
L<MooseX::Method::Signatures> |
587
|
|
|
|
|
|
|
|
588
|
|
|
|
|
|
|
=back |
589
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
=head1 AUTHOR |
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
Peter Shangov <pshangov@yahoo.com> |
593
|
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
595
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
This software is copyright (c) 2012 by Peter Shangov. |
597
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
599
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
600
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
=cut |
602
|
|
|
|
|
|
|
|