make 'method' default to attrs => ":method"
[p5sagit/Function-Parameters.git] / lib / Function / Parameters.pm
CommitLineData
7a63380c 1package Function::Parameters;
2
7dd35535 3use v5.14.0;
4
7a63380c 5use strict;
6use warnings;
7
db81d362 8use XSLoader;
9BEGIN {
5d0dba1f 10 our $VERSION = '0.05_03';
db81d362 11 XSLoader::load;
7a63380c 12}
13
db81d362 14use Carp qw(confess);
7a63380c 15
2d5cf47a 16sub _assert_valid_identifier {
17 my ($name, $with_dollar) = @_;
18 my $bonus = $with_dollar ? '\$' : '';
19 $name =~ /^${bonus}[^\W\d]\w*\z/
20 or confess qq{"$name" doesn't look like a valid identifier};
21}
22
b72eb6ee 23sub _assert_valid_attributes {
24 my ($attrs) = @_;
25 $attrs =~ /^\s*:\s*[^\W\d]\w*\s*(?:(?:\s|:\s*)[^\W\d]\w*\s*)*(?:\(|\z)/
26 or confess qq{"$attrs" doesn't look like valid attributes};
27}
28
125c067e 29my @bare_arms = qw(function method);
2d5cf47a 30my %type_map = (
31 function => { name => 'optional' },
7947f7ce 32 method => {
33 name => 'optional',
34 shift => '$self',
35 attrs => ':method',
36 },
2d5cf47a 37);
c9a39f6b 38
db81d362 39sub import {
40 my $class = shift;
7a63380c 41
b72eb6ee 42 @_ or @_ = {
43 fun => 'function',
44 method => 'method',
45 };
125c067e 46 if (@_ == 1 && ref($_[0]) eq 'HASH') {
47 @_ = map [$_, $_[0]{$_}], keys %{$_[0]}
48 or return;
49 }
7a63380c 50
125c067e 51 my %spec;
52
53 my $bare = 0;
54 for my $proto (@_) {
55 my $item = ref $proto
56 ? $proto
57 : [$proto, $bare_arms[$bare++] || confess(qq{Don't know what to do with "$proto"})]
58 ;
59 my ($name, $type) = @$item;
2d5cf47a 60 _assert_valid_identifier $name;
61
62 unless (ref $type) {
63 # use '||' instead of 'or' to preserve $type in the error message
64 $type = $type_map{$type}
65 || confess qq["$type" doesn't look like a valid type (one of ${\join ', ', sort keys %type_map})];
66 }
67 $type->{name} ||= 'optional';
68 $type->{name} =~ /^(?:optional|required|prohibited)\z/
69 or confess qq["$type->{name}" doesn't look like a valid name attribute (one of optional, required, prohibited)];
b72eb6ee 70
71 $type->{shift} and _assert_valid_identifier $type->{shift}, 1;
72 $type->{attrs} and _assert_valid_attributes $type->{attrs};
125c067e 73
db81d362 74 $spec{$name} = $type;
125c067e 75 }
76
db81d362 77 for my $kw (keys %spec) {
78 my $type = $spec{$kw};
79
80 $^H{HINTK_SHIFT_ . $kw} = $type->{shift} || '';
b72eb6ee 81 $^H{HINTK_ATTRS_ . $kw} = $type->{attrs} || '';
db81d362 82 $^H{HINTK_NAME_ . $kw} =
83 $type->{name} eq 'prohibited' ? FLAG_NAME_PROHIBITED :
84 $type->{name} eq 'required' ? FLAG_NAME_REQUIRED :
85 FLAG_NAME_OPTIONAL
86 ;
87 $^H{+HINTK_KEYWORDS} .= "$kw ";
125c067e 88 }
eeb7df5f 89}
90
db81d362 91sub unimport {
eeb7df5f 92 my $class = shift;
125c067e 93
db81d362 94 if (!@_) {
95 delete $^H{+HINTK_KEYWORDS};
125c067e 96 return;
97 }
98
db81d362 99 for my $kw (@_) {
100 $^H{+HINTK_KEYWORDS} =~ s/(?<![^ ])\Q$kw\E //g;
125c067e 101 }
102}
103
db81d362 104
125c067e 105'ok'
7a63380c 106
107__END__
108
109=head1 NAME
110
111Function::Parameters - subroutine definitions with parameter lists
112
113=head1 SYNOPSIS
114
115 use Function::Parameters;
116
117 fun foo($bar, $baz) {
118 return $bar + $baz;
119 }
120
121 fun mymap($fun, @args) :(&@) {
122 my @res;
123 for (@args) {
124 push @res, $fun->($_);
125 }
126 @res
127 }
128
129 print "$_\n" for mymap { $_ * 2 } 1 .. 4;
125c067e 130
131 method set_name($name) {
132 $self->{name} = $name;
133 }
7a63380c 134
125c067e 135=cut
136
137=pod
138
63a24d7c 139 use Function::Parameters {
140 proc => 'function',
141 meth => 'method',
142 };
c9a39f6b 143
125c067e 144 my $f = proc ($x) { $x * 2 };
145 meth get_age() {
146 return $self->{age};
147 }
148
7a63380c 149=head1 DESCRIPTION
150
151This module lets you use parameter lists in your subroutines. Thanks to
63a24d7c 152L<PL_keyword_plugin|perlapi/PL_keyword_plugin> it works without source filters.
7a63380c 153
db81d362 154WARNING: This is my first attempt at writing L<XS code|perlxs> and I have
7a63380c 155almost no experience with perl's internals. So while this module might
156appear to work, it could also conceivably make your programs segfault.
157Consider this module alpha quality.
158
159=head2 Basic stuff
160
161To use this new functionality, you have to use C<fun> instead of C<sub> -
162C<sub> continues to work as before. The syntax is almost the same as for
163C<sub>, but after the subroutine name (or directly after C<fun> if you're
125c067e 164writing an anonymous sub) you can write a parameter list in parentheses. This
7a63380c 165list consists of comma-separated variables.
166
167The effect of C<fun foo($bar, $baz) {> is as if you'd written
168C<sub foo { my ($bar, $baz) = @_; >, i.e. the parameter list is simply
169copied into C<my> and initialized from L<@_|perlvar/"@_">.
170
125c067e 171In addition you can use C<method>, which understands the same syntax as C<fun>
172but automatically creates a C<$self> variable for you. So by writing
173C<method foo($bar, $baz) {> you get the same effect as
174C<sub foo { my $self = shift; my ($bar, $baz) = @_; >.
7a63380c 175
125c067e 176=head2 Customizing the generated keywords
c9a39f6b 177
63a24d7c 178You can customize the names of the keywords injected into your scope. To do
179that you pass a hash reference in the import list:
7a63380c 180
125c067e 181 use Function::Parameters { proc => 'function', meth => 'method' }; # -or-
182 use Function::Parameters { proc => 'function' }; # -or-
183 use Function::Parameters { meth => 'method' };
184
185The first line creates two keywords, C<proc> and C<meth> (for defining
186functions and methods, respectively). The last two lines only create one
187keyword. Generally the hash keys can be any identifiers you want while the
ce052c57 188values have to be either C<function>, C<method>, or a hash reference (see
189below). The difference between C<function> and C<method> is that C<method>s
190automatically L<shift|perlfunc/shift> their first argument into C<$self>.
125c067e 191
192The following shortcuts are available:
193
194 use Function::Parameters;
195 # is equivalent to #
196 use Function::Parameters { fun => 'function', method => 'method' };
197
198=cut
199
200=pod
201
63a24d7c 202The following shortcuts are deprecated and may be removed from a future version
203of the module:
204
205 # DEPRECATED
125c067e 206 use Function::Parameters 'foo';
207 # is equivalent to #
208 use Function::Parameters { 'foo' => 'function' };
209
210=cut
211
212=pod
213
63a24d7c 214 # DEPRECATED
125c067e 215 use Function::Parameters 'foo', 'bar';
216 # is equivalent to #
217 use Function::Parameters { 'foo' => 'function', 'bar' => 'method' };
218
63a24d7c 219That is, if you want to pass arguments to L<Function::Parameters>, use a
220hashref, not a list of strings.
221
ce052c57 222You can customize things even more by passing a hashref instead of C<function>
223or C<method>. This hash can have the following keys:
224
225=over
226
227=item C<name>
228
229Valid values: C<optional> (default), C<required> (all uses of this keyword must
230specify a function name), and C<prohibited> (all uses of this keyword must not
231specify a function name). This means a C<< name => 'prohibited' >> keyword can
232only be used for defining anonymous functions.
233
234=item C<shift>
235
236Valid values: strings that look like a scalar variable. Any function created by
237this keyword will automatically L<shift|perlfunc/shift> its first argument into
63a24d7c 238a local variable whose name is specified here.
ce052c57 239
273c6544 240=item C<attrs>
241
242Valid values: strings that are valid source code for attributes. Any value
243specified here will be inserted as a subroutine attribute in the generated
244code. Thus:
245
246 use Function::Parameters { sub_l => { attrs => ':lvalue' } };
247 sub_l foo() {
248 ...
249 }
250
251turns into
252
253 sub foo :lvalue {
254 ...
255 }
256
ce052c57 257=back
258
63a24d7c 259Plain C<'function'> is equivalent to C<< { name => 'optional' } >>, and plain
273c6544 260C<'method'> is equivalent to
261C<< { name => 'optional', shift => '$self', attrs => ':method' } >>.
ce052c57 262
63a24d7c 263=head2 Syntax and generated code
7a63380c 264
265Normally, Perl subroutines are not in scope in their own body, meaning the
63a24d7c 266parser doesn't know the name C<foo> or its prototype while processing the body
267of C<sub foo ($) { foo $bar[1], $bar[0]; }>, parsing it as
7a63380c 268C<$bar-E<gt>foo([1], $bar[0])>. Yes. You can add parens to change the
269interpretation of this code, but C<foo($bar[1], $bar[0])> will only trigger
270a I<foo() called too early to check prototype> warning. This module attempts
271to fix all of this by adding a subroutine declaration before the definition,
272so the parser knows the name (and possibly prototype) while it processes the
273body. Thus C<fun foo($x) :($) { $x }> really turns into
274C<sub foo ($); sub foo ($) { my ($x) = @_; $x }>.
275
125c067e 276If you need L<subroutine attributes|perlsub/"Subroutine Attributes">, you can
277put them after the parameter list with their usual syntax.
278
279Syntactically, these new parameter lists live in the spot normally occupied
280by L<prototypes|perlsub/"Prototypes">. However, you can include a prototype by
281specifying it as the first attribute (this is syntactically unambiguous
63a24d7c 282because normal attributes have to start with a letter while a prototype starts
283with C<(>).
284
285As an example, the following declaration uses every feature available
286(subroutine name, parameter list, prototype, attributes, and implicit
287C<$self>):
288
289 method foo($x, $y, @z) :($;$@) :lvalue :Banana(2 + 2) {
290 ...
291 }
292
293And here's what it turns into:
294
295 sub foo ($;$@); sub foo ($;$@) :lvalue :Banana(2 + 2) { my $self = shift; my ($x, $y, @z) = @_;
296 ...
297 }
298
299Another example:
300
301 my $coderef = fun ($p, $q) :(;$$)
302 :lvalue
303 :Gazebo((>:O)) {
304 ...
305 };
306
307And the generated code:
308
309 my $coderef = sub (;$$) :lvalue :Gazebo((>:O)) { my ($p, $q) = @_;
310 ...
311 };
312
313=head2 Wrapping Function::Parameters
125c067e 314
db81d362 315If you want to wrap L<Function::Parameters>, you just have to call its
316C<import> method. It always applies to the file that is currently being parsed
63a24d7c 317and its effects are lexical (i.e. it works like L<warnings> or L<strict>):
318
319 package Some::Wrapper;
320 use Function::Parameters ();
321 sub import {
322 Function::Parameters->import;
323 # or Function::Parameters->import(@other_import_args);
324 }
eeb7df5f 325
7a63380c 326=head1 AUTHOR
327
328Lukas Mai, C<< <l.mai at web.de> >>
329
330=head1 COPYRIGHT & LICENSE
331
db81d362 332Copyright 2010, 2011, 2012 Lukas Mai.
7a63380c 333
334This program is free software; you can redistribute it and/or modify it
335under the terms of either: the GNU General Public License as published
336by the Free Software Foundation; or the Artistic License.
337
338See http://dev.perl.org/licenses/ for more information.
339
340=cut