File Coverage

blib/lib/Tie/Hash/CustomStorage.pm
Criterion Covered Total %
statement 86 107 80.3
branch 29 48 60.4
condition 4 6 66.6
subroutine 18 26 69.2
pod 0 3 0.0
total 137 190 72.1


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