| 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__ |