File Coverage

blib/lib/Tie/Subset/Hash.pm
Criterion Covered Total %
statement 48 58 82.7
branch 14 18 77.7
condition 3 6 50.0
subroutine 11 14 78.5
pod n/a
total 76 96 79.1


line stmt bran cond sub pod time code
1             #!perl
2             package Tie::Subset::Hash;
3 2     2   102973 use warnings;
  2         16  
  2         66  
4 2     2   11 use strict;
  2         4  
  2         38  
5 2     2   10 use warnings::register;
  2         4  
  2         278  
6 2     2   14 use Carp;
  2         3  
  2         1558  
7              
8             # For AUTHOR, COPYRIGHT, AND LICENSE see the bottom of this file
9              
10             =head1 Name
11              
12             Tie::Subset::Hash - Tie a hash to a subset of another hash
13              
14             =head1 Synopsis
15              
16             use Tie::Subset::Hash;
17             my %hash = ( foo=>11, bar=>22, quz=>33 );
18             tie my %subset, 'Tie::Subset::Hash', \%hash, ['bar','quz'];
19             print "$subset{bar}\n"; # prints "22"
20             $subset{quz}++; # modifies $hash{quz}
21              
22             =head1 Description
23              
24             This class for tied hashes provides a "view" of a subset of a hash.
25              
26             =over
27              
28             =cut
29              
30             our $VERSION = '0.01';
31              
32             =item Cing
33              
34             tie my %subset, 'Tie::Subset::Hash', \%hash, \@keys;
35              
36             You must specify which subset of keys from the original hash can
37             be accessed via the tied hash. (Keys that do not yet exist in the
38             original hash may be specified.)
39              
40             =cut
41              
42             sub TIEHASH { ## no critic (RequireArgUnpacking)
43 3 50   3   2137 @_==3 or croak "bad number of arguments to tie";
44 3         10 my ($class, $hash, $keys) = @_;
45 3 50       13 ref $hash eq 'HASH' or croak "must provide hashref to tie";
46 3 50       26 ref $keys eq 'ARRAY' or croak "must provide key list to tie";
47 3 50 33     10 for (@$keys) { croak "bad hash key '$_'" if ref || !defined }
  16         55  
48 3         16 my $self = { hash => $hash, keys => { map {$_=>1} @$keys } };
  16         42  
49 3         17 return bless $self, $class;
50             }
51              
52             =item Fetching
53              
54             If the key is in the subset, the value from the underlying hash is
55             returned, otherwise returns nothing (undef).
56              
57             =cut
58              
59             sub FETCH {
60 36     36   6630 my ($self,$key) = @_;
61 36 100       92 return unless exists $self->{keys}{$key};
62 30         78 return $self->{hash}{$key};
63             }
64              
65             =item Storing
66              
67             If the key is in the subset, the new value will be stored in the
68             underlying hash, otherwise the operation is ignored and a warning
69             issued.
70              
71             =cut
72              
73             sub STORE {
74 5     5   1579 my ($self,$key,$val) = @_;
75 5 100       19 if (exists $self->{keys}{$key}) {
76 3         16 return $self->{hash}{$key} = $val;
77             } # else
78 2         350 warnings::warnif("assigning to unknown key '$key' not (yet) supported in ".ref($self).", ignoring");
79 2         163 return;
80             }
81              
82             =item C
83              
84             Will return true only if the key is in the subset I it exists
85             in the underlying hash.
86              
87             =cut
88              
89             sub EXISTS {
90 25     25   284 my ($self,$key) = @_;
91 25   66     106 return exists $self->{keys}{$key} && exists $self->{hash}{$key};
92             }
93              
94             =item Iterating (C, C, etc.)
95              
96             Only keys that exist are both in the subset I the underlying
97             hash are iterated over.
98              
99             =cut
100              
101             sub FIRSTKEY {
102 9     9   3107 my ($self) = @_;
103 9         16 my $dummy = keys %{$self->{keys}}; # reset iterator
  9         31  
104 9         19 return $self->NEXTKEY;
105             }
106             sub NEXTKEY {
107 36     36   64 my ($self,$lkey) = @_;
108 36         57 my $next;
109             SEEK: {
110 36         50 $next = each %{$self->{keys}};
  55         60  
  55         95  
111 55 100       125 return unless defined $next;
112 46 100       95 redo SEEK unless exists $self->{hash}{$next};
113             }
114 27         67 return $next;
115             }
116              
117             =item Cing
118              
119             If the key is in the subset, the key will be deleted from the
120             underlying hash, but not the subset. Otherwise, the operation is
121             ignored and a warning issued.
122              
123             =cut
124              
125             sub DELETE {
126 6     6   1392 my ($self,$key) = @_;
127 6 100       17 if (exists $self->{keys}{$key}) {
128 4         22 return delete $self->{hash}{$key};
129             } # else
130 2         226 warnings::warnif("deleting unknown key '$key' not (yet) supported in ".ref($self).", ignoring");
131 2         92 return;
132             }
133              
134             =item Clearing
135              
136             Not (yet) supported (because it is ambiguous whether this operation
137             should delete keys from the underlying hash or not). Attempting to
138             clear the tied hash currently does nothing and causes a warning
139             to be issued.
140              
141             A future version of this module may lift this limitation (if a
142             useful default behavior exists).
143              
144             =cut
145              
146             sub CLEAR {
147 0     0     my ($self) = @_;
148 0           warnings::warnif("clearing of ".ref($self)." not (yet) supported, ignoring");
149 0           return;
150             }
151              
152             sub SCALAR {
153 0     0     my ($self) = @_;
154 0           return scalar %{$self->{keys}};
  0            
155             }
156              
157             sub UNTIE {
158 0     0     my ($self) = @_;
159 0           $self->{hash} = undef;
160 0           $self->{keys} = undef;
161 0           return;
162             }
163              
164             1;
165             __END__