The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
Changes 08
LICENSE 11
MANIFEST 05
META.json 137
META.yml 2119
Makefile.PL 1829
README 13
lib/System/Sub/AutoLoad.pm 52
lib/System/Sub.pm 1352
t/00-compile.t 5836
t/24-error.t 023
t/25-common-opts.t 023
t/exiterr.pl 03
t/print.pl 03
xt/release/kwalitee.t 72
xt/release/pod-coverage.t 93
xt/release/pod-syntax.t 32
17 files changed (This is a version diff) 149221
@@ -1,9 +1,17 @@
 Revision history for System-Sub.
 
+0.142280     2014-08-16    DOLMEN (Olivier Mengué)
+	Add option '&?' to handle exit code != 0.
+	Add common options (an ARRAY as first import arg) that will apply
+          to all the commands on the import list.
+	Doc: add link to Shell.pm (Thanks Slaven Rezic, RT#84739).
+
 0.130210     2013-01-21    DOLMEN (Olivier Mengué)
 	Add option '()' to define the prototype of the sub.
 
 0.130180     2013-01-18    DOLMEN (Olivier Mengué)
+	Define the DEBUG compile symbol with 'constant.pm'. This fixes
+	  Pod::Coverage tests.
 	Minor fixes from BOOK (Philippe Bruhat).
 
 0.123440     2012-12-09    DOLMEN (Olivier Mengué)
@@ -22,7 +22,7 @@ This is free software, licensed under:
                      Version 1, February 1989
 
  Copyright (C) 1989 Free Software Foundation, Inc.
- 51 Franklin St, Suite 500, Boston, MA  02110-1335  USA
+ 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
  Everyone is permitted to copy and distribute verbatim copies
  of this license document, but changing it is not allowed.
@@ -1,3 +1,4 @@
+# This file was automatically generated by Dist::Zilla::Plugin::Manifest v5.019.
 Changes
 LICENSE
 MANIFEST
@@ -15,6 +16,10 @@ t/20-hostname.t
 t/21-AUTOLOAD.t
 t/22-ENV.t
 t/23-prototype.t
+t/24-error.t
+t/25-common-opts.t
+t/exiterr.pl
+t/print.pl
 t/printenv.pl
 xt/release/kwalitee.t
 xt/release/pod-coverage.t
@@ -4,7 +4,7 @@
       "Olivier Mengue <dolmen@cpan.org>"
    ],
    "dynamic_config" : 0,
-   "generated_by" : "Dist::Zilla version 4.300028, CPAN::Meta::Converter version 2.120921",
+   "generated_by" : "Dist::Zilla version 5.019, CPAN::Meta::Converter version 2.140640",
    "license" : [
       "perl_5"
    ],
@@ -22,6 +22,7 @@
       "develop" : {
          "requires" : {
             "Pod::Coverage::TrustPod" : "0",
+            "Test::Kwalitee" : "1.12",
             "Test::Pod" : "1.41",
             "Test::Pod::Coverage" : "1.08"
          }
@@ -42,22 +43,15 @@
       },
       "test" : {
          "requires" : {
-            "File::Find" : "0",
             "File::Spec" : "0",
-            "File::Temp" : "0",
-            "Test::More" : "0"
+            "IO::Handle" : "0",
+            "IPC::Open3" : "0",
+            "Test::More" : "0",
+            "perl" : "5.006"
          }
       }
    },
    "release_status" : "stable",
-   "resources" : {
-      "homepage" : "https://github.com/dolmen/p5-System-Sub",
-      "repository" : {
-         "type" : "git",
-         "url" : "https://github.com/dolmen/p5-System-Sub.git",
-         "web" : "https://github.com/dolmen/p5-System-Sub"
-      }
-   },
-   "version" : "0.130210"
+   "version" : "0.142280"
 }
 
@@ -3,31 +3,29 @@ abstract: 'Wrap external command with a DWIM sub'
 author:
   - 'Olivier Mengue <dolmen@cpan.org>'
 build_requires:
-  File::Find: 0
-  File::Spec: 0
-  File::Temp: 0
-  Test::More: 0
+  File::Spec: '0'
+  IO::Handle: '0'
+  IPC::Open3: '0'
+  Test::More: '0'
+  perl: '5.006'
 configure_requires:
-  ExtUtils::MakeMaker: 6.30
+  ExtUtils::MakeMaker: '6.30'
 dynamic_config: 0
-generated_by: 'Dist::Zilla version 4.300028, CPAN::Meta::Converter version 2.120921'
+generated_by: 'Dist::Zilla version 5.019, CPAN::Meta::Converter version 2.140640'
 license: perl
 meta-spec:
   url: http://module-build.sourceforge.net/META-spec-v1.4.html
-  version: 1.4
+  version: '1.4'
 name: System-Sub
 requires:
-  Carp: 0
-  File::Which: 0
-  IPC::Run: 0
-  Scalar::Util: 1.11
-  Sub::Name: 0
-  Symbol: 0
-  constant: 0
-  perl: 5.006
-  strict: 0
-  warnings: 0
-resources:
-  homepage: https://github.com/dolmen/p5-System-Sub
-  repository: https://github.com/dolmen/p5-System-Sub.git
-version: 0.130210
+  Carp: '0'
+  File::Which: '0'
+  IPC::Run: '0'
+  Scalar::Util: '1.11'
+  Sub::Name: '0'
+  Symbol: '0'
+  constant: '0'
+  perl: '5.006'
+  strict: '0'
+  warnings: '0'
+version: '0.142280'
@@ -1,4 +1,5 @@
 
+# This file was automatically generated by Dist::Zilla::Plugin::MakeMaker v5.019.
 use strict;
 use warnings;
 
@@ -11,12 +12,6 @@ use ExtUtils::MakeMaker 6.30;
 my %WriteMakefileArgs = (
   "ABSTRACT" => "Wrap external command with a DWIM sub",
   "AUTHOR" => "Olivier Mengue <dolmen\@cpan.org>",
-  "BUILD_REQUIRES" => {
-    "File::Find" => 0,
-    "File::Spec" => 0,
-    "File::Temp" => 0,
-    "Test::More" => 0
-  },
   "CONFIGURE_REQUIRES" => {
     "ExtUtils::MakeMaker" => "6.30"
   },
@@ -35,24 +30,40 @@ my %WriteMakefileArgs = (
     "strict" => 0,
     "warnings" => 0
   },
-  "VERSION" => "0.130210",
+  "TEST_REQUIRES" => {
+    "File::Spec" => 0,
+    "IO::Handle" => 0,
+    "IPC::Open3" => 0,
+    "Test::More" => 0
+  },
+  "VERSION" => "0.142280",
   "test" => {
     "TESTS" => "t/*.t"
   }
 );
 
 
-unless ( eval { ExtUtils::MakeMaker->VERSION(6.56) } ) {
-  my $br = delete $WriteMakefileArgs{BUILD_REQUIRES};
-  my $pp = $WriteMakefileArgs{PREREQ_PM};
-  for my $mod ( keys %$br ) {
-    if ( exists $pp->{$mod} ) {
-      $pp->{$mod} = $br->{$mod} if $br->{$mod} > $pp->{$mod};
-    }
-    else {
-      $pp->{$mod} = $br->{$mod};
-    }
-  }
+my %FallbackPrereqs = (
+  "Carp" => 0,
+  "File::Spec" => 0,
+  "File::Which" => 0,
+  "IO::Handle" => 0,
+  "IPC::Open3" => 0,
+  "IPC::Run" => 0,
+  "Scalar::Util" => "1.11",
+  "Sub::Name" => 0,
+  "Symbol" => 0,
+  "Test::More" => 0,
+  "constant" => 0,
+  "strict" => 0,
+  "warnings" => 0
+);
+
+
+unless ( eval { ExtUtils::MakeMaker->VERSION(6.63_03) } ) {
+  delete $WriteMakefileArgs{TEST_REQUIRES};
+  delete $WriteMakefileArgs{BUILD_REQUIRES};
+  $WriteMakefileArgs{PREREQ_PM} = \%FallbackPrereqs;
 }
 
 delete $WriteMakefileArgs{CONFIGURE_REQUIRES}
@@ -1,7 +1,7 @@
 
 
 This archive contains the distribution System-Sub,
-version 0.130210:
+version 0.142280:
 
   Wrap external command with a DWIM sub
 
@@ -11,3 +11,5 @@ This is free software; you can redistribute it and/or modify it under
 the same terms as the Perl 5 programming language system itself.
 
 
+This README file was generated by Dist::Zilla::Plugin::Readme v5.019.
+
@@ -1,10 +1,7 @@
 use strict;
 use warnings;
 package System::Sub::AutoLoad;
-{
-  $System::Sub::AutoLoad::VERSION = '0.130210';
-}
-
+$System::Sub::AutoLoad::VERSION = '0.142280';
 use System::Sub ();
 
 sub _croak
@@ -59,7 +56,7 @@ System::Sub::AutoLoad - Auto-wrap external commands as DWIM subs
 
 =head1 VERSION
 
-version 0.130210
+version 0.142280
 
 =head1 SYNOPSIS
 
@@ -1,10 +1,7 @@
 use strict;
 use warnings;
 package System::Sub;
-{
-  $System::Sub::VERSION = '0.130210';
-}
-
+$System::Sub::VERSION = '0.142280';
 use File::Which ();
 use Sub::Name 'subname';
 use Symbol 'gensym';
@@ -23,6 +20,7 @@ my %OPTIONS = (
     '>' => '',
     '<' => '',
     'ENV' => 'HASH',
+    '?' => 'CODE',
 );
 
 sub _croak
@@ -42,6 +40,9 @@ sub import
     my $pkg = (caller)[0];
     shift;
 
+    my $common_options;
+    $common_options = shift if @_ && ref($_[0]) eq 'ARRAY';
+
     while (@_) {
         my $name = shift;
         # Must be a scalar
@@ -57,22 +58,30 @@ sub import
             $fq_name = $pkg.'::'.$name;
         }
 
+        my $options;
+        if (@_ && ref $_[0]) {
+            $options = shift;
+            splice(@$options, 0, 0, @$common_options) if $common_options;
+        } elsif ($common_options) {
+            # Just duplicate common options
+            $options = [ @$common_options ];
+        }
+
         my $cmd = $name;
         my $args;
         my %options;
-        if (@_ && ref $_[0]) {
-            my $options = shift;
 
+        if ($options) {
             while (@$options) {
                 my $opt = shift @$options;
-                (my $opt_short = $opt) =~ s/^[\$\@\%]//;
+                (my $opt_short = $opt) =~ s/^[\$\@\%\&]//;
                 if ($opt eq '--') {
-                    _croak 'duplicate @ARGV' if $args;
+                    _croak 'duplicate @ARGV' if $args && !$common_options;
                     $args = $options;
                     last
                 } elsif ($opt eq '()') {
                     $proto = shift @$options;
-                } elsif ($opt =~ /^\$?0$/) { # $0
+                } elsif ($opt =~ /^\$?0$/s) { # $0
                     $cmd = shift @$options;
                 } elsif ($opt =~ /^\@?ARGV$/) { # @ARGV
                     _croak "$name: invalid \@ARGV" if ref($options->[0]) ne 'ARRAY';
@@ -113,6 +122,16 @@ sub import
     }
 }
 
+sub _handle_error
+{
+    my ($name, $code, $cmd, $handler) = @_;
+    if ($handler) {
+        $handler->($name, $?, $cmd);
+    } else {
+        _croak "$name error ".($?>>8)
+    }
+}
+
 sub _build_sub
 {
     my ($name, $cmd, $options) = @_;
@@ -166,7 +185,7 @@ sub _build_sub
             }
             close $out;
             finish $h;
-            _croak "$name error ".($?>>8) if $? >> 8;
+            _handle_error($name, $?, \@cmd, $options->{'?'}) if $? >> 8;
             return @output
         } elsif (defined wantarray) {
             # Only the first line
@@ -174,7 +193,7 @@ sub _build_sub
             defined($output = <$out>) and chomp $output;
             close $out;
             finish $h;
-            _croak "$name error ".($?>>8) if $? >> 8;
+            _handle_error($name, $?, \@cmd, $options->{'?'}) if $? >> 8;
             _croak "no output" unless defined $output;
             return $output
         } else { # void context
@@ -186,7 +205,7 @@ sub _build_sub
             }
             close $out;
             finish $h;
-            _croak "$name error ".($?>>8) if $? >> 8;
+            _handle_error($name, $?, \@cmd, $options->{'?'}) if $? >> 8;
             return
         }
     }
@@ -204,7 +223,7 @@ System::Sub - Wrap external command with a DWIM sub
 
 =head1 VERSION
 
-version 0.130210
+version 0.142280
 
 =head1 SYNOPSIS
 
@@ -251,6 +270,7 @@ version 0.130210
 
     # Import with a prototype (see perlsub)
     use System::Sub 'hostname()';  # Empty prototype: no args allowed
+    use System::Sub hostname => [ '()' => '' ];  # Alternate syntax
     use strict;
     # This will fail at compile time with "Too many arguments"
     hostname("xx");
@@ -341,6 +361,23 @@ C<E<gt>>: I/O layers for the data fed to the command.
 
 C<E<lt>>: I/O layers for the data read from the command output.
 
+=item *
+
+C<&?>: sub that will be called if ($? >> 8) != 0.
+
+    sub {
+        my $name = shift; # name of the sub
+        my $code = shift; # exit code ($?)
+        my $cmd = shift;  # array ref to the executed command
+
+        # Default implementation:
+        require Carp;
+        Carp::croak("$name error ".($code >> 8));
+    }
+
+Mnemonic: C<&> is the sigil for subs and C<$?> is the exit code of the last
+command.
+
 =back
 
 =head1 SUB USAGE
@@ -407,6 +444,8 @@ If you do not specify a callback, the behavior is currently unspecified
 
 =over 4
 
+=item * L<Shell>, distributed with Perl 5 to 5.14. Removed from core in 5.16.
+
 =item * L<perlipc>, L<perlfaq8>
 
 =item * L<IPC::Run>
@@ -1,73 +1,51 @@
-#!perl
-
+use 5.006;
 use strict;
 use warnings;
 
-use Test::More;
+# this test was generated with Dist::Zilla::Plugin::Test::Compile 2.043
 
+use Test::More  tests => 2 + ($ENV{AUTHOR_TESTING} ? 1 : 0);
 
 
-use File::Find;
-use File::Temp qw{ tempdir };
 
-my @modules;
-find(
-  sub {
-    return if $File::Find::name !~ /\.pm\z/;
-    my $found = $File::Find::name;
-    $found =~ s{^lib/}{};
-    $found =~ s{[/\\]}{::}g;
-    $found =~ s/\.pm$//;
-    # nothing to skip
-    push @modules, $found;
-  },
-  'lib',
+my @module_files = (
+    'System/Sub.pm',
+    'System/Sub/AutoLoad.pm'
 );
 
-sub _find_scripts {
-    my $dir = shift @_;
-
-    my @found_scripts = ();
-    find(
-      sub {
-        return unless -f;
-        my $found = $File::Find::name;
-        # nothing to skip
-        open my $FH, '<', $_ or do {
-          note( "Unable to open $found in ( $! ), skipping" );
-          return;
-        };
-        my $shebang = <$FH>;
-        return unless $shebang =~ /^#!.*?\bperl\b\s*$/;
-        push @found_scripts, $found;
-      },
-      $dir,
-    );
-
-    return @found_scripts;
-}
 
-my @scripts;
-do { push @scripts, _find_scripts($_) if -d $_ }
-    for qw{ bin script scripts };
 
-my $plan = scalar(@modules) + scalar(@scripts);
-$plan ? (plan tests => $plan) : (plan skip_all => "no tests to run");
+# no fake home requested
+
+my $inc_switch = -d 'blib' ? '-Mblib' : '-Ilib';
+
+use File::Spec;
+use IPC::Open3;
+use IO::Handle;
+
+open my $stdin, '<', File::Spec->devnull or die "can't open devnull: $!";
 
+my @warnings;
+for my $lib (@module_files)
 {
-    # fake home for cpan-testers
-    # no fake requested ## local $ENV{HOME} = tempdir( CLEANUP => 1 );
-
-    like( qx{ $^X -Ilib -e "require $_; print '$_ ok'" }, qr/^\s*$_ ok/s, "$_ loaded ok" )
-        for sort @modules;
-
-    SKIP: {
-        eval "use Test::Script 1.05; 1;";
-        skip "Test::Script needed to test script compilation", scalar(@scripts) if $@;
-        foreach my $file ( @scripts ) {
-            my $script = $file;
-            $script =~ s!.*/!!;
-            script_compiles( $file, "$script script compiles" );
-        }
+    # see L<perlfaq8/How can I capture STDERR from an external command?>
+    my $stderr = IO::Handle->new;
+
+    my $pid = open3($stdin, '>&STDERR', $stderr, $^X, $inc_switch, '-e', "require q[$lib]");
+    binmode $stderr, ':crlf' if $^O eq 'MSWin32';
+    my @_warnings = <$stderr>;
+    waitpid($pid, 0);
+    is($?, 0, "$lib loaded ok");
+
+    if (@_warnings)
+    {
+        warn @_warnings;
+        push @warnings, @_warnings;
     }
 }
+
+
+
+is(scalar(@warnings), 0, 'no warnings found') if $ENV{AUTHOR_TESTING};
+
+
@@ -0,0 +1,23 @@
+use strict;
+use warnings;
+
+use Test::More tests => 8;
+use File::Spec;
+
+use System::Sub exiterr => [
+    0 => $^X,
+    ARGV => [ File::Spec->catfile(qw(t exiterr.pl)) ],
+    '()' => '$',
+    '&?' => sub {
+        my ($name, $code, $cmd) = @_;
+        is($name, 'exiterr', 'name');
+        is($cmd->[0], $^X, '$cmd[0]');
+        is($?, $code, '$code == $?');
+        is($? >> 8, $cmd->[2]);
+    },
+];
+
+exiterr 4;
+exiterr 5;
+
+# vim:set et sw=4 sts=4:
@@ -0,0 +1,23 @@
+use strict;
+use warnings;
+
+use Test::More tests => 5;
+use File::Spec;
+
+# Test common options and prototypes
+use System::Sub [ 0 => $^X, ARGV => [ File::Spec->catfile(qw(t print.pl)) ] ],
+                qw< print1($) print2($$) >,
+                printenv => [
+                    ENV  => { Toto => 'Lulu' },
+                    '--' => File::Spec->catfile(qw(t printenv.pl)), 'Toto'
+                ];
+
+is(  scalar print1('x'),   'x', 'print1 (scalar)');
+is_deeply([ print1('y') ], [ 'y' ], 'print1 (list)');
+
+is(  scalar print2('x', 'y'),   'x',           'print2 (scalar)');
+is_deeply([ print2('x', 'y') ], [ qw< x y > ], 'print2 (list)');
+
+is_deeply([ printenv ], [ 'Lulu' ], 'printenv Toto');
+
+# vim:set et sw=4 sts=4:
@@ -0,0 +1,3 @@
+#!/usr/bin/perl
+
+exit shift;
@@ -0,0 +1,3 @@
+#!/usr/bin/perl
+
+print $_, $/ for @ARGV;
@@ -1,9 +1,4 @@
-#!perl
-
-# This test is generated by Dist::Zilla::Plugin::Test::Kwalitee
+# this test was generated with Dist::Zilla::Plugin::Test::Kwalitee 2.07
 use strict;
 use warnings;
-use Test::More;   # needed to provide plan.
-eval "use Test::Kwalitee";
-
-plan skip_all => "Test::Kwalitee required for testing kwalitee" if $@;
+use Test::Kwalitee;
@@ -1,13 +1,7 @@
 #!perl
+# This file was automatically generated by Dist::Zilla::Plugin::PodCoverageTests.
 
-use Test::More;
-
-eval "use Test::Pod::Coverage 1.08";
-plan skip_all => "Test::Pod::Coverage 1.08 required for testing POD coverage"
-  if $@;
-
-eval "use Pod::Coverage::TrustPod";
-plan skip_all => "Pod::Coverage::TrustPod required for testing POD coverage"
-  if $@;
+use Test::Pod::Coverage 1.08;
+use Pod::Coverage::TrustPod;
 
 all_pod_coverage_ok({ coverage_class => 'Pod::Coverage::TrustPod' });
@@ -1,7 +1,6 @@
 #!perl
+# This file was automatically generated by Dist::Zilla::Plugin::PodSyntaxTests.
 use Test::More;
-
-eval "use Test::Pod 1.41";
-plan skip_all => "Test::Pod 1.41 required for testing POD" if $@;
+use Test::Pod 1.41;
 
 all_pod_files_ok();