+ $args =~ s/,\s*$//;
+ return $name . '(' . $args . ')';
+ }
+}
+
+sub _check_name {
+ my $name = $_[0];
+ croak 'No subroutine specified' unless $name;
+ my $proto;
+ my $r = ref $name;
+ if (!$r) {
+ $proto = prototype $name;
+ } elsif ($r eq 'HASH') {
+ croak 'Forced prototype hash reference must contain exactly one key/value pair' unless keys %$name == 1;
+ ($name, $proto) = %$name;
+ } else {
+ croak 'Unhandled ' . $r . ' reference as first argument';
+ }
+ $name =~ s/^\s+//;
+ $name =~ s/[\s\$\@\%\*\&;].*//;
+ return $name, $proto;
+}
+
+sub wrap {
+ my ($name, $proto) = _check_name shift;
+ croak 'Optional arguments must be passed as key => value pairs' if @_ % 2;
+ my %opts = @_;
+ $opts{ref} ||= 'ref';
+ $opts{sub} = 1 if not exists $opts{sub} or $opts{compile};
+ $opts{wrong_ref} = 'undef' if not defined $opts{wrong_ref};
+ my @cr;
+ my $call;
+ if (defined $proto) {
+ $call = _wrap $name, $proto, 0, '', \@cr, \%opts;
+ } else {
+ $call = _wrap $name, '', 0, '@_';
+ }
+ if (@cr) {
+ $call = 'my @c; '
+ . join('', map { 'push @c, $_[' . $_ . ']; ' } @cr)
+ . $call