File Coverage

blib/lib/IO/TieCombine.pm
Criterion Covered Total %
statement 55 66 83.3
branch 5 8 62.5
condition n/a
subroutine 17 20 85.0
pod 7 7 100.0
total 84 101 83.1


line stmt bran cond sub pod time code
1 1     1   3453 use strict;
  1         4  
  1         62  
2 1     1   7 use warnings;
  1         1  
  1         112  
3             package IO::TieCombine;
4             # ABSTRACT: produce tied (and other) separate but combined variables
5             $IO::TieCombine::VERSION = '1.004';
6 1     1   89 use Carp ();
  1         3  
  1         32  
7 1     1   1589 use IO::TieCombine::Handle;
  1         4  
  1         39  
8 1     1   31181 use IO::TieCombine::Scalar;
  1         3  
  1         32  
9 1     1   1038 use Symbol ();
  1         1741  
  1         694  
10              
11             # =head1 SYNOPSIS
12             #
13             # First, we set up a bunch of access points:
14             #
15             # my $hub = IO::TieCombine->new;
16             #
17             # my $str_ref = $hub->scalar_ref('x');
18             # my $fh = $hub->fh('x');
19             # my $callback = $hub->callback('x');
20             #
21             # tie my $scalar, $hub, 'x';
22             # tie local *STDOUT, $hub, 'x';
23             #
24             # tie local *STDERR, $hub, 'err';
25             #
26             # Then we write to things:
27             #
28             # $$str_ref .= 'And ';
29             # print $fh "now ";
30             # $callback->('for ');
31             # $scalar .= 'something ';
32             # print "completely ";
33             # warn "different.\n";
34             #
35             # And then:
36             #
37             # $hub->combined_contents; # And now for something completely different.
38             # $hub->slot_contents('x'); # And now for something completely
39             # $hub->slot_contents('err'); # different.
40             #
41             # B Because of a serious problem with Perl 5.10.0, output sent to a
42             # tied filehandle using C B. 5.10.1 or
43             # later is needed. Since 5.10.0 is broken in so many other ways, you should
44             # really upgrade anyway.
45             #
46             # B Because of a different problem with Perls 5.10.1 - 5.16.3, if you
47             # send output to a tied filehandle using C, and C<$\> is undefined (which is
48             # the default), B<< C<$\> will not be restored to C after the C >>!
49             # This means that once you've used C to print to I tied filehandle, you
50             # have corrupted the global state of your program. Either start your program by
51             # setting C<$\> to an empty string, which should be safe, or upgrade to 5.18.0.
52             #
53             # =cut
54              
55             # =method new
56             #
57             # The constructor takes no arguments.
58             #
59             # =cut
60              
61             sub new {
62 1     1 1 1135 my ($class) = @_;
63              
64 1         10 my $self = {
65             combined => \(my $str = ''),
66             slots => { },
67             };
68              
69 1         9 bless $self => $class;
70             }
71              
72             # =method combined_contents
73             #
74             # This method returns the contents of all collected data.
75             #
76             # =cut
77              
78             sub combined_contents {
79 1     1 1 2 my ($self) = @_;
80 1         2 return ${ $self->{combined} };
  1         7  
81             }
82              
83             # =method slot_contents
84             #
85             # my $str = $hub->slot_contents( $slot_name );
86             #
87             # This method returns the contents of all collected data for the named slot.
88             #
89             # =cut
90              
91             sub slot_contents {
92 4     4 1 20 my ($self, $name) = @_;
93 4 50       14 Carp::confess("no name provided for slot_contents") unless defined $name;
94              
95 4 50       17 Carp::confess("no such output slot exists")
96             unless exists $self->{slots}{$name};
97              
98 4         5 return ${ $self->{slots}{$name} };
  4         27  
99             }
100              
101             sub _slot_ref {
102 6     6   12 my ($self, $name) = @_;
103 6 50       19 Carp::confess("no slot name provided") unless defined $name;
104              
105 6 100       25 $self->{slots}{$name} = \(my $str = '') unless $self->{slots}{$name};
106 6         35 return $self->{slots}{$name};
107             }
108              
109             sub _tie_args {
110 5     5   9 my ($self, $name) = @_;
111             return {
112 5         23 slot_name => $name,
113             combined_ref => $self->{combined},
114             output_ref => $self->_slot_ref($name),
115             };
116             }
117              
118             # =method clear_slot
119             #
120             # $hub->clear_slot( $slot_name );
121             #
122             # This sets the slot back to an empty string.
123             #
124             # =cut
125              
126             sub clear_slot {
127 1     1 1 3132 my ($self, $slot_name) = @_;
128 1         5 ${ $self->_slot_ref($slot_name) } = '';
  1         6  
129 1         2739 return;
130             }
131              
132             # =method fh
133             #
134             # my $fh = $hub->fh( $slot_name );
135             #
136             # This method returns a reference to a tied filehandle. When printed to, output
137             # is collected in the named slot.
138             #
139             # =cut
140              
141             sub fh {
142 2     2 1 12 my ($self, $name) = @_;
143              
144 2         10 my $sym = Symbol::gensym;
145 2         33 my ($class, @rest) = $self->_tie_fh_args($name);
146 2         16 tie *$sym, $class, @rest;
147 2         9 return $sym;
148             }
149              
150             sub TIEHANDLE {
151 0     0   0 my ($self, @args) = @_;
152 0         0 my ($class, @rest) = $self->_tie_fh_args(@args);
153              
154 0         0 return $class->TIEHANDLE(@rest);
155             }
156              
157             sub _tie_fh_args {
158 2     2   5 my ($self, $name) = @_;
159 2         7 return ('IO::TieCombine::Handle', $self->_tie_args($name));
160             }
161              
162             # =method scalar_ref
163             #
164             # my $str_ref = $hub->scalar_ref( $slot_name );
165             #
166             # This method returns a reference to scalar. When appended to, the new content
167             # is collected in the named slot. Attempting to alter the string other than by
168             # adding new content to its end will result in an exception.
169             #
170             # =cut
171              
172             sub scalar_ref {
173 2     2 1 12 my ($self, $name) = @_;
174 2         8 my ($class, @rest) = $self->_tie_scalar_args($name);
175 2         16 tie my($tie), $class, @rest;
176 2         10 return \$tie;
177             }
178              
179             sub TIESCALAR {
180 1     1   8 my ($self, @args) = @_;
181 1         4 my ($class, @rest) = $self->_tie_scalar_args(@args);
182              
183 1         8 return $class->TIESCALAR(@rest);
184             }
185              
186             sub _tie_scalar_args {
187 3     3   8 my ($self, $name) = @_;
188 3         10 return ('IO::TieCombine::Scalar', $self->_tie_args($name));
189             }
190              
191             # =method callback
192             #
193             # my $code = $hub->callback( $slot_name );
194             #
195             # =cut
196              
197             sub callback {
198 0     0 1   my ($self, $name) = @_;
199 0           my $slot = $self->_slot_ref($name);
200             return sub {
201 0     0     my ($value) = @_;
202              
203 0           ${ $slot } .= $value;
  0            
204 0           ${ $self->{combined} } .= $value;
  0            
205             }
206 0           }
207              
208             1;
209              
210             __END__