File Coverage

blib/lib/Hash/AutoHash.pm
Criterion Covered Total %
statement 280 285 98.2
branch 80 88 90.9
condition 16 18 88.8
subroutine 51 53 96.2
pod 1 1 100.0
total 428 445 96.1


line stmt bran cond sub pod time code
1             package Hash::AutoHash;
2             our $VERSION='1.17_01';
3             $VERSION=eval $VERSION; # I think this is the accepted idiom..
4              
5             #################################################################################
6             #
7             # Author: Nat Goodman
8             # Created: 09-02-24
9             # $Id:
10             #
11             # Wrapper that provides accessor and mutator methods for hashes (real or tied)
12             # Hash can be externally supplied or this object itself
13             # Tying of hash can be done by application or by this class
14             # Can also wrap object tied to hash
15             # (actually, any object with suitable FETCH and STORE methods)
16             #
17             #################################################################################
18              
19 30     30   1260309 use strict;
  30         52  
  30         897  
20 30     30   128 use Carp;
  30         37  
  30         2050  
21 30     30   142 use vars qw($AUTOLOAD);
  30         46  
  30         13626  
22             our @CONSTRUCTORS_EXPORT_OK=
23             qw(autohash_new autohash_hash autohash_tie autohash_wrap autohash_wrapobj autohash_wraptie);
24             our @SUBCLASS_EXPORT_OK=
25             qw(autohash_clear autohash_delete autohash_each autohash_exists autohash_keys autohash_values
26             autohash_get autohash_set autohash_count autohash_empty autohash_notempty
27             autohash_alias autohash_tied
28             autohash_destroy autohash_untie);
29             our @EXPORT_OK=(@CONSTRUCTORS_EXPORT_OK,@SUBCLASS_EXPORT_OK);
30              
31             # following are used by subclasses
32             our @RENAME_EXPORT_OK=();
33             our %RENAME_EXPORT_OK=();
34              
35             # our @EXPORT_OK=qw(autohash_new autohash_tie
36             # autohash_wraphash autohash_wraptie autohash_wrapobject
37             # autohash2hash autohash2object
38             # autohash_clear autohash_delete autohash_exists autohash_keys autohash_values
39             # autohash_count autohash_empty autohash_notempty
40             # autohash_destroy autohash_untie
41             # autohash_get autohash_set);
42              
43             sub import {
44 142     142   103207 my $class_or_self=shift;
45 142 100       407 if (ref $class_or_self) {
46             # called as object method. access hash slot via AUTOLOAD
47 11         67 $AUTOLOAD='import';
48 11         25 return $class_or_self->AUTOLOAD(@_);
49             }
50             # called as class method. do regular 'import'
51 131         233 my $caller=caller;
52 131         288 my $helper_class=$class_or_self.'::helper';
53 131         484 $helper_class->_import($class_or_self,$caller,@_);
54             }
55             sub new {
56 79     79 1 90851 my $class_or_self=shift;
57 79 100       227 if (ref $class_or_self) {
58             # called as object method. access hash slot via AUTOLOAD
59 12         16 $AUTOLOAD='new';
60 12         25 return $class_or_self->AUTOLOAD(@_);
61             }
62             # called as class method. do regular 'new' via helper class
63 67         144 my $helper_class=$class_or_self.'::helper';
64 67         280 $helper_class->_new($class_or_self,@_);
65             }
66             # NG 12-09-02: no longer possible to use method notation for keys with same names as methods
67             # inherited from UNIVERSAL. 'Cuz as of Perl 5.9.3, calling UNIVERSAL methods as
68             # functions is deprecated and developers encouraged to use method form instead.
69             # sub can {
70             # my $class_or_self=shift;
71             # if (ref $class_or_self) {
72             # # called as object method. access hash slot via AUTOLOAD
73             # $AUTOLOAD='can';
74             # return $class_or_self->AUTOLOAD(@_);
75             # }
76             # # called as class method. do regular 'can' via base class
77             # return $class_or_self->SUPER::can(@_);
78             # }
79             # sub isa {
80             # my $class_or_self=shift;
81             # if (ref $class_or_self) {
82             # # called as object method. access hash slot via AUTOLOAD
83             # $AUTOLOAD='isa';
84             # return $class_or_self->AUTOLOAD(@_);
85             # }
86             # # called as function or class method. do regular 'isa' via base class
87             # return $class_or_self->SUPER::isa(@_);
88             # }
89             # sub DOES { # in perl 5.10, UNIVERSAL provides this
90             # my $class_or_self=shift;
91             # if (ref $class_or_self) {
92             # # called as object method. access hash slot via AUTOLOAD
93             # $AUTOLOAD='DOES';
94             # return $class_or_self->AUTOLOAD(@_);
95             # }
96             # # called as function or class method. do regular 'DOES' via base class
97             # # illegal and will die in perls < 5.10
98             # return $class_or_self->SUPER::DOES(@_);
99             # }
100             # sub VERSION {
101             # my $class_or_self=shift;
102             # if (ref $class_or_self) {
103             # # called as object method. access hash slot via AUTOLOAD
104             # $AUTOLOAD='VERSION';
105             # return $class_or_self->AUTOLOAD(@_);
106             # }
107             # # called as function or class method. do regular 'VERSION' via base class
108             # return $class_or_self->SUPER::VERSION(@_);
109             # }
110             sub DESTROY {
111             # CAUTION: do NOT shift - need $_[0] intact
112 772 50   772   1843525 if (ref($_[0])) {
113             # called as object method. inish up in helper class where namespace more complete
114 772         1894 my $helper_class=ref($_[0]).'::helper';
115 772         1084 my $helper_function=__PACKAGE__.'::helper::_destroy';
116 772         3387 return $helper_class->$helper_function(@_);
117             }
118             # called as class method. pass to base class. not sure this ever happens...
119 0         0 my $class_or_self=shift;
120 0         0 return $class_or_self->SUPER::DESTROY(@_);
121             }
122              
123             # my $self=$_[0]; # CAUTION: do NOT shift - need $_[0] intact
124             # return unless ref $self; # shouldn't happen, but...
125             # if (@_==1) { # called as destructor or accessor
126             # # perlobj says that $_[0] is read-only when DESTROY called as destructor
127             # local $@=undef;
128             # eval { $_[0]=undef };
129             # return if $@; # eval failed, so it's destructor.
130             # $_[0]=$self; # not destructor. restore $_[0]
131             # }
132             # # not destructor. access hash slot via AUTOLOAD
133             # shift; # now shift $self out of @_
134             # $AUTOLOAD='DESTROY';
135             # $self->AUTOLOAD(@_)
136              
137             sub AUTOLOAD {
138 1785     1785   1646976 my $self=shift;
139 1785         7773 $AUTOLOAD=~s/^.*:://; # strip class qualification
140             # return if $AUTOLOAD eq 'DESTROY'; # the books say you should do this
141 1785         2212 my $key=$AUTOLOAD;
142 1785 100       3498 defined $key or $key='AUTOLOAD';
143 1785         1577 $AUTOLOAD=undef; # reset for next time
144             # finish up in helper class where namespace more complete
145 1785         1783 my $helper_function=__PACKAGE__.'::helper::_autoload';
146 1785         4366 $self->$helper_function($key,@_);
147             }
148              
149             #################################################################################
150             # helper package exists to avoid polluting Hash::AutoHash namespace with
151             # subs that would mask accessor/mutator AUTOLOADs
152             # functions herein (except _new, _autoload) are exportable by Hash::AutoHash
153             #################################################################################
154             package Hash::AutoHash::helper;
155             our $VERSION=$Hash::AutoHash::VERSION;
156 30     30   174 use strict;
  30         62  
  30         793  
157 30     30   130 use Carp;
  30         44  
  30         1698  
158 30     30   147 use Scalar::Util qw(blessed readonly reftype);
  30         43  
  30         1812  
159 30     30   1695 use List::MoreUtils qw(uniq);
  30         32268  
  30         230  
160 30     30   26877 use Tie::ToObject;
  30         9496  
  30         1006  
161 30     30   154 use vars qw(%SELF2HASH %SELF2OBJECT %SELF2EACH %CLASS2ANCESTORS %EXPORT_OK);
  30         56  
  30         3034  
162              
163             sub _import {
164 131     131   288 my($helper_class,$class,$caller,@want)=@_;
165 131         303 $helper_class->EXPORT_OK; # initializes %EXPORT_OK if necessary
166 30     30   369 no strict 'refs';
  30         42  
  30         3300  
167 131         119 my %caller2export=%{$class.'::EXPORT_OK'};
  131         1390  
168             # my @export_ok=keys %caller2export;
169 131         60322 for my $want (@want) {
170 231 100       1949 confess("\"$want\" not exported by $class module") unless exists $caller2export{$want};
171 224 100       647 confess("\"$want\" not defined by $class module") unless defined $caller2export{$want};
172 222         293 my $caller_sym=$caller.'::'.$want;
173 222         211 my $export_sym=$caller2export{$want};
174 30     30   136 no strict 'refs';
  30         33  
  30         9715  
175 222         174 *{$caller_sym}=\&{$export_sym};
  222         44824  
  222         450  
176             }
177             }
178            
179             # front-end to autohash_new constructor function, which in turn is front-end
180             # to other constructor functions.
181             sub _new {
182 57     57   131 my($helper_class,$class)=splice @_,0,2;
183 57         148 my $self=autohash_new(@_);
184 57         208 bless $self,$class; # re-bless in case called via subclass
185             }
186              
187             sub _destroy {
188 772     772   1061 my $helper_class=shift;
189             # $_[0] is now original object.
190             # CAUTION: do NOT shift further - need $_[0] intact
191             # perlobj says that $_[0] is read-only when DESTROY called as destructor
192 772 100 100     8341 return if @_==1 && readonly($_[0]); # destructor. nothing to do.
193             # not destructor. access hash slot via AUTOLOAD
194 11         11 my $self=shift;
195 11         13 my $helper_function=__PACKAGE__.'::_autoload';
196 11         24 $self->$helper_function('DESTROY',@_)
197             }
198              
199             sub _autoload {
200 1796     1796   2925 my($self,$key)=splice(@_,0,2);
201 1796 100       3270 if (my $object=tied %$self) { # tied hash, so invoke FETCH/STORE methods
202 1184 100       3640 return @_==0? $object->FETCH($key): $object->STORE($key,@_);
203             } else { # regular hash
204 612 100       2485 return @_==0? ($self->{$key}): ($self->{$key}=$_[0]);
205             }
206             }
207              
208             # use vars qw(%CLASS2ANCESTORS);
209             sub _ancestors {
210 42     42   71 my($class,$visited)=@_;
211 42         69 my $ancestors=$CLASS2ANCESTORS{$class};
212 42 100       128 defined $visited or $visited={};
213 42 50 66     203 unless (defined($ancestors) || $visited->{$class}) {
214             # first call, so compute it
215 36         80 $ancestors=[$class]; # include self
216 36         73 $visited->{$class}++;
217 36         1037 my @isa;
218 30     30   166 {no strict "refs"; @isa = @{ $class . '::ISA' };}
  30         29  
  30         5651  
  36         40  
  36         45  
  36         504  
219 36         85 for my $super (@isa) {
220 6         22 push(@$ancestors,_ancestors($super,$visited));
221             }
222 36         235 @$ancestors=uniq(@$ancestors);
223 36         119 $CLASS2ANCESTORS{$class}=$ancestors
224             }
225 42 100       166 wantarray? @$ancestors: $ancestors;
226             }
227              
228             sub EXPORT_OK {
229 149     149   2662 my $helper_class=shift;
230 149         731 my($class)=$helper_class=~/^(.*)::helper$/;
231             # for Hash::AutoHash::helper, @EXPORT_OK is given and function computes %EXPORT_OK
232 149 100       398 if ($helper_class eq __PACKAGE__) { # NOTE: change this if you copy-and-paste into subclass
233 30     30   160 no strict 'refs';
  30         33  
  30         3451  
234 113         104 my $export_ok_list=\@{$class.'::EXPORT_OK'};
  113         337  
235 113         123 my $export_ok_hash=\%{$class.'::EXPORT_OK'};
  113         231  
236 113 100       289 unless(%$export_ok_hash) {
237 30         97 my $ancestors=$helper_class->_ancestors;
238 30         56 for my $func (@$export_ok_list) {
239 630         778 $export_ok_hash->{$func}=_export_sym($func,$class,$ancestors);
240             }}
241 113         261 return @$export_ok_list;
242             }
243             # for subclasses, @EXPORT_OK and %EXPORT_OK must both be computed
244 36         42 my($export_ok_list,$export_ok_hash,@isa,@normal_export_ok,@rename_export_ok,%rename_export_ok);
245             {
246 30     30   179 no strict 'refs';
  30         38  
  30         10729  
  36         32  
247 36         36 $export_ok_list=\@{$class.'::EXPORT_OK'};
  36         99  
248             # NG 12-11-29: 'defined @array' deprecated in 5.16 or so
249             # return @$export_ok_list if defined @$export_ok_list;
250 36 100       180 return @$export_ok_list if @$export_ok_list;
251 6         8 $export_ok_hash=\%{$class.'::EXPORT_OK'};
  6         19  
252 6         8 @isa=@{$helper_class.'::ISA'};
  6         26  
253 6         9 @normal_export_ok=@{$class.'::NORMAL_EXPORT_OK'};
  6         19  
254 6         8 @rename_export_ok=@{$class.'::RENAME_EXPORT_OK'};
  6         17  
255 6         7 %rename_export_ok=%{$class.'::RENAME_EXPORT_OK'};
  6         40  
256             };
257 6         11 map {$_->EXPORT_OK} @isa; # mqke sure EXPORT_OK setup in ancestors
  6         42  
258 6         36 my $ancestors=$helper_class->_ancestors;
259              
260 6         13 for my $func (@normal_export_ok) {
261 14         21 $export_ok_hash->{$func}=_export_sym($func,$class,$ancestors);
262             }
263 6         24 while(my($caller_func,$our_func)=each %rename_export_ok) {
264 6         9 $export_ok_hash->{$caller_func}=_export_sym($our_func,$class,$ancestors);
265             }
266 6 50       18 if (@rename_export_ok) {
267 6         12 my($sub,@our_funcs)=@rename_export_ok;
268 6         9 my %skip;
269 6 100       15 unless (@our_funcs) { # rename list empty, so use default
270             # start with all subclass-exportable functions from base classes
271             @our_funcs=uniq
272 2 50       4 map {UNIVERSAL::can($_,'SUBCLASS_EXPORT_OK')? $_->SUBCLASS_EXPORT_OK: ()} @isa;
  2         28  
273             # %skip contains ones dealt with in @NORMAL_EXPORT_OK or %RENAME_EXPORT_OK
274 2         14 @skip{@normal_export_ok}=(1) x @normal_export_ok;
275 2         7 @skip{keys %rename_export_ok}=(1) x keys %rename_export_ok;
276             # @skip{values %rename_export_ok}=(1) x values %rename_export_ok;
277             }
278 6         13 for my $our_func (@our_funcs) {
279 40         35 local $_=$our_func;
280 40         66 my $caller_func=&$sub(); # sub operates on $_
281 40 50       204 next if $skip{$caller_func};
282 40         53 $export_ok_hash->{$caller_func}=_export_sym($our_func,$class,$ancestors);
283             }
284             }
285 6         62 @$export_ok_list=keys %$export_ok_hash;
286             }
287             sub SUBCLASS_EXPORT_OK {
288 8     8   36 my $helper_class=shift;
289 8         30 my($class)=$helper_class=~/^(.*)::helper$/;
290 30     30   164 no strict 'refs';
  30         55  
  30         3517  
291             # for Hash::AutoHash::helper, @SUBCLASS_EXPORT_OK is given
292 8 100       24 if ($helper_class eq __PACKAGE__) { # NOTE: change this if you copy-and-paste into subclass
293 2         4 return @{$class.'::SUBCLASS_EXPORT_OK'};
  2         49  
294             }
295             # for subclasses, @SUBCLASS_EXPORT_OK must be computed
296 6         7 my $subclass_export_ok=\@{$class.'::SUBCLASS_EXPORT_OK'};
  6         17  
297             # NG 12-11-29: 'defined @array' deprecated in 5.16 or so
298             # return @$subclass_export_ok if defined @$subclass_export_ok;
299 6 50       15 return @$subclass_export_ok if @$subclass_export_ok;
300 6         15 return @$subclass_export_ok=$helper_class->EXPORT_OK;
301             }
302              
303             sub _export_sym {
304 690     690   631 my($func,$class,$ancestors)=@_;
305 690         596 for my $export_class (@$ancestors) { # @$ancestors includes self
306 30     30   132 no strict 'refs';
  30         37  
  30         38023  
307 738         1083 my $export_sym=$export_class.'::'.$func;
308 738 100       487 return $export_sym if defined *{$export_sym}{CODE};
  738         2920  
309             # see if ancestor renames it
310 62         200 my($class)=$export_class=~/^(.*)::helper$/;
311 62         65 my $export_sym=${$class.'::EXPORT_OK'}{$func};
  62         104  
312 62 100       139 return $export_sym if defined $export_sym;
313             }
314 4         15 undef;
315             }
316              
317             #################################################################################
318             # constructor functions. recommended over 'new'
319             #################################################################################
320             # make real autohash
321             # any extra params are key=>value pairs stored in object
322             sub autohash_hash {
323 160     160   20241 my(@hash)=@_;
324             # store params in self. can do in one step since no special semantics to worry about
325 160         835 my $self=bless {@hash},'Hash::AutoHash';
326 160         399 $self;
327             }
328             # tie autohash
329             # any extra params passed to tie
330             sub autohash_tie (*@) {
331 115     115   41210 my($hash_class,@hash_params)=@_;
332 115         292 my $self=bless {},'Hash::AutoHash';
333 115         679 tie %$self,$hash_class,@hash_params;
334 115         2178 $self;
335             }
336             # wrap pre-existing hash.
337             # any extra params are key=>value pairs passed to hash
338             sub autohash_wrap (\%@) {
339 240     240   35761 my($hash,@hash)=@_;
340             # pass params to hash in loop in case it's tied hash with special semantics
341 240         685 while (@hash>1) {
342 498         1729 my($key,$value)=splice @hash,0,2; # shift 1st two elements
343 498         1471 $hash->{$key}=$value;
344             }
345 240         1016 my $self=bless {},'Hash::AutoHash';
346             # if $hash is real, tie to 'alias', so autohash will alias hash
347 240 100       636 if (my $object=tied(%$hash)) {
348 122         1016 tie %$self,'Tie::ToObject',$object;
349             } else {
350 118         546 tie %$self,'Hash::AutoHash::alias',$hash;
351             }
352 240         2474 $self;
353             }
354             # wrap pre-existing tied object. (ie, object returned by tie),
355             # any extra params are key=>value pairs passed to object's STORE method
356             sub autohash_wrapobj {
357 128     128   27970 my($object,@hash)=@_;
358             # pass params to hash in loop in case it's tied hash with special semantics
359 128         404 while (@hash>1) {
360 259         1209 my($key,$value)=splice @hash,0,2; # shift 1st two elements
361 259         549 $object->STORE($key,$value);
362             }
363 128         702 my $self=bless {},'Hash::AutoHash';
364 128         926 tie %$self,'Tie::ToObject',$object;
365 128         2282 $self;
366             }
367             # tie and wrap hash in one step. any extra params passed to tie
368             # kinda silly, but oh well...
369             sub autohash_wraptie (\%*@) {
370 128     128   31036 my($hash,$hash_class,@hash_params)=@_;
371 128         1000 my $object=tie %$hash,$hash_class,@hash_params;
372 128         2351 my $self=bless {},'Hash::AutoHash';
373 128         1044 tie %$self,'Tie::ToObject',$object;
374 128         2235 $self;
375             }
376             # autohash_new - CAUTION: must come after other constructors because of prototypes
377             # front-end to other constructor functions
378             # cases:
379             # 1) 0 params - autohash_hash
380             # 2) >0 params - 1st param unblessed ARRAY - autohash_tie or autohash_wraptie
381             # 0th element scalar - autohash_tie
382             # 0th element HASH - autohash_wraptie
383             # 3) >0 params - 1st param unblessed HASH - autohash_wrap
384             # 4) >0 params - 1st param blessed HASH apparently not tied hash - autohash_wrap
385             # 5) >0 params - 1st param blessed and looks like tied hash object - autohash_wrapobj
386             # 6) other - autohash_hash
387             sub autohash_new {
388 348 100   348   77502 if (@_) {
389 302 100       986 if ('ARRAY' eq ref $_[0]) { # autohash_tie or autohash_wraptie
390 94         139 my $autohash;
391 94         151 my $params=shift;
392 94         174 my $class_or_hash=shift @$params;
393 94 100       257 unless (ref $class_or_hash) { # it's a class. so tie it
394 37         121 $autohash=autohash_tie($class_or_hash,@$params);
395             } else { # it's a hash. next param is class
396 57         113 my $hash=$class_or_hash;
397 57         90 my $class=shift @$params;
398 57         194 $autohash=autohash_wraptie(%$hash,$class,@$params);
399             }
400 94         363 return autohash_set($autohash,@_);
401             }
402 208 100 100     1129 if ('HASH' eq reftype($_[0]) && !_looks_wrappable($_[0])) {
403 102         135 my $hash=shift;
404 102         313 return autohash_wrap(%$hash,@_);
405             }
406 106 100       293 if (_looks_wrappable($_[0])) {
407 54         217 return autohash_wrapobj(@_);
408             }}
409             # none of the above, so must be real
410 98         271 autohash_hash(@_);
411             }
412              
413             # try to decide if object tied to hash. very approximate...
414             # say yes if blessed and has TIEHASH method
415 260 100   260   1653 sub _looks_wrappable {blessed($_[0]) && UNIVERSAL::can($_[0],'TIEHASH');}
416            
417             #################################################################################
418             # following functions provide standard hash operations on Hash::AutoHash
419             # objects. they delegate to wrapped goodie
420             #################################################################################
421 15     15   23937 sub autohash_clear {%{$_[0]}=()}
  15         109  
422             sub autohash_delete {
423 185     185   2651 my $self=shift;
424 185         758 delete @$self{@_};
425             }
426 490     490   566276 sub autohash_each {each %{$_[0]}}
  490         1581  
427 327     327   6213 sub autohash_exists {exists $_[0]->{$_[1]}}
428 98     98   4644 sub autohash_keys {keys %{$_[0]}}
  98         482  
429 95     95   1849 sub autohash_values {values %{$_[0]}}
  95         474  
430              
431             #################################################################################
432             # convenience methods easily be built on top of keys
433             #################################################################################
434 26 100   26   3040 sub autohash_count {scalar(keys %{$_[0]}) || 0}
  26         107  
435 27 100   27   735 sub autohash_empty {scalar(%{$_[0]})? undef: 1}
  27         99  
436 27 100   27   5174 sub autohash_notempty {scalar(%{$_[0]})? 1: undef}
  27         76  
437              
438             ################################################################################
439             # alias - connect autohash to hash - can be used to do the opposite of wrap
440             ################################################################################
441             sub autohash_alias (\$\%@) {
442 49     49   5408 my($autohash_ref,$hash,@hash)=@_;
443 49 100       154 if (!defined $$autohash_ref) { # no autohash, so create alias from hash to autohash
444 8         28 return $$autohash_ref=autohash_wrap(%$hash,@hash);
445             } else { # create alias from autohash to hash
446 41         57 my $autohash=$$autohash_ref;
447 41         124 autohash_set($autohash,@hash);
448 41         170 tie %$hash,'Hash::AutoHash::alias',$autohash;
449             }
450             }
451             ################################################################################
452             # functional access to tied object. works on aliased hash, also
453             ################################################################################
454             # sub autohash_options (\[$%]) {
455             # my($ref)=@_;
456             # my $autohash;
457             # if ('REF' eq ref $ref) { # it's autohash (we hope :)
458             # $autohash=$$ref; # dereference to get autohash
459             # my $object=tied %$autohash;
460             # return undef unless $object; # real hash
461             # return undef if 'Hash::AutoHash::alias' eq ref $object; # aliased to real
462             # return $object; # tied or aliased to tied
463             # } elsif ('HASH' eq ref $ref) { # HASH may be tied to 'real object or 'alias'
464             # my $object=tied %$ref;
465             # return undef unless $object;
466             # return $object unless 'Hash::AutoHash::alias' eq ref $object;
467             # # hash aliased to autohash. recurse to get underlying tied object
468             # $autohash=$object->[0]; # extract autohash from alias
469             # return &autohash_options(\$autohash); # use old-style call to turn off prototyping
470             # }
471             # undef;
472             # }
473             # sub autohash_options (\[$%]) {
474             # my($ref)=@_;
475             # my($autohash,$hash);
476             # $autohash=$$ref if 'REF' eq ref $ref; # it's autohash (we hope :)
477             # $hash=$ref if 'HASH' eq ref $ref;
478             # if ($hash) { # do hash case first. sometimes falls into autohash case
479             # my $object=tied %$ref;
480             # return undef unless $object;
481             # return $object unless 'Hash::AutoHash::alias' eq ref $object;
482             # # hash aliased to autohash. extract autohash from alias and fall into authohash case
483             # $autohash=$object->[0];
484             # }
485             # if ($autohash) {
486             # my $object=tied %$autohash;
487             # return undef unless $object; # real hash
488             # return undef if 'Hash::AutoHash::alias' eq ref $object; # aliased to real
489             # return $object; # tied or aliased to tied
490             # }
491             # undef;
492             # }
493             # sub autohash_option (\[$%]@) {
494             # my($ref,$option,@params)=@_;
495             # my $object=&autohash_options($ref); # use old-style call to turn off prototyping
496             # return undef unless $object;
497             # $object->$option(@params);
498             # }
499             sub autohash_tied (\[$%]@) {
500 376     376   24166 my $ref=shift;
501 376         321 my($autohash,$hash,$tied);
502 376 100       1015 $autohash=$$ref if 'REF' eq ref $ref; # it's autohash (we hope :)
503 376 100       659 $hash=$ref if 'HASH' eq ref $ref;
504 376 100       588 if ($hash) { # do hash case first. sometimes falls into autohash case
505 171         177 $tied=tied %$ref;
506             # hash aliased to autohash. extract autohash from alias and fall into authohash case
507 171 100       344 $autohash=$tied->[0] if 'Hash::AutoHash::alias' eq ref $tied;
508             }
509 376 100       559 if ($autohash) {
510 296         281 $tied=tied %$autohash;
511 296 100       602 $tied=undef if 'Hash::AutoHash::alias' eq ref $tied; # aliased to real
512             }
513 376 100 100     1594 return $tied unless @_ && $tied;
514             # have tied object and there are more params. this means 'run method on tied object'
515 168         266 my($method,@params)=@_;
516 168         853 $tied->$method(@params);
517             }
518              
519             #################################################################################
520             # get and set offer extended functionality for users of this interface.
521             # 'set' is the useful one. 'get' provided for symmetry
522             #################################################################################
523             # get values for one or more keys.
524             sub autohash_get {
525 137     137   2215 my $self=shift;
526 137         658 @$self{@_};
527             }
528             # set one or more key=>value pairs in hash
529             sub autohash_set {
530 183     183   5736 my $self=shift;
531 183 100 100     1006 if (@_==2 && 'ARRAY' eq ref $_[0] && 'ARRAY' eq ref $_[1]) { # separate arrays form
      66        
532 19         35 my($keys,$values)=@_;
533 19         77 for (my $i=0; $i<@$keys; $i++) {
534 23         98 my($key,$value)=($keys->[$i],$values->[$i]);
535 23         94 $self->{$key}=$value;
536             }} else { # key=>value form
537 164         531 while (@_>1) {
538 255         1372 my($key,$value)=splice @_,0,2; # shift 1st two elements
539 255         878 $self->{$key}=$value;
540             }}
541 183         1144 $self;
542             }
543              
544             #################################################################################
545             # destroy and untie rarely used but needed for full tied hash functionality.
546             # destroy nop. untie calls tied object's untie method
547             #################################################################################
548       0     sub autohash_destroy {}
549             sub autohash_untie {
550 0     0   0 my $object=tied(%{$_[0]});
  0         0  
551 0 0       0 $object->UNTIE() if $object;
552             }
553              
554             # #################################################################################
555             # # this package used to 'dup' autohash to externally supplied real hash
556             # # amazing that nothing in CPAN does this! I found several 'alias' packages but
557             # # none could connect new variable to old one without changing the type of old
558             # #################################################################################
559             # package Hash::AutoHash::dup;
560             # use strict;
561             # use Tie::Hash;
562             # our @ISA=qw(Tie::ExtraHash);
563              
564             # sub TIEHASH {
565             # my($class,$existing_hash)=@_;
566             # bless [$existing_hash],$class;
567             # }
568             #################################################################################
569             # this package used to 'alias' hash to externally supplied hash
570             # amazing that nothing in CPAN does this! I found several 'alias' packages but
571             # none could connect new variable to old one without changing the type of old
572             #################################################################################
573             package Hash::AutoHash::alias;
574             our $VERSION=$Hash::AutoHash::VERSION;
575 30     30   203 use strict;
  30         48  
  30         729  
576 30     30   16772 use Tie::Hash;
  30         24937  
  30         2501  
577             our @ISA=qw(Tie::ExtraHash);
578              
579             sub TIEHASH {
580 159     159   247 my($class,$existing_autohash)=@_;
581 159         551 bless [$existing_autohash],$class;
582             }
583             1;
584              
585             __END__