]> git.vpit.fr Git - perl/modules/Sub-Prototype-Util.git/blobdiff - lib/Sub/Prototype/Util.pm
Importing Sub-Prototype-Util-0.05.tar.gz
[perl/modules/Sub-Prototype-Util.git] / lib / Sub / Prototype / Util.pm
index f090f87be84c8460f2bc030e535d097b1868248e..73a1a60115f6d384ace73083584543d99bf60cc0 100644 (file)
@@ -8,15 +8,17 @@ use Scalar::Util qw/reftype/;
 
 =head1 NAME
 
-Sub::Prototype::Util - Prototypes-related utility routines.
+Sub::Prototype::Util - Prototype-related utility routines.
 
 =head1 VERSION
 
-Version 0.01
+Version 0.05
 
 =cut
 
-our $VERSION = '0.01';
+use vars qw/$VERSION/;
+
+$VERSION = '0.05';
 
 =head1 SYNOPSIS
 
@@ -30,7 +32,7 @@ our $VERSION = '0.01';
 
 =head1 DESCRIPTION
 
-Prototypes are evil, but sometimes you just have to bear with them, especially when messing with core functions. This module provides several utilities aimed at faciliting "overloading" of prototyped functions.
+Prototypes are evil, but sometimes you just have to bear with them, especially when messing with core functions. This module provides several utilities aimed at facilitating "overloading" of prototyped functions.
 
 They all handle C<5.10>'s C<_> prototype.
 
@@ -78,7 +80,7 @@ sub flatten {
   } elsif ($p =~ /[\@\%]/) {
    push @args, @_;
    last;
-  } elsif ($p eq '_') {
+  } elsif ($p eq '_' && @_ == 0) {
    push @args, $_;
   } else {
    push @args, shift;
@@ -96,60 +98,82 @@ Calls the function C<$name> with the prototyped argument list C<@args>. That is,
 
 will call C<push @$a, 1, 2, 3> and so fill the arrayref C<$a> with C<1, 2, 3>. This is especially needed for core functions because you can't C<goto> into them.
 
+You can also force the use of a specific prototype. In this case, C<$name> must be a hash reference that holds exactly one key/value pair, the key being the function name and the value the prototpye that should be used to call it.
+
+    recall { 'CORE::push' => '\@$' }, $a, 1, 2, 3; # will only push 1
+
+This allows you to recall into C<CORE::grep> and C<CORE::map> by using the C<\&@> prototype :
+
+    sub mygrep (&@) { recall { 'CORE::grep' => '\&@' }, @_ } # the prototypes are intentionally different
+
 =cut
 
 sub recall {
- my ($name, @a) = @_;
- croak 'Wrong subroutine name' unless $name;
+ my $name = shift;
+ croak 'No subroutine specified' unless $name;
+ my $proto;
+ my $r = ref $name;
+ if ($r eq 'HASH') {
+  croak 'Forced prototype hash reference must contain exactly one key/value pair' unless keys %$name == 1;
+  ($name, $proto) = %$name;
+ } elsif (length $r) {
+  croak 'Unhandled ' . $r . ' reference as first argument';
+ }
  $name =~ s/^\s+//;
  $name =~ s/[\s\$\@\%\*\&;].*//;
- my $proto = prototype $name;
- my @args;
+ $proto = prototype $name unless $proto;
+ my $call = $name . '(';
+ my @cr;
  if (defined $proto) {
   my $i = 0;
   while ($proto =~ /(\\?)(\[[^\]]+\]|[^\];])/g) {
    my $p = $2;
    if ($1) {
-    my $r = _check_ref $a[$i], $p;
-    push @args, join '', $sigils{$r}, '{$a[', $i, ']}';
+    my $r = _check_ref $_[$i], $p;
+    $call .= $sigils{$r} . '{$_[' . $i . ']},';
    } elsif ($p =~ /[\@\%]/) {
-    push @args, join '', '@a[', $i, '..', (@a - 1), ']';
+    $call .= '@_[' . $i . '..' . (@_ - 1) . ']';
     last;
    } elsif ($p =~ /\&/) {
-    push @args, 'sub{&{$a[' . $i . ']}}';
-   } elsif ($p eq '_') {
-    push @args, '$_';
+    push @cr, $_[$i];
+    $call .= 'sub{&{$cr[' . $#cr . ']}},';
+   } elsif ($p eq '_' && $i >= @_) {
+    $call .= '$_,';
    } else {
-    push @args, '$a[' . $i . ']';
+    $call .= '$_[' . $i . '],';
    }
    ++$i; 
   }
+  $call =~ s/,$//;
  } else {
-  @args = map '$a[' . $_ . ']', 0 .. @a - 1;
+  $call .= join ',', map '$_[' . $_ . ']', 0 .. @_ - 1;
  }
- my @ret = eval $name . '(' . join(',', @args) . ');';
+ $call .= ');';
+ my @ret = eval $call;
  croak $@ if $@;
  return @ret;
 }
 
 =head1 EXPORT
 
-The functions L</flatten> and L</recall> are only exported on request, either by providing their name or by the C<':consts'> and C<':all'> tags.
+The functions L</flatten> and L</recall> are only exported on request, either by providing their name or by the C<':funcs'> and C<':all'> tags.
 
 =cut
 
 use base qw/Exporter/;
 
-our @EXPORT         = ();
-our %EXPORT_TAGS    = (
+use vars qw/@EXPORT @EXPORT_OK %EXPORT_TAGS/;
+
+@EXPORT             = ();
+%EXPORT_TAGS        = (
  'funcs' =>  [ qw/flatten recall/ ]
 );
-our @EXPORT_OK      = map { @$_ } values %EXPORT_TAGS;
+@EXPORT_OK          = map { @$_ } values %EXPORT_TAGS;
 $EXPORT_TAGS{'all'} = [ @EXPORT_OK ];
 
 =head1 DEPENDENCIES
 
-L<Carp> (core module since perl 5), L<Scalar::Util> (since 5.7.3).
+L<Carp>, L<Exporter> (core modules since perl 5), L<Scalar::Util> (since 5.7.3).
 
 =head1 AUTHOR