File Coverage

blib/lib/Hash/AutoHash.pm
Criterion Covered Total %
statement 280 286 97.9
branch 81 88 92.0
condition 16 18 88.8
subroutine 51 53 96.2
pod 1 1 100.0
total 429 446 96.1


line stmt bran cond sub pod time code
1             package Hash::AutoHash;
2             our $VERSION='1.17';
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   1344361 use strict;
  30         77  
  30         1117  
20 30     30   171 use Carp;
  30         64  
  30         1893  
21 30     30   158 use vars qw($AUTOLOAD);
  30         64  
  30         20080  
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   135824 my $class_or_self=shift;
45 142 100       477 if (ref $class_or_self) {
46             # called as object method. access hash slot via AUTOLOAD
47 11         65 $AUTOLOAD='import';
48 11         33 return $class_or_self->AUTOLOAD(@_);
49             }
50             # called as class method. do regular 'import'
51 131         285 my $caller=caller;
52 131         330 my $helper_class=$class_or_self.'::helper';
53 131         564 $helper_class->_import($class_or_self,$caller,@_);
54             }
55             sub new {
56 79     79 1 157680 my $class_or_self=shift;
57 79 100       250 if (ref $class_or_self) {
58             # called as object method. access hash slot via AUTOLOAD
59 12         23 $AUTOLOAD='new';
60 12         35 return $class_or_self->AUTOLOAD(@_);
61             }
62             # called as class method. do regular 'new' via helper class
63 67         149 my $helper_class=$class_or_self.'::helper';
64 67         310 $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   2742828 if (ref($_[0])) {
113             # called as object method. inish up in helper class where namespace more complete
114 772         2213 my $helper_class=ref($_[0]).'::helper';
115 772         1335 my $helper_function=__PACKAGE__.'::helper::_destroy';
116 772         4658 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   2645425 my $self=shift;
139 1785         12016 $AUTOLOAD=~s/^.*:://; # strip class qualification
140             # return if $AUTOLOAD eq 'DESTROY'; # the books say you should do this
141 1785         2982 my $key=$AUTOLOAD;
142 1785 100       4455 defined $key or $key='AUTOLOAD';
143 1785         2202 $AUTOLOAD=undef; # reset for next time
144             # finish up in helper class where namespace more complete
145 1785         2734 my $helper_function=__PACKAGE__.'::helper::_autoload';
146 1785         7077 $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   182 use strict;
  30         56  
  30         890  
157 30     30   189 use Carp;
  30         69  
  30         1923  
158 30     30   173 use Scalar::Util qw(blessed readonly reftype);
  30         64  
  30         1980  
159 30     30   2858 use List::MoreUtils qw(uniq);
  30         3658  
  30         1426  
160 30     30   25994 use Tie::ToObject;
  30         9741  
  30         977  
161 30     30   202 use vars qw(%SELF2HASH %SELF2OBJECT %SELF2EACH %CLASS2ANCESTORS %EXPORT_OK);
  30         58  
  30         2945  
162              
163             sub _import {
164 131     131   353 my($helper_class,$class,$caller,@want)=@_;
165 131         375 $helper_class->EXPORT_OK; # initializes %EXPORT_OK if necessary
166 30     30   383 no strict 'refs';
  30         56  
  30         3703  
167 131         166 my %caller2export=%{$class.'::EXPORT_OK'};
  131         1619  
168             # my @export_ok=keys %caller2export;
169 131         73304 for my $want (@want) {
170 231 100       2573 confess("\"$want\" not exported by $class module") unless exists $caller2export{$want};
171 224 100       980 confess("\"$want\" not defined by $class module") unless defined $caller2export{$want};
172 222         385 my $caller_sym=$caller.'::'.$want;
173 222         314 my $export_sym=$caller2export{$want};
174 30     30   153 no strict 'refs';
  30         48  
  30         11164  
175 222         245 *{$caller_sym}=\&{$export_sym};
  222         64064  
  222         615  
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   166 my($helper_class,$class)=splice @_,0,2;
183 57         157 my $self=autohash_new(@_);
184 57         271 bless $self,$class; # re-bless in case called via subclass
185             }
186              
187             sub _destroy {
188 772     772   1234 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     9744 return if @_==1 && readonly($_[0]); # destructor. nothing to do.
193             # not destructor. access hash slot via AUTOLOAD
194 11         17 my $self=shift;
195 11         17 my $helper_function=__PACKAGE__.'::_autoload';
196 11         37 $self->$helper_function('DESTROY',@_)
197             }
198              
199             sub _autoload {
200 1796     1796   3973 my($self,$key)=splice(@_,0,2);
201 1796 100       4559 if (my $object=tied %$self) { # tied hash, so invoke FETCH/STORE methods
202 1184 100       5222 return @_==0? $object->FETCH($key): $object->STORE($key,@_);
203             } else { # regular hash
204 612 100       3160 return @_==0? ($self->{$key}): ($self->{$key}=$_[0]);
205             }
206             }
207              
208             # use vars qw(%CLASS2ANCESTORS);
209             sub _ancestors {
210 42     42   88 my($class,$visited)=@_;
211 42         84 my $ancestors=$CLASS2ANCESTORS{$class};
212 42 100       158 defined $visited or $visited={};
213 42 100 66     305 unless (defined($ancestors) || $visited->{$class}) {
214             # first call, so compute it
215 36         92 $ancestors=[$class]; # include self
216 36         102 $visited->{$class}++;
217 36         60 my @isa;
218 30     30   176 {no strict "refs"; @isa = @{ $class . '::ISA' };}
  30         50  
  30         6429  
  36         59  
  36         55  
  36         589  
219 36         105 for my $super (@isa) {
220 6         26 push(@$ancestors,_ancestors($super,$visited));
221             }
222 36         448 @$ancestors=uniq(@$ancestors);
223 36         129 $CLASS2ANCESTORS{$class}=$ancestors
224             }
225 42 100       217 wantarray? @$ancestors: $ancestors;
226             }
227              
228             sub EXPORT_OK {
229 149     149   3258 my $helper_class=shift;
230 149         782 my($class)=$helper_class=~/^(.*)::helper$/;
231             # for Hash::AutoHash::helper, @EXPORT_OK is given and function computes %EXPORT_OK
232 149 100       443 if ($helper_class eq __PACKAGE__) { # NOTE: change this if you copy-and-paste into subclass
233 30     30   210 no strict 'refs';
  30         52  
  30         3971  
234 113         154 my $export_ok_list=\@{$class.'::EXPORT_OK'};
  113         370  
235 113         242 my $export_ok_hash=\%{$class.'::EXPORT_OK'};
  113         300  
236 113 100       535 unless(%$export_ok_hash) {
237 30         121 my $ancestors=$helper_class->_ancestors;
238 30         71 for my $func (@$export_ok_list) {
239 630         1104 $export_ok_hash->{$func}=_export_sym($func,$class,$ancestors);
240             }}
241 113         328 return @$export_ok_list;
242             }
243             # for subclasses, @EXPORT_OK and %EXPORT_OK must both be computed
244 36         52 my($export_ok_list,$export_ok_hash,@isa,@normal_export_ok,@rename_export_ok,%rename_export_ok);
245             {
246 30     30   159 no strict 'refs';
  30         51  
  30         17178  
  36         43  
247 36         45 $export_ok_list=\@{$class.'::EXPORT_OK'};
  36         110  
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       200 return @$export_ok_list if @$export_ok_list;
251 6         8 $export_ok_hash=\%{$class.'::EXPORT_OK'};
  6         22  
252 6         12 @isa=@{$helper_class.'::ISA'};
  6         30  
253 6         11 @normal_export_ok=@{$class.'::NORMAL_EXPORT_OK'};
  6         23  
254 6         9 @rename_export_ok=@{$class.'::RENAME_EXPORT_OK'};
  6         23  
255 6         12 %rename_export_ok=%{$class.'::RENAME_EXPORT_OK'};
  6         31  
256             };
257 6         16 map {$_->EXPORT_OK} @isa; # mqke sure EXPORT_OK setup in ancestors
  6         49  
258 6         53 my $ancestors=$helper_class->_ancestors;
259              
260 6         15 for my $func (@normal_export_ok) {
261 14         39 $export_ok_hash->{$func}=_export_sym($func,$class,$ancestors);
262             }
263 6         38 while(my($caller_func,$our_func)=each %rename_export_ok) {
264 6         15 $export_ok_hash->{$caller_func}=_export_sym($our_func,$class,$ancestors);
265             }
266 6 50       19 if (@rename_export_ok) {
267 6         24 my($sub,@our_funcs)=@rename_export_ok;
268 6         9 my %skip;
269 6 100       31 unless (@our_funcs) { # rename list empty, so use default
270             # start with all subclass-exportable functions from base classes
271 2 50       24 @our_funcs=uniq
272 2         5 map {UNIVERSAL::can($_,'SUBCLASS_EXPORT_OK')? $_->SUBCLASS_EXPORT_OK: ()} @isa;
273             # %skip contains ones dealt with in @NORMAL_EXPORT_OK or %RENAME_EXPORT_OK
274 2         13 @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         12 for my $our_func (@our_funcs) {
279 40         55 local $_=$our_func;
280 40         92 my $caller_func=&$sub(); # sub operates on $_
281 40 50       243 next if $skip{$caller_func};
282 40         117 $export_ok_hash->{$caller_func}=_export_sym($our_func,$class,$ancestors);
283             }
284             }
285 6         81 @$export_ok_list=keys %$export_ok_hash;
286             }
287             sub SUBCLASS_EXPORT_OK {
288 8     8   66 my $helper_class=shift;
289 8         40 my($class)=$helper_class=~/^(.*)::helper$/;
290 30     30   192 no strict 'refs';
  30         68  
  30         3851  
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         383 return @{$class.'::SUBCLASS_EXPORT_OK'};
  2         53  
294             }
295             # for subclasses, @SUBCLASS_EXPORT_OK must be computed
296 6         10 my $subclass_export_ok=\@{$class.'::SUBCLASS_EXPORT_OK'};
  6         24  
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       23 return @$subclass_export_ok if @$subclass_export_ok;
300 6         18 return @$subclass_export_ok=$helper_class->EXPORT_OK;
301             }
302              
303             sub _export_sym {
304 690     690   921 my($func,$class,$ancestors)=@_;
305 690         872 for my $export_class (@$ancestors) { # @$ancestors includes self
306 30     30   170 no strict 'refs';
  30         54  
  30         44515  
307 738         1196 my $export_sym=$export_class.'::'.$func;
308 738 100       678 return $export_sym if defined *{$export_sym}{CODE};
  738         3897  
309             # see if ancestor renames it
310 62         238 my($class)=$export_class=~/^(.*)::helper$/;
311 62         78 my $export_sym=${$class.'::EXPORT_OK'}{$func};
  62         156  
312 62 100       192 return $export_sym if defined $export_sym;
313             }
314 4         17 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   32027 my(@hash)=@_;
324             # store params in self. can do in one step since no special semantics to worry about
325 160         670 my $self=bless {@hash},'Hash::AutoHash';
326 160         535 $self;
327             }
328             # tie autohash
329             # any extra params passed to tie
330             sub autohash_tie (*@) {
331 115     115   56073 my($hash_class,@hash_params)=@_;
332 115         364 my $self=bless {},'Hash::AutoHash';
333 115         764 tie %$self,$hash_class,@hash_params;
334 115         2637 $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   52334 my($hash,@hash)=@_;
340             # pass params to hash in loop in case it's tied hash with special semantics
341 240         916 while (@hash>1) {
342 498         2328 my($key,$value)=splice @hash,0,2; # shift 1st two elements
343 498         2349 $hash->{$key}=$value;
344             }
345 240         1448 my $self=bless {},'Hash::AutoHash';
346             # if $hash is real, tie to 'alias', so autohash will alias hash
347 240 100       1113 if (my $object=tied(%$hash)) {
348 122         1109 tie %$self,'Tie::ToObject',$object;
349             } else {
350 118         653 tie %$self,'Hash::AutoHash::alias',$hash;
351             }
352 240         3355 $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   39846 my($object,@hash)=@_;
358             # pass params to hash in loop in case it's tied hash with special semantics
359 128         441 while (@hash>1) {
360 259         1667 my($key,$value)=splice @hash,0,2; # shift 1st two elements
361 259         831 $object->STORE($key,$value);
362             }
363 128         1023 my $self=bless {},'Hash::AutoHash';
364 128         988 tie %$self,'Tie::ToObject',$object;
365 128         2385 $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   43101 my($hash,$hash_class,@hash_params)=@_;
371 128         746 my $object=tie %$hash,$hash_class,@hash_params;
372 128         2936 my $self=bless {},'Hash::AutoHash';
373 128         1147 tie %$self,'Tie::ToObject',$object;
374 128         2576 $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   126200 if (@_) {
389 302 100       1052 if ('ARRAY' eq ref $_[0]) { # autohash_tie or autohash_wraptie
390 94         167 my $autohash;
391 94         175 my $params=shift;
392 94         182 my $class_or_hash=shift @$params;
393 94 100       307 unless (ref $class_or_hash) { # it's a class. so tie it
394 37         131 $autohash=autohash_tie($class_or_hash,@$params);
395             } else { # it's a hash. next param is class
396 57         153 my $hash=$class_or_hash;
397 57         106 my $class=shift @$params;
398 57         228 $autohash=autohash_wraptie(%$hash,$class,@$params);
399             }
400 94         352 return autohash_set($autohash,@_);
401             }
402 208 100 100     1220 if ('HASH' eq reftype($_[0]) && !_looks_wrappable($_[0])) {
403 102         173 my $hash=shift;
404 102         5517 return autohash_wrap(%$hash,@_);
405             }
406 106 100       318 if (_looks_wrappable($_[0])) {
407 54         197 return autohash_wrapobj(@_);
408             }}
409             # none of the above, so must be real
410 98         306 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   1889 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   32390 sub autohash_clear {%{$_[0]}=()}
  15         109  
422             sub autohash_delete {
423 185     185   3270 my $self=shift;
424 185         963 delete @$self{@_};
425             }
426 490     490   844020 sub autohash_each {each %{$_[0]}}
  490         2068  
427 327     327   10512 sub autohash_exists {exists $_[0]->{$_[1]}}
428 98     98   6236 sub autohash_keys {keys %{$_[0]}}
  98         569  
429 95     95   2749 sub autohash_values {values %{$_[0]}}
  95         792  
430              
431             #################################################################################
432             # convenience methods easily be built on top of keys
433             #################################################################################
434 26 100   26   5067 sub autohash_count {scalar(keys %{$_[0]}) || 0}
  26         159  
435 27 100   27   1216 sub autohash_empty {scalar(%{$_[0]})? undef: 1}
  27         140  
436 27 100   27   12253 sub autohash_notempty {scalar(%{$_[0]})? 1: undef}
  27         276  
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   8497 my($autohash_ref,$hash,@hash)=@_;
443 49 100       154 if (!defined $$autohash_ref) { # no autohash, so create alias from hash to autohash
444 8         29 return $$autohash_ref=autohash_wrap(%$hash,@hash);
445             } else { # create alias from autohash to hash
446 41         71 my $autohash=$$autohash_ref;
447 41         116 autohash_set($autohash,@hash);
448 41         190 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   21183 my $ref=shift;
501 376         441 my($autohash,$hash,$tied);
502 376 100       953 $autohash=$$ref if 'REF' eq ref $ref; # it's autohash (we hope :)
503 376 100       832 $hash=$ref if 'HASH' eq ref $ref;
504 376 100       719 if ($hash) { # do hash case first. sometimes falls into autohash case
505 171         213 $tied=tied %$ref;
506             # hash aliased to autohash. extract autohash from alias and fall into authohash case
507 171 100       434 $autohash=$tied->[0] if 'Hash::AutoHash::alias' eq ref $tied;
508             }
509 376 100       818 if ($autohash) {
510 296         368 $tied=tied %$autohash;
511 296 100       682 $tied=undef if 'Hash::AutoHash::alias' eq ref $tied; # aliased to real
512             }
513 376 100 100     1882 return $tied unless @_ && $tied;
514             # have tied object and there are more params. this means 'run method on tied object'
515 168         307 my($method,@params)=@_;
516 168         826 $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   3401 my $self=shift;
526 137         607 @$self{@_};
527             }
528             # set one or more key=>value pairs in hash
529             sub autohash_set {
530 183     183   8818 my $self=shift;
531 183 100 100     1092 if (@_==2 && 'ARRAY' eq ref $_[0] && 'ARRAY' eq ref $_[1]) { # separate arrays form
      66        
532 19         33 my($keys,$values)=@_;
533 19         62 for (my $i=0; $i<@$keys; $i++) {
534 23         101 my($key,$value)=($keys->[$i],$values->[$i]);
535 23         106 $self->{$key}=$value;
536             }} else { # key=>value form
537 164         552 while (@_>1) {
538 255         1787 my($key,$value)=splice @_,0,2; # shift 1st two elements
539 255         1227 $self->{$key}=$value;
540             }}
541 183         1328 $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     0   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         75  
  30         901  
576 30     30   29626 use Tie::Hash;
  30         28462  
  30         2801  
577             our @ISA=qw(Tie::ExtraHash);
578              
579             sub TIEHASH {
580 159     159   300 my($class,$existing_autohash)=@_;
581 159         741 bless [$existing_autohash],$class;
582             }
583             1;
584              
585             __END__