From: Lukas Mai Date: Sun, 4 Nov 2012 01:32:50 +0000 (+0100) Subject: document info(), add args_min/args_max X-Git-Tag: v1.00_02~11 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=ebdc721b189a191184af4bbb1d405ab4ad33a183;p=p5sagit%2FFunction-Parameters.git document info(), add args_min/args_max --- diff --git a/lib/Function/Parameters.pm b/lib/Function/Parameters.pm index 5734c7d..c67e6ec 100644 --- a/lib/Function/Parameters.pm +++ b/lib/Function/Parameters.pm @@ -613,6 +613,16 @@ C<< use Function::Parameters { fun => 'function', method => 'method' } >>. C is equivalent to C<< use Function::Parameters { fun => 'function_strict', method => 'method_strict' } >>. +=head2 Introspection + +You can ask a function at runtime what parameters it has. This functionality is +available through the function C (which is not +exported, so you have to call it by its full name). It takes a reference to a +function, and returns either C (if it knows nothing about the function) +or a L object describing the parameter list. + +See L for examples. + =head2 Wrapping C If you want to write a wrapper around C, you only have to @@ -643,6 +653,10 @@ generated code corresponds to: # ... turns into ... sub bar :method { my $self = shift; my ($x, $y, @z) = @_; sub bar; ... } +=head1 SEE ALSO + +L + =head1 AUTHOR Lukas Mai, C<< >> diff --git a/lib/Function/Parameters/Info.pm b/lib/Function/Parameters/Info.pm index 1519629..8604eeb 100644 --- a/lib/Function/Parameters/Info.pm +++ b/lib/Function/Parameters/Info.pm @@ -20,6 +20,125 @@ for my $gen (join "\n", map "sub $_ { \@{\$_[0]->_$_} }", @pn_ro) { eval "$gen\n1" or die $@; } +sub args_min { + my $self = shift; + my $r = 0; + $r++ if defined $self->invocant; + $r += $self->positional_required; + $r += $self->named_required * 2; + $r +} + +sub args_max { + my $self = shift; + return 0 + 'Inf' if defined $self->slurpy || $self->named_required || $self->named_optional; + my $r = 0; + $r++ if defined $self->invocant; + $r += $self->positional_required; + $r += $self->positional_optional; + $r +} + 'ok' __END__ + +=encoding UTF-8 + +=head1 NAME + +Function::Parameters::Info - Information about parameter lists + +=head1 SYNOPSIS + + use Function::Parameters; + + fun foo($x, $y, :$hello, :$world = undef) {} + + my $info = Function::Parameters::info \&foo; + my $p0 = $info->invocant; # undef + my @p1 = $info->positional_required; # ('$x', '$y') + my @p2 = $info->positional_optional; # () + my @p3 = $info->named_required; # ('$hello') + my @p4 = $info->named_optional; # ('$world') + my $p5 = $info->slurpy; # undef + my $min = $info->args_min; # 4 + my $max = $info->args_max; # inf + + my $invocant = Function::Parameters::info(method () { 42 })->invocant; # '$self' + + my $slurpy = Function::Parameters::info(fun {})->slurpy; # '@_' + +=head1 DESCRIPTION + +L|Function::Parameters/Introspection> returns +objects of this class to describe parameter lists of functions. The following +methods are available: + +=head2 C<< $info->invocant >> + +Returns the name of the variable into which the first argument is +L|perlfunc/shift>ed into automatically, or C if no such thing +exists. This will usually return C<'$self'> for methods. + +=head2 C<< $info->positional_required >> + +Returns a list of the names of the required positional parameters (or a count +in scalar context). + +=head2 C<< $info->positional_optional >> + +Returns a list of the names of the optional positional parameters (or a count +in scalar context). + +=head2 C<< $info->named_required >> + +Returns a list of the names of the required named parameters (or a count +in scalar context). + +=head2 C<< $info->named_optional >> + +Returns a list of the names of the optional named parameters (or a count +in scalar context). + +=head2 C<< $info->slurpy >> + +Returns the name of the final array or hash that gobbles up all remaining +arguments, or C if no such thing exists. + +As a special case, functions defined without an explicit parameter list (i.e. +without C<( )>) will return C<'@_'> here because they accept any number of +arguments. + +=head2 C<< $info->args_min >> + +Returns the minimum number of arguments this function requires. This is +computed as follows: Invocant and required positional parameters count 1 each. +Optional parameters don't count. Required named parameters count 2 each (key + +value). Slurpy parameters don't count either because they accept empty lists. + +=head2 C<< $info->args_max >> + +Returns the maximum number of arguments this function accepts. This is computed +as follows: If there is any named or slurpy parameter, the result is C. +Otherwise the result is the sum of all invocant and positional parameters. + +=head1 SEE ALSO + +L + +=head1 AUTHOR + +Lukas Mai, C<< >> + +=head1 COPYRIGHT & LICENSE + +Copyright 2012 Lukas Mai. + +This program is free software; you can redistribute it and/or modify it +under the terms of either: the GNU General Public License as published +by the Free Software Foundation; or the Artistic License. + +See http://dev.perl.org/licenses/ for more information. + +=cut diff --git a/t/info.t b/t/info.t index c670cef..683fa15 100644 --- a/t/info.t +++ b/t/info.t @@ -2,10 +2,12 @@ use warnings FATAL => 'all'; use strict; -use Test::More tests => 104; +use Test::More tests => 122; use Function::Parameters; +sub Inf () { 0 + 'Inf' } + fun foo($pr1, $pr2, $po1 = 1, $po2 = 2, :$no1 = 3, :$no2 = 4, %r) {} { @@ -21,6 +23,8 @@ fun foo($pr1, $pr2, $po1 = 1, $po2 = 2, :$no1 = 3, :$no2 = 4, %r) {} is_deeply [$info->named_optional], [qw($no1 $no2)]; is scalar $info->named_optional, 2; is $info->slurpy, '%r'; + is $info->args_min, 2; + is $info->args_max, Inf; } { @@ -36,6 +40,8 @@ fun foo($pr1, $pr2, $po1 = 1, $po2 = 2, :$no1 = 3, :$no2 = 4, %r) {} is_deeply [$info->named_optional], []; is scalar $info->named_optional, 0; is $info->slurpy, undef; + is $info->args_min, 5; + is $info->args_max, Inf; } sub bar {} @@ -59,6 +65,8 @@ method baz($class: $po1 = 1, $po2 = 2, $po3 = 3, :$no1 = 4, @rem) {} is_deeply [$info->named_optional], [qw($no1)]; is scalar $info->named_optional, 1; is $info->slurpy, '@rem'; + is $info->args_min, 1; + is $info->args_max, Inf; } { @@ -74,6 +82,8 @@ method baz($class: $po1 = 1, $po2 = 2, $po3 = 3, :$no1 = 4, @rem) {} is_deeply [$info->named_optional], []; is scalar $info->named_optional, 0; is $info->slurpy, undef; + is $info->args_min, 1; + is $info->args_max, 1; } { @@ -90,6 +100,8 @@ method baz($class: $po1 = 1, $po2 = 2, $po3 = 3, :$no1 = 4, @rem) {} is_deeply [$info->named_optional], []; is scalar $info->named_optional, 0; is $info->slurpy, '@_'; + is $info->args_min, 0; + is $info->args_max, Inf; } { @@ -105,6 +117,8 @@ method baz($class: $po1 = 1, $po2 = 2, $po3 = 3, :$no1 = 4, @rem) {} is_deeply [$info->named_optional], []; is scalar $info->named_optional, 0; is $info->slurpy, '@_'; + is $info->args_min, 1; + is $info->args_max, Inf; } { @@ -126,6 +140,8 @@ method baz($class: $po1 = 1, $po2 = 2, $po3 = 3, :$no1 = 4, @rem) {} is_deeply [$info->named_optional], []; is scalar $info->named_optional, 0; is $info->slurpy, undef; + is $info->args_min, 6; + is $info->args_max, Inf; is $f->(), $i; } }