File Coverage

blib/lib/Devel/Ditto.pm
Criterion Covered Total %
statement 21 49 42.8
branch 0 8 0.0
condition n/a
subroutine 7 17 41.1
pod n/a
total 28 74 37.8


line stmt bran cond sub pod time code
1             package Devel::Ditto;
2              
3 1     1   42769 use 5.008;
  1         3  
  1         63  
4              
5             =head1 NAME
6              
7             Devel::Ditto - Identify where print output comes from
8              
9             =head1 VERSION
10              
11             This document describes Devel::Ditto version 0.06
12              
13             =cut
14              
15             our $VERSION = '0.06';
16              
17             =head1 SYNOPSIS
18              
19             $ perl -MDevel::Ditto myprog.pl
20             [main, t/myprog.pl, 9] This is regular text
21             [main, t/myprog.pl, 10] This is a warning
22             [MyPrinter, t/lib/MyPrinter.pm, 7] Hello, World
23             [MyPrinter, t/lib/MyPrinter.pm, 8] Whappen?
24              
25             =head1 DESCRIPTION
26              
27             Sometimes it's hard to work out where some printed output is coming
28             from. This module ties STDOUT and STDERR such that each call to C
29             or C will have its output prefixed with the package, file and line
30             of the C or C statement.
31              
32             Load it in your program:
33              
34             use Devel::Ditto;
35              
36             or from the command line:
37              
38             perl -MDevel::Ditto myprog.pl
39            
40             =cut
41              
42 1     1   6 no warnings;
  1         1  
  1         60  
43              
44             open( REALSTDOUT, ">&STDOUT" );
45             open( REALSTDERR, ">&STDERR" );
46              
47 1     1   4 use warnings;
  1         7  
  1         43  
48 1     1   6 use strict;
  1         1  
  1         42  
49              
50 1     1   5 use File::Spec;
  1         1  
  1         636  
51              
52             sub import {
53 1     1   9 my $class = shift;
54 1         3 my %params = @_;
55              
56             tie *STDOUT, $class, %params,
57             is_err => 0,
58             realout => sub {
59 0     0   0 open( local *STDOUT, ">&REALSTDOUT" );
60 0         0 $_[0]->( @_[ 1 .. $#_ ] );
61 1         9 };
62              
63             tie *STDERR, $class, %params,
64             is_err => 1,
65             realout => sub {
66 0     0   0 open( local *STDOUT, ">&REALSTDERR" );
67 0         0 $_[0]->( @_[ 1 .. $#_ ] );
68 1         6 };
69             }
70              
71             sub TIEHANDLE {
72 2     2   7 my ( $class, %params ) = @_;
73 2         16 bless \%params, $class;
74             }
75              
76             sub _caller {
77 0     0     my $self = shift;
78 0           my $depth = 0;
79 0           while () {
80 0           my ( $pkg, $file, $line ) = caller $depth;
81 0 0         return unless defined $pkg;
82 0 0         return ( $pkg, $file, $line )
83             unless $pkg->isa( __PACKAGE__ );
84 0           $depth++;
85             }
86             }
87              
88             sub _logbit {
89 0     0     my $self = shift;
90 0           my ( $pkg, $file, $line ) = $self->_caller();
91 0           $file = File::Spec->canonpath($file);
92 0           return "[$pkg, $file, $line] ";
93             }
94              
95             sub PRINT {
96 0     0     my $self = shift;
97 0     0     $self->{realout}->( sub { print $self->_logbit, @_ }, @_ );
  0            
98             }
99              
100             sub PRINTF {
101 0     0     my $self = shift;
102 0           $self->PRINT( sprintf $_[0], @_[ 1 .. $#_ ] );
103             }
104              
105             sub WRITE {
106 0     0     my $self = shift;
107             $self->{realout}->(
108             sub {
109 0     0     my ( $buf, $len, $offset ) = @_;
110 0 0         syswrite STDOUT, $buf, $len, defined $offset ? $offset : 0;
111             },
112             @_
113 0           );
114             }
115              
116             sub CLOSE {
117 0     0     my $self = shift;
118 0 0         if ( $self->{is_err} ) {
119 0           close REALSTDERR;
120             }
121             else {
122 0           close REALSTDOUT;
123             }
124             }
125              
126             1;
127             __END__