Skip to content

Commit

Permalink
Add Capture::Tiny, but as a single function with options.
Browse files Browse the repository at this point in the history
Closes #178
  • Loading branch information
schwern committed Feb 14, 2011
1 parent 7ea34e5 commit 34509b1
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 1 deletion.
6 changes: 5 additions & 1 deletion Changes
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
2.5.2
2.6.0
New Feature
* Added capture(), from Capture::Tiny, to capture output to STDOUT and
STDERR [github 178]

Windows Fixes
* Fix t/center.t (Myf White)

Expand Down
45 changes: 45 additions & 0 deletions lib/perl5i.pm
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,51 @@ STDOUT, STDIN, STDERR and all newly opened filehandles will have UTF8
encoding turned on. Consequently, if you want to output raw bytes to
a file, such as outputting an image, you must set C<< binmode $fh >>.
=head2 capture()
my($stdout, $stderr) = capture { ... } %options;
my $stdout = capture { ... } %options;
C<capture()> lets you capture all output to C<STDOUT> and C<STDERR> in
any block of code.
# $out = "Hello"
# $err = "Bye"
my($out, $err) = capture {
print "Hello";
print STDERR "Bye";
};
If called in scalar context, it will only return C<STDOUT> and silence C<STDERR>.
# $out = "Hello"
my $out = capture {
print "Hello";
warn "oh god";
};
C<capture> takes some options.
=over 4
=item B<tee>
tee will cause output to be captured yet still printed.
my $out = capture { print "Hi" } tee => 1;
=item B<merge>
merge will merge C<STDOUT> and C<STDERR> into one variable.
# $out = "HiBye"
my $out = capture {
print "Hi";
print STDERR "Bye";
} merge => 1;
=back
=head2 Carp
C<croak> and C<carp> from L<Carp> are always available.
Expand Down
34 changes: 34 additions & 0 deletions lib/perl5i/2.pm
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,20 @@ sub import {
(\&{$Latest .'::DateTime::dt_gmtime'})->alias($caller, 'gmtime');
(\&{$Latest .'::DateTime::dt_localtime'})->alias($caller, 'localtime');
(\&{$Latest .'::DateTime::dt_time'})->alias($caller, 'time');

# Export our stat and lstat
(\&stat)->alias( $caller, 'stat' );
(\&lstat)->alias( $caller, 'lstat' );

# Export our open
(\&utf8_open)->alias($caller, 'open');

# Export our fixed die
(\&perl5i_die)->alias($caller, "die");

# Export capture()
(\&capture)->alias($caller, "capture");

# utf8ify @ARGV
$_ = Encode::decode('utf8', $_) for @ARGV;

Expand Down Expand Up @@ -153,3 +162,28 @@ sub lstat {
return File::stat::lstat(@_);
}


sub capture(&;@) {
my($code, %opts) = @_;

# valid options
state $valid_options = { map { $_ => 1 } qw(merge tee) };

for my $key (keys %opts) {
croak "$key is not a valid option to capture()" unless $valid_options->{$key};
}

my $opts = join "/", sort { $a cmp $b } grep { $opts{$_} } keys %opts;

# Translate option combinations into Capture::Tiny functions
require Capture::Tiny;
state $captures = {
"" => \&Capture::Tiny::capture,
"tee" => \&Capture::Tiny::tee,
"merge" => \&Capture::Tiny::capture_merged,
"merge/tee" => \&Capture::Tiny::tee_merged
};

my $func = $captures->{$opts};
return $func->($code);
}
38 changes: 38 additions & 0 deletions t/capture.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/usr/bin/env perl

use perl5i::latest;

use Test::More;

note "scalar context"; {
is capture { print "Hello" }, "Hello";

is capture {
print "Hello";
warn "you should not see this";
}, "Hello", "stderr is silenced";
}


note "tee"; {
my($out, $err) = capture {
capture {
print "out";
warn "err";
} tee => 1;
};
is $out, "out";
like $err, qr/^err\b/;
}


note "merge"; {
my $out = capture {
print "out";
print STDERR "err";
} merge => 1;

is $out, "outerr";
}

done_testing;

0 comments on commit 34509b1

Please sign in to comment.