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   259 use strict; use warnings;
  58     58   75  
  58         1794  
  58         250  
  58         73  
  58         2111  
2             package IO::All::Base;
3              
4 58     58   246 use Fcntl;
  58         74  
  58         18239  
5              
6             sub import {
7 427     427   12372 my $class = shift;
8 427   100     1565 my $flag = $_[0] || '';
9 427         762 my $package = caller;
10 58     58   344 no strict 'refs';
  58         89  
  58         24095  
11 427 100       1352 if ($flag eq '-base') {
    50          
12 340         396 push @{$package . "::ISA"}, $class;
  340         4035  
13 2040         21829 *{$package . "::$_"} = \&$_
14 340         1454 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         167 my @flags = @_;
21 87         121 for my $export (@{$class . '::EXPORT'}) {
  87         2316  
22 63         16466 *{$package . "::$export"} = $export eq 'io'
  0         0  
23             ? $class->_generate_constructor(@flags)
24 63 50       484 : \&{$class . "::$export"};
25             }
26             }
27             }
28              
29             sub _generate_constructor {
30 63     63   107 my $class = shift;
31 63         99 my (@flags, %flags, $key);
32 63         176 for (@_) {
33 9 100       46 if (s/^-//) {
34 8         14 push @flags, $_;
35 8         15 $flags{$_} = 1;
36 8         15 $key = $_;
37             }
38             else {
39 1 50       3 $flags{$key} = $_ if $key;
40             }
41             }
42 63         84 my $constructor;
43             $constructor = sub {
44 632     632   54239 my $self = $class->new(@_);
45 632         1365 for (@flags) {
46 12         79 $self->$_($flags{$_});
47             }
48 631         1296 $self->_constructor($constructor);
49 631         2473 return $self;
50             }
51 63         430 }
52              
53             sub _init {
54 772     772   829 my $self = shift;
55 772         1483 $self->io_handle(undef);
56 772         1535 $self->is_open(0);
57 772         2065 return $self;
58             }
59              
60             #===============================================================================
61             # Closure generating functions
62             #===============================================================================
63             sub option {
64 560     560 0 778 my $package = caller;
65 560         697 my ($field, $default) = @_;
66 560   100     1728 $default ||= 0;
67 560         1108 field("_$field", $default);
68 58     58   319 no strict 'refs';
  58         83  
  58         7043  
69 560         2136 *{"${package}::$field"} =
70             sub {
71 25     25   16005 my $self = shift;
72 25 100       209 *$self->{"_$field"} = @_ ? shift(@_) : 1;
73 25         82 return $self;
74 560         1493 };
75             }
76              
77             sub chain {
78 373     373 0 484 my $package = caller;
79 373         1079 my ($field, $default) = @_;
80 58     58   288 no strict 'refs';
  58         72  
  58         7141  
81 373         1403 *{"${package}::$field"} =
82             sub {
83 6228     6228   6509 my $self = shift;
84 6228 100       8948 if (@_) {
85 1045         7893 *$self->{$field} = shift;
86 1045         1788 return $self;
87             }
88 5183 100       11624 return $default unless exists *$self->{$field};
89 3924         15472 return *$self->{$field};
90 373         1024 };
91             }
92              
93             sub field {
94 1173     1173 0 1421 my $package = caller;
95 1173         1388 my ($field, $default) = @_;
96 58     58   289 no strict 'refs';
  58         80  
  58         9500  
97 1173 50       1005 return if defined &{"${package}::$field"};
  1173         5105  
98 1173         4440 *{"${package}::$field"} =
99             sub {
100 10229     10229   12972 my $self = shift;
101 10229 100       28437 unless (exists *$self->{$field}) {
102 3559 50       9863 *$self->{$field} =
    100          
103             ref($default) eq 'ARRAY' ? [] :
104             ref($default) eq 'HASH' ? {} :
105             $default;
106             }
107 10229 100       40219 return *$self->{$field} unless @_;
108 3990         6264 *$self->{$field} = shift;
109 1173         2974 };
110             }
111              
112             sub const {
113 95     95 0 317 my $package = caller;
114 95         216 my ($field, $default) = @_;
115 58     58   295 no strict 'refs';
  58         96  
  58         6126  
116 95 50       160 return if defined &{"${package}::$field"};
  95         1003  
117 95     178   552 *{"${package}::$field"} = sub { $default };
  95         1521  
  178         621  
118             }
119              
120             sub proxy {
121 348     348 0 492 my $package = caller;
122 348         367 my ($proxy) = @_;
123 58     58   291 no strict 'refs';
  58         70  
  58         8152  
124 348 50       274 return if defined &{"${package}::$proxy"};
  348         1333  
125 348         1122 *{"${package}::$proxy"} =
126             sub {
127 7     7   11 my $self = shift;
128 7         19 my @return = $self->io_handle->$proxy(@_);
129 7         66 $self->_error_check;
130 7 50       51 wantarray ? @return : $return[0];
131 348         1019 };
132             }
133              
134             sub proxy_open {
135 356     356 0 475 my $package = caller;
136 356         516 my ($proxy, @args) = @_;
137 58     58   277 no strict 'refs';
  58         80  
  58         12905  
138 356 50       295 return if defined &{"${package}::$proxy"};
  356         1328  
139             my $method = sub {
140 60     60   90 my $self = shift;
141 60         234 $self->_assert_open(@args);
142 60         157 my @return = $self->io_handle->$proxy(@_);
143 60         1239 $self->_error_check;
144 60 50       192 wantarray ? @return : $return[0];
145 356         1003 };
146 356         1131 *{"$package\::$proxy"} =
147             (@args and $args[0] eq '>') ?
148             sub {
149 57     57   460 my $self = shift;
150 57         173 $self->$method(@_);
151 57         128 return $self;
152             }
153 356 100 100     1610 : $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   296 no strict 'refs';
  58         92  
  58         1658  
166 58     58   262 no warnings;
  58         79  
  58         7985  
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   298 no strict 'refs';
  58         92  
  58         6940  
177 0           my %methods = all_methods($mixin_class);
178 0           map {
179 0           $methods{$_}
180 0           ? ($_, \ &{"$methods{$_}\::$_"})
181 0 0         : ($_, \ &{"$mixin_class\::$_"})
182             } (keys %methods);
183             }
184              
185             sub all_methods {
186 58     58   295 no strict 'refs';
  58         75  
  58         7267  
187 0     0 0   my $class = shift;
188 0           my %methods = map {
189 0           ($_, $class)
190             } grep {
191 0 0         defined &{"$class\::$_"} and not /^_/
  0            
192 0           } keys %{"$class\::"};
193 0           return (%methods);
194             }
195              
196             1;