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   245 use strict; use warnings;
  58     58   85  
  58         1807  
  58         296  
  58         79  
  58         2190  
2             package IO::All::Base;
3              
4 58     58   262 use Fcntl;
  58         79  
  58         18184  
5              
6             sub import {
7 427     427   9609 my $class = shift;
8 427   100     1579 my $flag = $_[0] || '';
9 427         838 my $package = caller;
10 58     58   338 no strict 'refs';
  58         84  
  58         23678  
11 427 100       1350 if ($flag eq '-base') {
    50          
12 340         386 push @{$package . "::ISA"}, $class;
  340         3853  
13 2040         20967 *{$package . "::$_"} = \&$_
14 340         1350 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         168 my @flags = @_;
21 87         121 for my $export (@{$class . '::EXPORT'}) {
  87         2357  
22 63         17235 *{$package . "::$export"} = $export eq 'io'
  0         0  
23             ? $class->_generate_constructor(@flags)
24 63 50       487 : \&{$class . "::$export"};
25             }
26             }
27             }
28              
29             sub _generate_constructor {
30 63     63   113 my $class = shift;
31 63         102 my (@flags, %flags, $key);
32 63         183 for (@_) {
33 9 100       42 if (s/^-//) {
34 8         13 push @flags, $_;
35 8         13 $flags{$_} = 1;
36 8         12 $key = $_;
37             }
38             else {
39 1 50       4 $flags{$key} = $_ if $key;
40             }
41             }
42 63         86 my $constructor;
43             $constructor = sub {
44 632     632   49707 my $self = $class->new(@_);
45 632         1490 for (@flags) {
46 12         75 $self->$_($flags{$_});
47             }
48 631         1522 $self->_constructor($constructor);
49 631         2670 return $self;
50             }
51 63         440 }
52              
53             sub _init {
54 772     772   861 my $self = shift;
55 772         1691 $self->io_handle(undef);
56 772         1669 $self->is_open(0);
57 772         2221 return $self;
58             }
59              
60             #===============================================================================
61             # Closure generating functions
62             #===============================================================================
63             sub option {
64 560     560 0 795 my $package = caller;
65 560         678 my ($field, $default) = @_;
66 560   100     1741 $default ||= 0;
67 560         1114 field("_$field", $default);
68 58     58   316 no strict 'refs';
  58         83  
  58         7194  
69 560         2097 *{"${package}::$field"} =
70             sub {
71 25     25   15933 my $self = shift;
72 25 100       275 *$self->{"_$field"} = @_ ? shift(@_) : 1;
73 25         93 return $self;
74 560         1552 };
75             }
76              
77             sub chain {
78 373     373 0 1422 my $package = caller;
79 373         545 my ($field, $default) = @_;
80 58     58   295 no strict 'refs';
  58         92  
  58         6893  
81 373         1367 *{"${package}::$field"} =
82             sub {
83 6228     6228   7629 my $self = shift;
84 6228 100       9984 if (@_) {
85 1045         7896 *$self->{$field} = shift;
86 1045         2095 return $self;
87             }
88 5183 100       13482 return $default unless exists *$self->{$field};
89 3924         17903 return *$self->{$field};
90 373         1031 };
91             }
92              
93             sub field {
94 1173     1173 0 1741 my $package = caller;
95 1173         1282 my ($field, $default) = @_;
96 58     58   301 no strict 'refs';
  58         84  
  58         9626  
97 1173 50       919 return if defined &{"${package}::$field"};
  1173         5207  
98 1173         4608 *{"${package}::$field"} =
99             sub {
100 10229     10229   25420 my $self = shift;
101 10229 100       30129 unless (exists *$self->{$field}) {
102 3559 50       10775 *$self->{$field} =
    100          
103             ref($default) eq 'ARRAY' ? [] :
104             ref($default) eq 'HASH' ? {} :
105             $default;
106             }
107 10229 100       42608 return *$self->{$field} unless @_;
108 3990         7040 *$self->{$field} = shift;
109 1173         2986 };
110             }
111              
112             sub const {
113 95     95 0 304 my $package = caller;
114 95         220 my ($field, $default) = @_;
115 58     58   303 no strict 'refs';
  58         76  
  58         6226  
116 95 50       152 return if defined &{"${package}::$field"};
  95         1044  
117 95     178   573 *{"${package}::$field"} = sub { $default };
  95         1317  
  178         575  
118             }
119              
120             sub proxy {
121 348     348 0 466 my $package = caller;
122 348         388 my ($proxy) = @_;
123 58     58   294 no strict 'refs';
  58         67  
  58         7687  
124 348 50       281 return if defined &{"${package}::$proxy"};
  348         1297  
125 348         1075 *{"${package}::$proxy"} =
126             sub {
127 7     7   8 my $self = shift;
128 7         10 my @return = $self->io_handle->$proxy(@_);
129 7         41 $self->_error_check;
130 7 50       31 wantarray ? @return : $return[0];
131 348         968 };
132             }
133              
134             sub proxy_open {
135 356     356 0 457 my $package = caller;
136 356         530 my ($proxy, @args) = @_;
137 58     58   285 no strict 'refs';
  58         82  
  58         12836  
138 356 50       303 return if defined &{"${package}::$proxy"};
  356         1309  
139             my $method = sub {
140 60     60   103 my $self = shift;
141 60         218 $self->_assert_open(@args);
142 60         149 my @return = $self->io_handle->$proxy(@_);
143 60         1434 $self->_error_check;
144 60 50       183 wantarray ? @return : $return[0];
145 356         1051 };
146 356         1166 *{"$package\::$proxy"} =
147             (@args and $args[0] eq '>') ?
148             sub {
149 57     57   475 my $self = shift;
150 57         165 $self->$method(@_);
151 57         116 return $self;
152             }
153 356 100 100     1621 : $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   312 no strict 'refs';
  58         87  
  58         1699  
166 58     58   249 no warnings;
  58         74  
  58         7743  
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   274 no strict 'refs';
  58         103  
  58         6716  
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   307 no strict 'refs';
  58         80  
  58         7141  
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;