File Coverage

blib/lib/Tie/Array/CustomStorage.pm
Criterion Covered Total %
statement 82 105 78.1
branch 29 52 55.7
condition 4 6 66.6
subroutine 17 23 73.9
pod 0 3 0.0
total 132 189 69.8


line stmt bran cond sub pod time code
1             package Tie::Array::CustomStorage ;
2              
3 1     1   42322 use warnings ;
  1         2  
  1         36  
4 1     1   7 use Carp;
  1         2  
  1         90  
5 1     1   6 use strict;
  1         8  
  1         69  
6              
7 1     1   6 use vars qw($VERSION) ;
  1         1  
  1         86  
8             $VERSION = sprintf "%d.%03d", q$Revision: 1.1 $ =~ /(\d+)\.(\d+)/;
9              
10 1     1   6 use base qw/Tie::Array/;
  1         89  
  1         2008  
11              
12             # if not init or tie_array or init parameter is given, behaves exactly
13             # as a standard array
14              
15             sub TIEARRAY
16             {
17 5     5   3265 my $type = shift ;
18 5         20 my %args = @_ ;
19              
20 5         12 my @data = () ;
21 5         11 my $autovivify = 1 ;
22              
23 5         16 my $self = { data => \@data } ;
24              
25             my $load = sub
26             {
27 4     4   12 my $file = $_[0].'.pm';
28 4         13 $file =~ s!::!/!g;
29 4 100       5 require $file unless defined *{$_[0].'::'} ;
  4         477  
30 5         20 };
31              
32 5 50       20 if (defined $args{autovivify})
33             {
34 0         0 $autovivify = delete $args{autovivify} ;
35             }
36              
37             # applied to array containing the storage
38 5 100       16 if (defined $args{tie_array})
39             {
40 1         4 my $p = delete $args{tie_array} ;
41 1 50       6 my ($class, @args) = ref $p ? @$p : ($p) ;
42 1         3 $load->($class) ;
43 1         6 $self->{tie_array_obj} = tie @data, $class, @args ;
44             }
45              
46 5         18 my $init_obj = delete $args{init_object} ;
47              
48             # applied to storage
49 5 100       26 if (defined $args{class_storage})
    100          
    100          
50             {
51 1         3 my $p = delete $args{class_storage} ;
52 1 50       5 my ($class, @args) = ref $p ? @$p : ($p) ;
53 1         4 $load->($class) ;
54              
55             $self->{init} = $autovivify ?
56             sub
57             {
58 2     2   4 my $idx = shift ;
59 2   66     13 my $obj = shift || $class -> new (@args) ;
60 2 50       21 $init_obj->($obj,$idx) if defined $init_obj ;
61              
62 2         12 $self->{data}[$idx] = $obj ;
63 1 50   0   28 } : sub {} ;
  0         0  
64              
65 1         4 $self->{class_storage} = $class ;
66             }
67             elsif (defined $args{tie_storage})
68             {
69 2         6 my $p = delete $args{tie_storage} ;
70 2 50       11 my ($class, @args) = ref $p ? @$p : ($p) ;
71 2         7 $load->($class) ;
72             $self->{init} = sub
73             {
74             #print "storage init with tie_storage\n";
75 4     4   14 my $ref = $self->get_storage_ref($_[0]) ;
76 4         22 my $obj = tie $$ref, $class, @args ;
77 4 100       97 $init_obj->($obj,$_[0]) if defined $init_obj ;
78 2         2493 } ;
79             }
80             elsif (defined $args{init_storage})
81             {
82 1         2 my ($init_method, @args) = @{delete $args{init_storage}} ;
  1         5  
83             $self->{init} = sub
84             {
85             #print "storage init with init\n";
86 2     2   9 my $ref = $self->get_storage_ref($_[0]) ;
87 2         8 $init_method->($ref, @args)
88 1         7 } ;
89             }
90             else
91             {
92 1     3   4 $self->{init} = sub {} ;
  3         27  
93             }
94              
95 5 50       17 croak __PACKAGE__,": Unexpected TIEARRAY argument: ",
96             join(' ',keys %args) if %args ;
97              
98 5         46 bless $self, $type ;
99             }
100              
101             # this one is tricky, all direct method calls to this class must be
102             # forwarded to the tied object hidden behind the @data array
103             sub AUTOLOAD
104             {
105 0     0   0 our $AUTOLOAD ;
106 0         0 my $self=shift ;
107 0         0 my $obj = $self->{tie_array_obj} ;
108              
109 0 0       0 if (defined $obj)
110             {
111 0         0 my ($pack,$method) = ($AUTOLOAD =~ /(.*)::(\w+)/) ;
112 0         0 $obj->$method(@_) ;
113             }
114             else
115             {
116 0         0 croak "Undefined subroutine $AUTOLOAD called";
117             }
118             }
119              
120             sub FETCH
121             {
122 12     12   3903 my ($self,$idx) = @_ ;
123              
124             #print "TieArray: fetch idx $idx\n";
125 12 100       59 $self->{init}->($idx) unless defined $self->{data}[$idx] ;
126              
127 12         77 return $self->{data}[$idx] ;
128             }
129              
130             # Implementation note: The tie must be applied to the variable which
131             # is actually stored. For a standard array this variable is
132             # $self->{$name}[$key]. For a tied array, the actual variable is hidden
133             # within the tied array. The code will find the actual location if the
134             # tied array inherits from StdArray or if the tied array follows the
135             # example of the camel book (e.g. $self->{DATA} or $self->{data}). If
136             # all fails, the user's tied array must provide a get_data_ref method
137             # that give a ref to the actual location of the variable to be tied.
138              
139             sub get_storage_ref
140             {
141 7     7 0 15 my ($self,$idx) = @_ ;
142 7         20 my $h_obj = $self->get_user_tied_array_object ;
143              
144 7 50       43 return \$self->{data}[$idx] unless defined $h_obj;
145              
146             # print "get_scalar_ref called for $h_obj,$idx\n";
147 0 0       0 return $h_obj->isa('Tie::StdArray') ? \$h_obj->[$idx] :
    0          
    0          
    0          
148             defined $h_obj->{DATA} ? \$h_obj->{DATA}[$idx] :
149             defined $h_obj->{data} ? \$h_obj->{data}[$idx] :
150             $h_obj->can('get_data_ref') ? $h_obj->get_data_ref($idx):
151             die ref($h_obj)," must provide a get_data_ref method" ;
152             }
153              
154             sub get_user_tied_array_object
155             {
156 7     7 0 9 my $self = shift ;
157 7         11 return tied @{$self->{data}} ;
  7         19  
158             }
159              
160             sub get_tied_storage_object
161             {
162 1     1 0 3 my ($self,$idx) = @_ ;
163 1 50       15 $self->{init}->($idx) unless defined $self->{data}[$idx] ;
164             #print "TieArray: get_storage on idx $idx\n";
165 1         11 my $r = $self->get_storage_ref($idx) ;
166 1         5 tied ($$r) ;
167             }
168              
169             sub STORE
170             {
171 7     7   4736 my ($self,$idx, $data) = @_ ;
172              
173             #print "TieArray: store idx $idx, data ", defined $data ? $data : 'UNDEF', " (", join('~', @{$self->{data}}),")\n";
174              
175 7         11 my @args;
176 7 100 66     39 if (defined $self->{class_storage} and defined $data)
177             {
178 2 100       8 if (ref($data) eq $self->{class_storage})
179             {
180             # provided object will be run through init process
181 1         5 $self->{init}->($idx,$data) ;
182 1         4 return $self->{data}[$idx] ;
183             }
184             else
185             {
186 1         222 croak ref($self),": wrong object assigned to index '$idx'. ",
187             "Expected '$self->{class_storage}', got '",ref($data),"'" ;
188             }
189             }
190              
191 5 100       28 $self->{init}->($idx,$data) unless defined $self->{data}[$idx] ;
192              
193 5         28 return $self->{data}[$idx] = $data ;
194             }
195              
196              
197             sub STORESIZE
198             {
199 0     0   0 my ($self,$size) = @_ ;
200              
201 0         0 my $old = scalar @{$self->{data}} ;
  0         0  
202              
203 0 0       0 return if $old == $size ;
204              
205 0 0       0 if ($size < $old) {
206             #print "Reducing array from $old to $size elements\n";
207 0         0 $#{$self->{data}} = $size -1 ;
  0         0  
208 0         0 return ;
209             }
210              
211             #print "Growing array from $old to $size elements\n";
212              
213 0         0 for (my $i = $old; $i<$size; $i++) {
214 0         0 $self->{init}->($i);
215             }
216              
217             }
218              
219 4     4   2202 sub FETCHSIZE { scalar @{$_[0]->{data}} }
  4         26  
220              
221              
222 0     0     sub EXISTS { exists $_[0]->{data}[$_[1]] ;}
223 0     0     sub DELETE { delete $_[0]->{data}[$_[1]] ;}
224              
225 0     0     sub DESTROY {}
226              
227             1;
228              
229             __END__