File Coverage

blib/lib/RSH/SmartHash.pm
Criterion Covered Total %
statement 62 94 65.9
branch 10 24 41.6
condition 6 23 26.0
subroutine 13 19 68.4
pod 0 7 0.0
total 91 167 54.4


line stmt bran cond sub pod time code
1             # ------------------------------------------------------------------------------
2             # Copyright © 2003 by Matt Luker. All rights reserved.
3             #
4             # Revision:
5             #
6             # $Header$
7             #
8             # ------------------------------------------------------------------------------
9              
10             # SmartHash.pm - Hash with default values.
11             #
12             # SmartHash objects can also be given a callback method parameter to call when
13             # values are changed. This allows wrapping objects to implement "is dirty?"
14             # mechanisms.
15             #
16             # Change call back methods will be passed the object reference, the key name,
17             # the old value, and the new value. Callback methods are called AFTER the value
18             # has been changed.
19             #
20             # @author Matt Luker
21             # @version $Revision: 1327 $
22              
23             # SmartHash.pm - Hash with default values.
24             #
25             # Copyright (C) 2003, Matt Luker
26             #
27             # This library is free software; you can redistribute it and/or modify
28             # it under the same terms as Perl itself.
29              
30             # If you have any questions about this software,
31             # or need to report a bug, please contact me.
32             #
33             # Matt Luker
34             # Port Angeles, WA
35             # kostya@redstarhackers.com
36             #
37             # TTGOG
38              
39             package RSH::SmartHash;
40              
41 3     3   2722 use 5.008;
  3         12  
  3         162  
42 3     3   17 use strict;
  3         4  
  3         119  
43 3     3   17 use warnings;
  3         4  
  3         212  
44              
45             require Tie::Hash;
46              
47             our @ISA = qw(Tie::Hash);
48              
49 3     3   16 use RSH::Exception;
  3         5  
  3         3102  
50              
51             # ******************** PUBLIC Class Methods ********************
52              
53             sub merge_hashes {
54 0     0 0 0 my @hash_refs = @_;
55              
56 0 0       0 if (scalar(@hash_refs) == 0) { die new RSH::CodeException message => 'Please supply a hash reference.'; }
  0         0  
57              
58 0         0 for (my $i = 1; $i < scalar(@hash_refs); $i++) {
59 0 0       0 if (ref($hash_refs[$i]) ne 'HASH') { next; }
  0         0  
60 0         0 foreach my $key (keys %{$hash_refs[$i]}) {
  0         0  
61 0 0 0     0 if (defined($key) && defined($hash_refs[$i]->{$key})) {
62 0         0 $hash_refs[0]->{$key} = $hash_refs[$i]->{$key};
63             }
64             }
65             }
66              
67 0         0 return $hash_refs[0];
68             }
69            
70              
71             # ******************** CONSTRUCTOR Methods ********************
72              
73             sub new {
74 3     3 0 6 my $class = shift;
75 3         15 my %params = @_;
76              
77 3         7 my $default_vals = $params{default};
78 3         136 my $vals = $params{values};
79 3         7 my $change_callback = $params{change_callback};
80 3         7 my $dirty = $params{dirty};
81              
82 3         5 my $self = {};
83 3         7 $self->{default} = $default_vals;
84 3         8 $self->{hash} = $vals;
85 3 50 33     14 if ( (defined($change_callback)) &&
86             (ref($change_callback ne 'CODE')) ) {
87 0         0 $change_callback = undef;
88             }
89              
90 3         7 $self->{change_callback} = $change_callback;
91              
92 3 100       10 if (not defined($dirty)) {
93 1         2 $dirty = 0;
94             }
95              
96 3         13 $self->{dirty} = $dirty;
97            
98 3         17 bless $self, $class;
99 3         16 return $self;
100             }
101              
102             sub TIEHASH {
103 3     3   32 return (new @_);
104             }
105              
106             # ******************** PUBLIC Instance Methods ********************
107              
108             # ******************** Hash Tie Methods ********************
109              
110             sub STORE {
111 37     37   263 my $self = shift;
112 37         54 my $key = shift;
113 37         55 my $val = shift;
114              
115 37         77 my $old_val = $self->{hash}{$key};
116 37         80 $self->{hash}{$key} = $val;
117 37 50 33     305 if ( defined($old_val) &&
    50 33        
      0        
      0        
      33        
118             defined($val) &&
119             (ref($old_val) eq ref($val)) &&
120             defined(($old_val ne $val)) &&
121             ($old_val ne $val) ) {
122              
123 0         0 $self->{dirty} = 1;
124 0 0       0 if (defined($self->{change_callback})) {
125 0         0 &{$self->{change_callback}}($self, $key, $old_val, $val);
  0         0  
126             }
127             } elsif ( (not defined($old_val)) && (not defined($val) ) ) {
128             # NOTHING
129             } else {
130             # one is defined and one isn't, which is different--so ...
131 37         99 $self->{dirty} = 1;
132 37 100       688 if (defined($self->{change_callback})) {
133 1         7 &{$self->{change_callback}}($self, $key, $old_val, $val);
  1         5  
134             }
135             }
136             }
137              
138             sub FETCH {
139 207     207   286 my $self = shift;
140 207         227 my $key = shift;
141              
142 207 100       574 if (defined($self->{hash}{$key})) { return $self->{hash}{$key}; }
  191         677  
143 16         90 else { return $self->{default}{$key}; }
144              
145             }
146              
147             sub FIRSTKEY {
148 9     9   35 my $self = shift;
149              
150 9         14 my $a = keys %{$self->{hash}};
  9         30  
151 9         13 each %{$self->{hash}};
  9         58  
152             }
153              
154             sub NEXTKEY {
155 81     81   109 my $self = shift;
156 81         109 my $last_key = shift;
157 81         85 each %{$self->{hash}};
  81         844  
158             }
159              
160             sub EXISTS {
161 0     0   0 my $self = shift;
162 0         0 my $key = shift;
163              
164 0 0       0 if (not exists($self->{hash}{$key})) { return exists($self->{default}{$key}); }
  0         0  
165 0         0 else { return exists($self->{default}{$key}); }
166             }
167              
168             sub DELETE {
169 0     0   0 my $self = shift;
170 0         0 my $key = shift;
171              
172 0         0 delete $self->{hash}{$key};
173             }
174              
175             sub CLEAR {
176 3     3   7 my $self = shift;
177              
178 3         12 $self->{hash} = {};
179             }
180              
181             # ******************** Regular Instance Methods ********************
182              
183             sub default_hash {
184 0     0 0 0 my $self = shift;
185              
186 0         0 return $self->{default};
187             }
188              
189             # is_dirty
190             #
191             # Read-only accessor for the object's dirty flag. The dirty flag is set
192             # whenever a value is changed for the object's hash values.
193             #
194             sub is_dirty {
195 4     4 0 7 my $self = shift;
196              
197 4         47 return $self->{dirty};
198             }
199              
200             # dirty
201             #
202             # Read-write accessor for the dirty state of this object.
203             #
204             # params:
205             # val - new dirty state
206             #
207             sub dirty {
208 7     7 0 12 my $self = shift;
209 7         11 my $val = shift;
210              
211 7 50 100     30 if (defined($val)) { $self->{dirty} = ($val && 1); }
  7         28  
212              
213 7         25 return $self->{dirty};
214             }
215              
216             # merge
217             #
218             # Merges the values of a hash reference into this object.
219             #
220             sub merge {
221 0     0 0   my $self = shift;
222            
223 0           merge_hashes($self, @_);
224             }
225              
226             # rollback_value
227             #
228             # Rollback the value. Works like the Tie STORE, but does not call the
229             # change callback method (prevents an endless loop).
230             #
231             sub rollback_value {
232 0     0 0   my $self = shift;
233 0           my $key = shift;
234 0           my $old_val = shift;
235              
236 0           $self->{hash}{$key} = $old_val;
237             }
238              
239             # #################### SmartHash.pm ENDS ####################
240             1;
241             # ------------------------------------------------------------------------------
242             #
243             # $Log$
244             # Revision 1.4 2004/04/09 06:18:26 kostya
245             # Added quote escaping capabilities.
246             #
247             # Revision 1.3 2003/10/15 01:07:00 kostya
248             # documentation and license updates--everything is Artistic.
249             #
250             # Revision 1.2 2003/10/14 22:49:32 kostya
251             # Added the merge functions for combining settings.
252             #
253             # Revision 1.1.1.1 2003/10/13 01:38:04 kostya
254             # First import
255             #
256             #
257             # ------------------------------------------------------------------------------
258              
259             __END__