File Coverage

blib/lib/IO/All/Base.pm
Criterion Covered Total %
statement 136 165 82.4
branch 28 46 60.8
condition 7 7 100.0
subroutine 31 34 91.1
pod 0 9 0.0
total 202 261 77.3


line stmt bran cond sub pod time code
1 58     58   416 use strict; use warnings;
  58     58   150  
  58         1805  
  58         361  
  58         152  
  58         2449  
2             package IO::All::Base;
3              
4 58     58   385 use Fcntl;
  58         147  
  58         19447  
5              
6             sub import {
7 427     427   10797 my $class = shift;
8 427   100     1950 my $flag = $_[0] || '';
9 427         1162 my $package = caller;
10 58     58   460 no strict 'refs';
  58         145  
  58         31859  
11 427 100       1701 if ($flag eq '-base') {
    50          
12 340         705 push @{$package . "::ISA"}, $class;
  340         4440  
13 2040         23790 *{$package . "::$_"} = \&$_
14 340         1660 for qw'field const option chain proxy proxy_open';
15             }
16             elsif ($flag eq -mixin) {
17 0         0 mixin_import(scalar(caller(0)), $class, @_);
18             }
19             else {
20 87         284 my @flags = @_;
21 87         191 for my $export (@{$class . '::EXPORT'}) {
  87         2338  
22 63         17427 *{$package . "::$export"} = $export eq 'io'
23             ? $class->_generate_constructor(@flags)
24 63 50       1452 : \&{$class . "::$export"};
  0         0  
25             }
26             }
27             }
28              
29             sub _generate_constructor {
30 63     63   219 my $class = shift;
31 63         259 my (@flags, %flags, $key);
32 63         234 for (@_) {
33 9 100       41 if (s/^-//) {
34 8         20 push @flags, $_;
35 8         38 $flags{$_} = 1;
36 8         17 $key = $_;
37             }
38             else {
39 1 50       3 $flags{$key} = $_ if $key;
40             }
41             }
42 63         153 my $constructor;
43             $constructor = sub {
44 636     636   66335 my $self = $class->new(@_);
45 636         1794 for (@flags) {
46 12         78 $self->$_($flags{$_});
47             }
48 635         2017 $self->_constructor($constructor);
49 635         3007 return $self;
50             }
51 63         453 }
52              
53             sub _init {
54 777     777   1442 my $self = shift;
55 777         2546 $self->io_handle(undef);
56 777         2379 $self->is_open(0);
57 777         2656 return $self;
58             }
59              
60             #===============================================================================
61             # Closure generating functions
62             #===============================================================================
63             sub option {
64 560     560 0 1272 my $package = caller;
65 560         1299 my ($field, $default) = @_;
66 560   100     2999 $default ||= 0;
67 560         2076 field("_$field", $default);
68 58     58   542 no strict 'refs';
  58         152  
  58         7999  
69 560         3004 *{"${package}::$field"} =
70             sub {
71 25     25   16261 my $self = shift;
72 25 100       199 *$self->{"_$field"} = @_ ? shift(@_) : 1;
73 25         119 return $self;
74 560         2411 };
75             }
76              
77             sub chain {
78 373     373 0 1049 my $package = caller;
79 373         985 my ($field, $default) = @_;
80 58     58   487 no strict 'refs';
  58         153  
  58         7945  
81 373         2035 *{"${package}::$field"} =
82             sub {
83 6257     6257   12656 my $self = shift;
84 6257 100       14269 if (@_) {
85 1050         5788 *$self->{$field} = shift;
86 1050         2714 return $self;
87             }
88 5207 100       17037 return $default unless exists *$self->{$field};
89 3942         19585 return *$self->{$field};
90 373         1410 };
91             }
92              
93             sub field {
94 1173     1173 0 2540 my $package = caller;
95 1173         2768 my ($field, $default) = @_;
96 58     58   419 no strict 'refs';
  58         164  
  58         11792  
97 1173 50       2451 return if defined &{"${package}::$field"};
  1173         7541  
98 1173         6443 *{"${package}::$field"} =
99             sub {
100 10605     10605   23564 my $self = shift;
101 10605 100       36756 unless (exists *$self->{$field}) {
102 3716 50       13501 *$self->{$field} =
    100          
103             ref($default) eq 'ARRAY' ? [] :
104             ref($default) eq 'HASH' ? {} :
105             $default;
106             }
107 10605 100       52055 return *$self->{$field} unless @_;
108 4012         9704 *$self->{$field} = shift;
109 1173         5514 };
110             }
111              
112             sub const {
113 95     95 0 434 my $package = caller;
114 95         396 my ($field, $default) = @_;
115 58     58   446 no strict 'refs';
  58         469  
  58         7022  
116 95 50       223 return if defined &{"${package}::$field"};
  95         1410  
117 95     176   663 *{"${package}::$field"} = sub { $default };
  95         721  
  176         832  
118             }
119              
120             sub proxy {
121 348     348 0 765 my $package = caller;
122 348         887 my ($proxy) = @_;
123 58     58   486 no strict 'refs';
  58         143  
  58         9127  
124 348 50       757 return if defined &{"${package}::$proxy"};
  348         1891  
125 348         1688 *{"${package}::$proxy"} =
126             sub {
127 7     7   9 my $self = shift;
128 7         15 my @return = $self->io_handle->$proxy(@_);
129 7         50 $self->_error_check;
130 7 50       41 wantarray ? @return : $return[0];
131 348         1750 };
132             }
133              
134             sub proxy_open {
135 356     356 0 839 my $package = caller;
136 356         1031 my ($proxy, @args) = @_;
137 58     58   442 no strict 'refs';
  58         164  
  58         15892  
138 356 50       645 return if defined &{"${package}::$proxy"};
  356         1724  
139             my $method = sub {
140 60     60   153 my $self = shift;
141 60         315 $self->_assert_open(@args);
142 60         233 my @return = $self->io_handle->$proxy(@_);
143 60         1698 $self->_error_check;
144 60 50       254 wantarray ? @return : $return[0];
145 356         1804 };
146 356         1803 *{"$package\::$proxy"} =
147             (@args and $args[0] eq '>') ?
148             sub {
149 57     57   564 my $self = shift;
150 57         253 $self->$method(@_);
151 57         184 return $self;
152             }
153 356 100 100     2231 : $method;
154             }
155              
156             sub mixin_import {
157 0     0 0   my $target_class = shift;
158 0 0         $target_class = caller(0)
159             if $target_class eq 'mixin';
160 0 0         my $mixin_class = shift
161             or die "Nothing to mixin";
162 0           eval "require $mixin_class";
163 0           my $pseudo_class = CORE::join '-', $target_class, $mixin_class;
164 0           my %methods = mixin_methods($mixin_class);
165 58     58   487 no strict 'refs';
  58         172  
  58         2009  
166 58     58   376 no warnings;
  58         142  
  58         9244  
167 0           @{"$pseudo_class\::ISA"} = @{"$target_class\::ISA"};
  0            
  0            
168 0           @{"$target_class\::ISA"} = ($pseudo_class);
  0            
169 0           for (keys %methods) {
170 0           *{"$pseudo_class\::$_"} = $methods{$_};
  0            
171             }
172             }
173              
174             sub mixin_methods {
175 0     0 0   my $mixin_class = shift;
176 58     58   492 no strict 'refs';
  58         165  
  58         7756  
177 0           my %methods = all_methods($mixin_class);
178             map {
179 0           $methods{$_}
180 0           ? ($_, \ &{"$methods{$_}\::$_"})
181 0 0         : ($_, \ &{"$mixin_class\::$_"})
  0            
182             } (keys %methods);
183             }
184              
185             sub all_methods {
186 58     58   434 no strict 'refs';
  58         165  
  58         7983  
187 0     0 0   my $class = shift;
188             my %methods = map {
189 0           ($_, $class)
190             } grep {
191 0 0         defined &{"$class\::$_"} and not /^_/
  0            
192 0           } keys %{"$class\::"};
  0            
193 0           return (%methods);
194             }
195              
196             1;