File Coverage

blib/lib/Data/DRef.pm
Criterion Covered Total %
statement 95 216 43.9
branch 31 122 25.4
condition 7 20 35.0
subroutine 23 42 54.7
pod 30 30 100.0
total 186 430 43.2


line stmt bran cond sub pod time code
1             ### Data::DRef - Delimited-key access to complex data structures
2              
3             ### Copyright 1996, 1997, 1998, 1999 Evolution Online Systems, Inc.
4             # You may use this software for free under the terms of the Artistic License.
5              
6             ### Change History
7             # 1999-02-06 Added to CPAN module list. Repackaged for distribution.
8             # 1999-01-31 Collapsed Data::Collection into Data::DRef.
9             # 1999-01-31 Removed Data::Collection's dependancy on Data::Sorting.
10             # 1999-01-22 Revision of documentation, and improved Exporter tagging.
11             # 1998-12-01 Added get_value_for_optional_dref; minor doc revisions.
12             # 1998-10-15 Added explicit undef return value from get_value_for_key.
13             # 1998-10-14 Added doc caveat about possible use of UNIVERSAL methods.
14             # 1998-10-07 Reworked, conventionalized documentation and Exporter behaviour.
15             # 1998-10-06 Refactored value_for_keys algorithm; clarified dref syntax.
16             # 1998-07-16 Preliminary support for DRef pragmas: ignore (!reverse). -Simon
17             # 1998-05-21 Added undef behavior in matching_keys and matching_values.
18             # 1998-05-07 Replaced map with foreach in a few places.
19             # 1998-04-17 Updated to use new Data::Sorting interface.
20             # 1998-04-10 Added hash_by_array_key.
21             # 1998-04-09 Fixed single-item problem with scalarkeysof algorithm. -Simon
22             # 1998-03-12 Patched dref manipulation functions to escape separator.
23             # 1998-02-24 Changed valuesof to return value of non-ref arguments. -Piglet
24             # 1998-01-30 Added array_by_hash_key($) and intersperse($@) -Simon
25             # 1997-12-08 Removed package Data::Types, replaced with UNIVERSAL isa.
26             # 1997-12-07 Exported uniqueindexby. -Piglet
27             # 1997-11-24 Finished orderedindexby.
28             # 1997-11-19 Renamed removekey function to shiftdref at Jeremy's suggestion.
29             # 1997-11-14 Added resolveparens behaviour to standard syntax.
30             # 1997-11-14 Added getDRef, setDRef functions as can() wrappers for get, set
31             # 1997-11-13 Added orderedindexby, but it still needs a bit of work.
32             # 1997-10-29 Add'l modifications; replaced recursion with iteration in get()
33             # 1997-10-25 Revisions; separator changed from colon to period.
34             # 1997-10-03 Refactored get and set operations
35             # 1997-09-05 Package split from the original dataops.pm into Data::*.
36             # 1997-04-18 Cleaned up documentation a smidge.
37             # 1997-04-08 Added getbysubkeys, now called matching_values
38             # 1997-01-29 Altered set to create hashes even for numerics
39             # 1997-01-28 Possible fix to recurring "keysof operates on containers" error.
40             # 1997-01-26 Catch bad argument types for sortby, indexby.
41             # 1997-01-21 Failure for keysof, valuesof now returns () rather than undef.
42             # 1997-01-21 Added scalarsof.
43             # 1997-01-11 Cloned and cleaned for IWAE; removed asdf code to dictionary.pm.
44             # 1996-11-18 Moved v2 code into production, additional cleanup. -Simon
45             # 1996-11-13 Version 2.00, major overhaul.
46             # 1996-10-29 Fixed set to handle '0' items. -Piglet
47             # 1996-09-09 Various changes, esp. fixing get to handle '0' items. -Simon
48             # 1996-07-24 Wrote copy, getString, added 'append' to set.
49             # 1996-07-18 Wrote setData, fixed headers. -Piglet
50             # 1996-07-18 Additional Exporter fudging.
51             # 1996-07-17 Globalized theData. -Simon
52             # 1996-07-13 Simplified getData into get; wrote set. -Piglet
53             # 1996-06-25 Various tweaks.
54             # 1996-06-24 First version of dataops.pm created. -Simon
55              
56             package Data::DRef;
57              
58             require 5;
59 2     2   12650 use strict;
  2         4  
  2         67  
60 2     2   12 use Carp;
  2         3  
  2         142  
61 2     2   10 use Exporter;
  2         13  
  2         81  
62              
63 2     2   2987 use String::Escape qw( printable unprintable );
  2         13172  
  2         188  
64              
65 2     2   17 use vars qw( $VERSION @ISA %EXPORT_TAGS );
  2         2  
  2         2976  
66             $VERSION = 1999.02_06;
67              
68             push @ISA, qw( Exporter );
69             %EXPORT_TAGS = (
70             key_access => [ qw(
71             get_keys get_values get_value_for_key set_value_for_key
72             get_or_create_value_for_key get_reference_for_key
73             get_value_for_keys set_value_for_keys
74             ) ],
75             dref_syntax => [ qw(
76             $Separator $DRefPrefix dref_from_keys keys_from_dref
77             join_drefs unshift_dref_key shift_dref_key resolve_pragmas
78             ) ],
79             dref_access => [ qw(
80             get_key_drefs get_value_for_dref set_value_for_dref
81             ) ],
82             root_dref => [ qw(
83             $Root get_value_for_root_dref set_value_for_root_dref
84             ) ],
85             'select' => [ qw(
86             matching_keys matching_values
87             ) ],
88             'index' => [ qw(
89             index_by_drefs unique_index_by_drefs ordered_index_by_drefs
90             ) ],
91             'leaf' => [ qw(
92             leaf_drefs leaf_values leaf_drefs_and_values
93             ) ],
94             compat => [ qw(
95             getData setData getDRef setDRef joindref shiftdref $Root get set
96             $Separator splitdref keysof valuesof scalarkeysof scalarkeysandvalues
97             matching_values matching_keys indexby uniqueindexby orderedindexby
98             ) ],
99             );
100             Exporter::export_ok_tags( keys %EXPORT_TAGS );
101              
102             ### Value-For-Key Interface
103              
104             # @keys = get_keys($target)
105             sub get_keys {
106 3     3 1 4 my $target = shift;
107            
108 3 50       17 if ( UNIVERSAL::can($target, 'm_get_keys') ) {
    50          
    0          
109 0         0 return $target->m_get_keys(@_);
110             } elsif ( UNIVERSAL::isa($target, 'HASH') ) {
111 3         10 return keys %$target;
112             } elsif ( UNIVERSAL::isa($target, 'ARRAY') ) {
113 0         0 return ( 0 .. $#$target );
114             } else {
115 0         0 return ();
116             }
117             }
118              
119             # @values = get_values($target)
120             # Returns a list of scalar values in a referenced hash or list
121             sub get_values {
122 0     0 1 0 my $target = shift;
123            
124 0 0       0 if ( UNIVERSAL::can($target, 'm_get_values') ) {
    0          
    0          
    0          
125 0         0 return $target->m_get_values(@_);
126             } elsif ( UNIVERSAL::isa($target, 'HASH') ) {
127 0         0 return values %$target;
128             } elsif ( UNIVERSAL::isa($target, 'ARRAY') ) {
129 0         0 return @$target;
130             } elsif ( ! ref $target ) {
131 0         0 return $target;
132             } else {
133 0         0 return ();
134             }
135             }
136              
137             # $value = get_value_for_key($target, $key);
138             sub get_value_for_key ($$) {
139 29     29 1 29 my $target = shift;
140 29 50       57 croak "get called without target \n" unless (defined $target);
141            
142 29         28 my $key = shift;
143            
144 29 50       144 if ( UNIVERSAL::can($target, 'm_get_value_for_key') ) {
    100          
    50          
145 0         0 return $target->m_get_value_for_key($key);
146             } elsif ( UNIVERSAL::isa($target, 'HASH') ) {
147 26 50       98 return $target->{$key} if (exists $target->{$key});
148             } elsif ( UNIVERSAL::isa($target, 'ARRAY') ) {
149 3 50 66     13 carp "Use of non-numeric key '$key'" unless ( $key eq '0' or $key > 0 );
150 3 50 33     16 return $target->[$key] if ($key >= 0 and $key < scalar @$target);
151             } else {
152 0         0 carp "'$target' can't get_value_for_key '$key'\n";
153             }
154 0         0 return undef;
155             }
156              
157             # set_value_for_key($target, $key, $value);
158             sub set_value_for_key ($$$) {
159 5     5 1 7 my $target = shift;
160 5 50       10 croak "set_value_for_key called without target \n" unless (defined $target);
161            
162 5 50       18 if ( UNIVERSAL::can($target, 'm_set_value_for_key') ) {
    50          
    0          
163 0         0 return $target->m_set_value_for_key(@_);
164             } elsif ( UNIVERSAL::isa($target, 'HASH') ) {
165 5         30 $target->{ $_[0] } = $_[1];
166             } elsif ( UNIVERSAL::isa($target, 'ARRAY') ) {
167 0         0 $target->[ $_[0] ] = $_[1];
168             } else {
169             # We do not natively support set() on anything else.
170 0         0 carp "'$target' can't set_value_for_key '$_[0]'\n";
171             }
172             }
173              
174             # $value = get_or_create_value_for_key($target, $key);
175             sub get_or_create_value_for_key {
176 1     1 1 1 my $target = shift;
177 1         2 my $key = shift;
178            
179 1 50       4 return $target->m_get_or_create_value_for_key($key)
180             if ( UNIVERSAL::can($target, 'm_get_or_create_value_for_key') );
181            
182 1         3 my $value = get_value_for_key($target, $key);
183            
184 1 50       4 unless (defined $value) {
185 0         0 $value = {};
186 0         0 set_value_for_key($target, $key, $value);
187             }
188            
189 1         66 return $value;
190             }
191              
192             # $value_reference = get_reference_for_key($target, $key);
193             sub get_reference_for_key ($$) {
194 0     0 1 0 my $target = shift;
195 0 0       0 croak "get_reference_for_key called w/o target\n" unless (defined $target);
196            
197 0         0 my $key = shift;
198            
199 0 0       0 if ( UNIVERSAL::can($target, 'm_get_reference_for_key') ) {
    0          
    0          
200 0         0 return $target->m_get_reference_for_key($key);
201             } elsif ( UNIVERSAL::isa($target, 'HASH') ) {
202 0         0 return \${$target}{$key};
  0         0  
203             } elsif ( UNIVERSAL::isa($target, 'ARRAY') ) {
204 0         0 return \${$target}[$key];
  0         0  
205             } else {
206 0         0 carp "'$target' can't get_reference_for_key '$_[0]'\n";
207             }
208             }
209              
210             ### Multiple-Key Chaining
211             #
212             # These functions allow access through a series of keys. Generally, the list
213             # of keys is interpreted each starting from the result of the previous one.
214              
215             # $value = get_value_for_keys($target, @keys);
216             sub get_value_for_keys ($@) {
217 17     17 1 21 my $target = shift;
218 17 50       32 croak "get_value_for_keys called without target \n" unless (defined $target);
219 17 50       35 croak "get_value_for_keys called without keys \n" unless (scalar @_);
220            
221 17         44 while ( scalar @_ ) {
222             # If we've got keys remaining, use the appropriate get method...
223 28 50       69 return $target->m_get_value_for_keys(@_)
224             if UNIVERSAL::can($target, 'm_get_value_for_keys');
225            
226 28         55 my $key = shift @_;
227 28         49 my $result = get_value_for_key($target, $key);
228            
229             # If there aren't any more keys, we're done!
230 28 100       114 return $result unless (scalar @_);
231            
232             # We can't keep going without a ref value, despite the remaining keys
233 11 50       30 return undef unless (ref $result);
234            
235             # ... or select the target and iterate through another key
236 11         31 $target = $result;
237             }
238             }
239              
240             # set_value_for_keys($target, $value, @keys);
241             sub set_value_for_keys {
242 5     5 1 7 my $target = shift;
243 5         6 my $value = shift;
244            
245 5 50       12 croak "set_value_for_keys called without target \n" unless (defined $target);
246 5 50       12 croak "set_value_for_keys called without keys \n" unless (scalar @_);
247            
248 5         11 while ( scalar @_ ) {
249 6 50       18 return $target->m_set_value_for_keys($value, @_)
250             if UNIVERSAL::can($target, 'm_set_value_for_keys');
251            
252 6         7 my $key = shift @_;
253            
254             # Last key -- we're at the end of the line
255 6 100       21 return set_value_for_key($target, $key, $value) unless (scalar @_);
256            
257             # Get the value for this key, or create an empty hash ref to build into.
258 1         4 my $result = get_or_create_value_for_key($target, $key);
259            
260             # We've got keys remaining, but we can't keep going
261 1 50       21 return undef unless (ref $result);
262            
263 1         3 $target = $result;
264             }
265             }
266              
267             # $value = get_or_create_value_for_keys($target, @keys);
268             sub get_or_create_value_for_keys {
269 0     0 1 0 my $target = shift;
270 0         0 my $value = shift;
271            
272 0 0       0 croak "set_value_for_keys called without target \n" unless (defined $target);
273 0 0       0 croak "set_value_for_keys called without keys \n" unless (scalar @_);
274            
275 0         0 while ( scalar @_ ) {
276 0 0       0 return $target->m_get_or_create_value_for_keys($value, @_)
277             if UNIVERSAL::can($target, 'm_get_or_create_value_for_keys');
278            
279 0         0 my $key = shift @_;
280 0         0 my $result = get_or_create_value_for_key($target, $key);
281            
282             # If there aren't any more keys, we're done!
283 0 0       0 return $result unless (scalar @_);
284            
285             # We can't keep going without a ref value, despite the remaining keys
286 0 0       0 return undef unless (ref $result);
287            
288             # ... or select the target and iterate through another key
289 0         0 $target = $result;
290             }
291             }
292              
293             # $val_ref = get_reference_for_keys($target, @keys);
294             sub get_reference_for_keys {
295 0     0 1 0 my $target = shift;
296            
297 0 0       0 croak "get_reference_for_keys called w/o target\n" unless (defined $target);
298 0 0       0 croak "get_reference_for_keys called w/o keys \n" unless (scalar @_);
299            
300 0         0 while ( scalar @_ ) {
301 0 0       0 return $target->m_get_reference_for_keys(@_)
302             if UNIVERSAL::can($target, 'm_get_reference_for_keys');
303            
304 0         0 my $key = shift @_;
305            
306             # Last key -- we're at the end of the line
307 0 0       0 return get_reference_for_key($target, $key) unless (scalar @_);
308            
309             # Get the value for this key, or create an empty hash ref to build into.
310 0         0 my $result = get_or_create_value_for_key($target, $key);
311            
312             # We've got keys remaining, but we can't keep going
313 0 0       0 return undef unless (ref $result);
314            
315 0         0 $target = $result;
316             }
317             }
318              
319             ### DRef Syntax
320             #
321             # DRef strings are dot-separated
322              
323             # $Separator - Multiple-key delimiter character
324 2     2   11 use vars qw( $Separator $DRefPrefix );
  2         4  
  2         1428  
325             $Separator = '.';
326             $DRefPrefix = '#';
327              
328             # @drefs = get_key_drefs($target);
329             sub get_key_drefs {
330 3     3 1 9 map { printable($_) } get_keys( @_ );
  4         20  
331             }
332              
333             # $dref = dref_from_keys( @keys );
334             # Return a dref composed of a list of $Separator-protected keys
335             sub dref_from_keys (@) {
336 0     0 1 0 join $Separator, map { printable($_) } @_;
  0         0  
337             }
338              
339             # @keys = keys_from_dref( $dref );
340             # Return a series of key strings extracted from a dref
341             sub keys_from_dref ($) {
342 22     22 1 28 my $dref = shift;
343 22         21 my @keys;
344 22   66     119 while ( defined $dref and length $dref ) {
345 34         397 $dref =~ s/\A((?:[^\\\Q$Separator\E]+|\\.)*)(?:\Q$Separator\E|\Z)//m;
346 34         107 push(@keys, unprintable($1));
347             }
348 22         266 return @keys;
349             }
350              
351             # $dref = join_drefs( @drefs );
352             sub join_drefs (@) {
353 2     2 1 8 join($Separator, @_);
354             }
355              
356             # unshift_dref_key( $dref, $key );
357             # Prepends key to dref -- modifies value of first argument
358             sub unshift_dref_key {
359 0     0 1 0 $_[0] = join($Separator, unprintable($_[1]), $_[0]);
360             }
361              
362             # $key = shift_dref_key( $dref );
363             # Removes first key from dref -- modifies value of its argument
364             sub shift_dref_key {
365 0     0 1 0 $_[0] =~ s/\A((?:[^\\\Q$Separator\E]+|\\.)*)(?:\Q$Separator\E|\Z)//m;
366 0         0 return unprintable($1);
367             }
368              
369             # $dref = resolve_pragmas( $dref_with_embedded_parens );
370             # ($dref, %options) = resolve_pragmas( $dref_with_embedded_parens );
371             sub resolve_pragmas ($) {
372 22     22 1 27 my $path = shift;
373 22         33 my $options = {};
374            
375 22         69 do {} while (
376             $path =~ s/(\A|[^\\]|[^\\](?:\\{2})*)\(([\#\!])([^\(\)]+)\)
377 0         0 /$1._expand_pragma($2, $3, $options)/ex
378             );
379            
380 22 50       101 return wantarray ? ($path, %$options) : $path;
381             }
382              
383             sub _expand_pragma {
384 0     0   0 my ($type, $value, $options) = @_;
385 0 0       0 if ( $type eq $DRefPrefix ) {
    0          
386 0         0 return get_value_for_root_dref($value);
387             } elsif ( $type eq '!' ) {
388 0         0 $options->{ $value } = 1;
389             } else {
390 0         0 carp "use of unsupported DRef pragma '$type$value'";
391             }
392 0         0 return '';
393             }
394              
395             ### DRef Access
396              
397             # $value = get_value_for_dref($target, $dref);
398             sub get_value_for_dref {
399 17     17 1 40 get_value_for_keys $_[0], keys_from_dref( (resolve_pragmas($_[1]))[0] );
400             }
401              
402             # set_value_for_dref($target, $dref, $value);
403             sub set_value_for_dref {
404 5     5 1 14 set_value_for_keys $_[0], $_[2], keys_from_dref((resolve_pragmas($_[1]))[0]);
405             }
406              
407             ### Shared Data Graph Entry
408              
409             # $Root - Data graph entry point
410 2     2   12 use vars qw( $Root );
  2         4  
  2         2737  
411             $Root = {};
412              
413             # $value = get_value_for_root_dref($dref);
414             sub get_value_for_root_dref ($) {
415 11     11 1 382 get_value_for_dref($Root, @_)
416             }
417              
418             # $value = set_value_for_root_dref($dref, $value);
419             sub set_value_for_root_dref ($$) {
420 5     5 1 193 set_value_for_dref($Root, @_)
421             }
422              
423             # $value = get_value_for_optional_dref($literal_or_dref_with_leading_hashmark);
424             sub get_value_for_optional_dref ($) {
425 0 0   0 1 0 $_[0] =~ /^\Q$DRefPrefix\E(.*)/o ? get_value_for_root_dref($1) : $_[0]
426             }
427              
428             ### Select by DRefs
429              
430             # $key or @keys = matching_keys($target, %dref_value_criteria_pairs);
431             sub matching_keys {
432 0     0 1 0 my($target, %kvp_criteria) = @_;
433 0 0 0     0 return unless ($target and scalar %kvp_criteria);
434 0         0 my ($key, $dref, @keys);
435 0         0 ITEM: foreach $key (get_keys $target) {
436 0         0 my $item = get_value_for_key($target,$key);
437 0         0 foreach $dref (keys %kvp_criteria) {
438 0 0 0     0 next ITEM unless $kvp_criteria{$dref} eq (
    0          
439             defined $dref && length $dref ? get_value_for_dref($item,$dref) : $item
440             );
441             }
442 0 0       0 return $key unless (wantarray);
443 0         0 push @keys, $key;
444             }
445 0         0 return @keys;
446             }
447              
448             # $item or @items = matching_values($target, %dref_value_criteria_pairs);
449             sub matching_values {
450 0     0 1 0 my($target, %kvp_criteria) = @_;
451 0         0 my($item, $dref, @items);
452 0         0 ITEM: foreach $item ( get_values($target) ) {
453 0         0 foreach $dref (keys %kvp_criteria) {
454 0 0 0     0 next ITEM unless $kvp_criteria{$dref} eq (
    0          
455             defined $dref && length $dref ? get_value_for_dref($item,$dref) : $item
456             );
457             }
458 0 0       0 return $item unless (wantarray);
459 0         0 push @items, $item;
460             }
461 0         0 return @items;
462             }
463              
464             ### Index by DRefs
465              
466             # $index = index_by_drefs($target, @drefs)
467             sub index_by_drefs {
468 0     0 1 0 my($target, @drefs) = @_;
469 0         0 my $index = {};
470            
471 0         0 my $item;
472 0         0 foreach $item ( get_values($target) ) {
473 0         0 my @keys = map { get_value_for_dref($item, $_) } @drefs;
  0         0  
474 0         0 my $grouping = get_reference_for_keys($index, @keys);
475 0         0 push @$$grouping, $item;
476             }
477            
478 0         0 return $index;
479             }
480              
481             # $index = unique_index_by_drefs($target, @drefs)
482             sub unique_index_by_drefs {
483 0     0 1 0 my($target, @drefs) = @_;
484 0         0 my $index = {};
485            
486 0         0 my $item;
487 0         0 foreach $item (get_values ($target)) {
488 0         0 my @keys = map { get_value_for_dref($item, $_) } @drefs;
  0         0  
489 0         0 set_value_for_keys($index, $item, @keys);
490             }
491            
492 0         0 return $index;
493             }
494              
495             # $entry_ary = ordered_index_by_drefs( $target, $index_dref );
496             sub ordered_index_by_drefs {
497 0     0 1 0 my($target, $grouper) = @_;
498 0         0 my $index = {};
499 0         0 my $order = [];
500            
501 0         0 my $item;
502 0         0 foreach $item ( get_values($target) ) {
503 0         0 my $value = get_value_for_dref($item, $grouper);
504 0 0       0 $value = '' unless (defined $value);
505 0 0       0 push @$order, (
506             $index->{$value} = { 'value' => $value, 'items' => [] }
507             ) unless ( exists($index->{ $value }) );
508 0         0 push @{ $index->{ $value }{'items'} }, $item;
  0         0  
509             }
510 0         0 return $order;
511             }
512              
513             ### DRefs to Leaf nodes
514              
515             # @drefs = leaf_drefs($target);
516             # Returns a list of drefs for non-ref leaves in a referenced structure.
517             # Keep track of items we've visited previously to protect against loops.
518             sub leaf_drefs ($) {
519 1     1 1 2 my $target = shift;
520 1         5 my @drefs = get_key_drefs( $target );
521 1         9 my %visited;
522             my $i;
523 1         6 for ( $i = 0; $i <= $#drefs; $i++ ) {
524 4         13 my $dref = $drefs[$i];
525 4         28 my $value = get_value_for_dref($target, $dref);
526 4 100 66     28 next if ( ! ref $value or $visited{$value}++ );
527 2         4 my @subkeys = get_key_drefs( $value );
528 2 50       18 if ( scalar @subkeys ) {
529 2         5 splice @drefs, $i, 1, map { join_drefs($dref, $_) } @subkeys;
  2         4  
530 2         10 $i--;
531             }
532             }
533 1         5 return @drefs;
534             }
535              
536             # @values = leaf_values( $target )
537             sub leaf_values ($) {
538 0     0 1 0 my $target = shift;
539 0         0 map { get_value_for_dref($target, $_) } leaf_drefs( $target );
  0         0  
540             }
541              
542             # %dref_value_pairs = leaf_drefs_and_values( $target )
543             sub leaf_drefs_and_values ($) {
544 1     1 1 15 my $target = shift;
545 1         4 map { $_, get_value_for_dref($target, $_) } leaf_drefs( $target );
  2         7  
546             }
547              
548             ### Compatiblity
549              
550             *get = *get_value_for_dref;
551             *set = *set_value_for_dref;
552             *getDRef = *get_value_for_dref;
553             *setDRef = *set_value_for_dref;
554             *getData = *get_value_for_root_dref;
555             *setData = *set_value_for_root_dref;
556             *splitdref = *keys_from_dref;
557             *joindref = *dref_from_keys;
558             *shiftdref = *shift_dref_key;
559             *keysof = *get_keys;
560             *valuesof = *get_values;
561             *indexby = *index_by_drefs;
562             *uniqueindexby = *unique_index_by_drefs;
563             *orderedindexby = *ordered_index_by_drefs;
564             *scalarkeysof = *leaf_drefs;
565             *scalarkeysandvalues = *leaf_drefs_and_values;
566              
567             ### Data::DRef::MethodBased
568              
569             package Data::DRef::MethodBased;
570              
571             ### Minimal DRef Interface for Object Methods
572              
573             # @keys = $target->m_get_keys()
574             sub m_get_keys {
575 0     0     return ();
576             }
577              
578             # @values = $target->m_get_values()
579             sub m_get_values {
580 0     0     my $target = shift;
581 0           map { $target->m_get_value_for_key($_) } $target->m_get_keys;
  0            
582             }
583              
584             # $value = $target->m_get_value_for_key($key);
585             sub m_get_value_for_key {
586 0     0     my ($target, $key) = @_;
587 0 0         return $target->$key() if ( $target->can($key) );
588 0           die "$target is unable to get value for key '$key'\n";
589             }
590              
591             # $target->m_set_value_for_key($key, $value);
592             sub m_set_value_for_key {
593 0     0     my ($target, $key, $value) = @_;
594 0 0         return $target->$key($value) if ( $target->can($key) );
595 0           die "$target is unable to set value for key '$key'\n";
596             }
597              
598             # No default implementation provided for these other supported methods...
599             # $value_reference = $target->m_get_reference_for_key($key);
600             # $value = $target->m_get_or_create_value_for_key($key);
601             # $value = $target->m_get_value_for_keys(@keys);
602             # $target->m_set_value_for_keys($value, @keys);
603             # $val_ref = $target->m_get_reference_for_keys(@keys);
604             # $target->m_set_value_for_keys($value, @keys);
605              
606             1;
607              
608             __END__