File Coverage

blib/lib/Data/SimplePath.pm
Criterion Covered Total %
statement 147 147 100.0
branch 112 112 100.0
condition 32 33 96.9
subroutine 27 27 100.0
pod 13 13 100.0
total 331 332 99.7


line stmt bran cond sub pod time code
1             package Data::SimplePath;
2              
3 16     16   75815 use warnings;
  16         33  
  16         564  
4 16     16   99 use warnings::register;
  16         26  
  16         2303  
5 16     16   93 use strict;
  16         34  
  16         40107  
6              
7             =head1 NAME
8              
9             Data::SimplePath - Path-like access to complex data structures
10              
11             =head1 VERSION
12              
13             Version 0.005
14              
15             =cut
16              
17             our $VERSION = '0.005';
18              
19             {
20             # global options, will be used as defaults for newly created objects, can be changed on
21             # import (see import):
22              
23             my %config = (
24             'AUTO_ARRAY' => 1,
25             'REPLACE_LEAF' => 1,
26             'SEPARATOR' => '/',
27             );
28              
29             # _global ($key, $value) - retrieves or changes global configuration options,
30             # $key the option to get (see %config above for valid keys)
31             # $value if defined, the option will be set to this value and a true value
32             # will be returned, if undefined, current value of the option will be
33             # returned
34             # if $key is invalid, an undefined value will be returned
35              
36             sub _global {
37 968     968   1362 my ($key, $value) = @_;
38 968 100       2162 return unless exists $config {$key};
39 964 100       2160 if (defined $value) {
40 6         13 $config {$key} = $value;
41 6         40 return 1;
42             }
43 958         3141 return $config {$key};
44             }
45              
46             my $valid_number = qr/^\d+$/; # only positive integers (no sign) are valid as array index
47              
48             # _number ($var) - returns the - always true - array index if $var is a valid number (ie.
49             # the number $var if it is greater than 0 or '0 but true' for the value 0 itself). if the
50             # argument is not a valid number, returns undef.
51              
52             sub _number {
53 338     338   16959 my ($num) = @_;
54 338 100       2214 return unless $num =~ /$valid_number/;
55 272 100       1189 return $num == 0 ? '0 but true' : $num;
56             }
57              
58             }
59              
60             # import (%args) - allow global options to be set when the module is used.
61             # eg.: use Data::SimplePath 'AUTO_ARRAY' => 1, 'SEPARATOR' => '/';
62             # see global config hash above for valid keys. will warn on invalid keys if enabled.
63              
64             sub import {
65 17     17   1103 my ($class, %args) = @_;
66 17         110 while (my ($key, $value) = each %args) {
67 5 100       14 _warn ("Unknown option: $key") unless _global ($key, $value);
68             }
69 17         3094 return; # birthday present for perl::critic...
70             }
71              
72             =head1 SYNOPSIS
73              
74             # use default options
75             use Data::SimplePath;
76              
77             # or change the default options for new objects:
78             use Data::SimplePath 'AUTO_ARRAY' => 0,
79             'REPLACE_LEAF' => 0,
80             'SEPARATOR' => '#';
81              
82             # create new empty object with default options:
83             my $a = Data::SimplePath -> new ();
84              
85             # create new object, set some initial content:
86             my $b = Data::SimplePath -> new (
87             { 'k1' => 'v1', 'k2' => ['a', { 'b' => 'c' }, 'd'] }
88             );
89              
90             # same as above, but override some default options:
91             my $c = Data::SimplePath -> new (
92             { 'k1' => 'v1', 'k2' => ['a', { 'b' => 'c' }, 'd'] },
93             { 'AUTO_ARRAY' => 0, 'SEPARATOR' => ':' }
94             );
95              
96             # get the value 'c', ':' is the separator:
97             my $x = $c -> get ('k2:1:b');
98              
99             # change the separator to '/':
100             $c -> separator ('/');
101              
102             # enable automatic creation of arrays for numeric keys:
103             $c -> auto_array (1);
104              
105             # create a new element:
106             $c -> set ('k2/4/some key/0', 'new value');
107              
108             # the object will now contain the following data:
109             #
110             # {
111             # 'k1' => 'v1', # k1
112             # 'k2' => [ # k2
113             # 'a', # k2/0
114             # { # k2/1
115             # 'b' => 'c' # k2/1/b
116             # },
117             # 'd', # k2/2
118             # undef, # k2/3
119             # { # k2/4
120             # 'some key' => [ # k2/4/some key
121             # 'new value' # k2/4/some/key/0
122             # ]
123             # }
124             # ]
125             # }
126              
127             =head1 DESCRIPTION
128              
129             This module enables path-like (as in file system path) access to complex data structures of hashes
130             and/or arrays. Not much more to say, see the L example above...
131              
132             Ok, a few more notes: The data structure may consist of hashes or arrays, to an arbitrary depth,
133             and scalar values. You probably should not try to put blessed arrays or hashes in it, it may lead
134             to unexpected behaviour in some situations.
135              
136             The object containing the data structure exists only to help accessing the contents, you are free
137             to modify the data in any way you want without the provided methods if you like, this will not
138             break the object's behaviour.
139              
140             The methods to access a certain element in the data structure need to know which element to act on
141             (of course), there are two ways of specifying the element:
142              
143             =over
144              
145             =item by key
146              
147             The key is a single string, with parts of the path separated by the (object specific) separator.
148             This is the recommended way to access an element. Note that the methods will normalize the provided
149             key before it is used, see the C method below.
150              
151             =item by path
152              
153             The path is an array containing the parts of the full path, it is basically the key split on the
154             separator string. Empty (or undef) elements are usually ignored when a path is processed.
155              
156             =back
157              
158             In the following documentation these two terms will be used as described above. Note that the root
159             of the data structure is specified as an empty key (ie. he empty string C<''>) or an empty array as
160             path.
161              
162             =head2 Similar Modules
163              
164             There are a few modules with similar functionality are available: L and L
165             provide access to data structures using a more flexible and powerful (some may call it complicated)
166             XPath like matching.
167              
168             L provides access to data structures using paths like C does
169             (including accessing arrayrefs with numeric keys, L and L require special
170             syntax for arrayrefs). Also, this module does support calling object methods with method names
171             specified in the path, C does not offer special treatment for objects.
172              
173             However, unlike the aforementioned modules, C not only provides read access to an
174             existing data structure, it also provides methods to create, change or delete values in the data
175             structure, using paths to specify the location, and automatically create nested structures if
176             required.
177              
178             So if you only need read access, see the documentation of the modules mentioned above, maybe one is
179             better suited for your needs than C.
180              
181             =head1 CONFIGURATION
182              
183             Each of the following configuration options can be set for every object either when creating the
184             object (see C and the example in the L above) or later on with the methods
185             C, C and C (see below). The default values for the
186             options are mentioned below, and these defaults can be modified on C time, as shown in
187             the C example above.
188              
189             =head2 AUTO_ARRAY
190              
191             If this option is set to a true value, arrays will be created for numeric keys:
192              
193             # suppose the data structure is an empty hashref:
194              
195             # with AUTO_ARRAY set to true:
196             $h -> set ('a/0/b', 'value');
197              
198             # the data structure will now contain:
199             # {
200             # 'a' => [ # array created due to numeric key 0
201             # {
202             # 'b' => 'value'
203             # }
204             # ]
205             # }
206              
207             # same with AUTO_ARRAY set to false:
208             $h -> set ('a/0/b', 'value');
209              
210             # the data structure will now contain:
211             # {
212             # 'a' => { # everything's a hash
213             # '0' => {
214             # 'b' => 'value'
215             # }
216             # }
217             # }
218              
219             This only works for newly created sub-lists (and thus this setting only changes how the C
220             method works), already existing hashes will not be changed, and elements in these hashes can be
221             created, deleted and accessed with numeric keys as usual.
222              
223             The default value of this option is C<1> (enabled).
224              
225             =head2 REPLACE_LEAF
226              
227             If this option is true (default), an already existing scalar value in the data structure will be
228             replaced by a hashref or arrayref automatically if you try to C a value beneath its path:
229              
230             # suppose the data structure contains the following data:
231             # {
232             # 'key' => 'value'
233             # }
234              
235             # with REPLACE_LEAF disabled:
236             $h -> set ('key/subkey', 'value'); # this won't work
237             # data is not changed
238              
239             # with REPLACE_LEAF enabled:
240             $h -> set ('key/subkey', 'value'); # works
241              
242             # the data structure now contains:
243             # {
244             # 'key' => {
245             # 'subkey' => 'value'
246             # }
247             # }
248              
249             Note that if this option is set to false, you can still assign a hashref (or arrayref) directly to
250             the element itself:
251              
252             # same result as above:
253             $h -> set ('key', {'subkey' => 'value'});
254              
255             The default value of this option is C<1> (enabled).
256              
257             =head2 SEPARATOR
258              
259             The string used to separate path elements in the key. This may be any string you like, just make
260             sure the string itself is not contained in any actual keys of the hashes in the data structure, you
261             will not be able to access such elements by key (access by path will still work, though).
262              
263             The default value is C<'/'>.
264              
265             =head1 CLASS METHODS
266              
267             =head2 new
268              
269             my $h = Data::SimplePath -> new ($initial, $config);
270              
271             Creates a new C object. If C<$initial> is specified, which must be either a
272             hashref or an arrayref, the contents of the object will be set to this data structure. C<$config>
273             may be used to set the configuration options for the object. It must be a hashref, valid keys are
274             C<'AUTO_ARRAY'>, C<'REPLACE_LEAF'> and C<'SEPARATOR'> (see the L section for
275             details). Note that you have to specify C<$initial> if you want to set configuration options, even
276             if you don't want to add any initial content, use C in that case:
277              
278             my $h = Data::SimplePath -> new (undef, $config);
279              
280             The initial hashref (or arrayref) will be used as is, every modification of the object will alter
281             the original data:
282              
283             my $i = { 'a' => 'b' };
284             my $h = Data::SimplePath -> new ($i);
285              
286             $h -> set ('a', 'c');
287             print $i -> {'a'}; # will print the new value 'c'
288              
289             Note that if C<$initial> is defined a warning will be printed if it is not a hashref or an
290             arraryref, see the L section below. An invalid value for C<$config> will cause no
291             warning, the default settings will be used in this case.
292              
293             =cut
294              
295             sub new {
296 313     313 1 128479 my ($class, $init, $config) = @_;
297 313 100       729 my $self = {
298             'DATA' => undef,
299             'AUTO_ARRAY' => _global ('AUTO_ARRAY'),
300             'REPLACE_LEAF' => _global ('REPLACE_LEAF'),
301             'SEPARATOR' => _global ('SEPARATOR'),
302             _hashref ($config) ? %$config : ()
303             };
304 313 100       795 $self -> {'DATA'} = $init if _valid_root ($init);
305 313 100 100     1895 _warn ("Discarding invalid data: $init") if defined $init and not $self -> {'DATA'};
306 313         1871 return bless $self, $class;
307             }
308              
309 1988 100   1988   12562 sub _arrayref { return ref shift eq 'ARRAY' ? 1 : 0; }
310 1726 100   1726   13451 sub _hashref { return ref shift eq 'HASH' ? 1 : 0; }
311              
312             sub _warn {
313 234 100   234   12434 warnings::warn (shift) if warnings::enabled ();
314 234         270472 return;
315             }
316              
317             # _is_number ($var) - basically the same as _number (), but prints a warning if $var is no number
318              
319             sub _is_number {
320 296     296   995 my ($number) = @_;
321 296 100       570 unless ($number = _number ($number)) {
322 46         161 _warn ("Trying to access array element with non-numeric key $_[0]");
323 46         346 return;
324             }
325 250         741 return $number;
326             }
327              
328             # _valid_root can be used as a class method (with one parameter $root) and as an object method
329             # (without any parameter), it will return true if $root or $self -> {'DATA'} is a hashref or an
330             # arrayref.
331              
332             sub _valid_root {
333 1033     1033   3194 my ($root) = @_;
334 1033 100       11127 $root = $root -> {'DATA'} if (ref $root eq __PACKAGE__);
335 1033 100 100     1833 return (_arrayref ($root) or _hashref ($root)) ? 1 : 0;
336             }
337              
338             =head1 OBJECT METHODS
339              
340             =head2 auto_array, replace_leaf, separator
341              
342             # get current value
343             my $aa = $h -> auto_array ();
344              
345             # set AUTO_ARRAY to 1, $aa will contain the old value:
346             my $aa = $h -> auto_array (1);
347              
348             # the same syntax works for $h -> replace_leaf () and
349             # $h -> separator ()
350              
351             Get and/or set the object's C, C and C options. If no
352             parameter is specified (or the paramter is C) these methods will return the current value of
353             the option, else the option will be set to the given (scalar) value and the old setting will be
354             returned.
355              
356             =cut
357              
358 238     238 1 100280 sub auto_array { return shift -> _config ('AUTO_ARRAY', shift); }
359 250     250 1 3502 sub replace_leaf { return shift -> _config ('REPLACE_LEAF', shift); }
360 255     255 1 3910 sub separator { return shift -> _config ('SEPARATOR', shift); }
361              
362             # _config ($key, $value) - get or set a configuration option
363             # $key the name of the option to get/set (AUTO_ARRAY, REPLACE_LEAF or SEPARATOR)
364             # $value if defined, the option is set to this new value and the old value is returned, if
365             # undefined, only the current value of the option will be returned
366             # for invalid keys (or the DATA key) undef must be returned!
367              
368             sub _config {
369 807     807   19909 my ($self, $key, $new) = @_;
370 807 100 100     4695 return if not exists $self -> {$key} or $key eq 'DATA';
371 758 100       4296 return $self -> {$key} unless defined $new;
372 27         87 (my $old, $self -> {$key}) = ($self -> {$key}, $new);
373 27         104 return $old;
374             }
375              
376             =head2 clone
377              
378             my $copy = $h -> clone ();
379              
380             Creates a new C object with the same contents and settings as the original one.
381             Both objects are independent, ie. changing the contents (or settings) of one object does not effect
382             the other one. (L's C funtion is used to create the copy, see its
383             documentation for details.)
384              
385             =over
386              
387             If you actually need more than one object to modify one data structure, either create the root
388             reference first and pass it to the constructors of the different objects, or retrieve the root
389             reference from an existing object with the C method and pass it to the constructor. This
390             may be useful for example if you need certain operations with C enabled and others
391             without the C feature.
392              
393             =back
394              
395             =cut
396              
397             sub clone {
398 2     2 1 54 my ($self) = @_;
399 2 100       1221 require Storable if $self -> {'DATA'};
400 2 100       4330 return __PACKAGE__ -> new (
401             $self -> {'DATA'} ? Storable::dclone ($self -> {'DATA'}) : undef,
402             {
403             'AUTO_ARRAY' => $self -> auto_array (),
404             'REPLACE_LEAF' => $self -> replace_leaf (),
405             'SEPARATOR' => $self -> separator (),
406             }
407             );
408             }
409              
410             =head2 data
411              
412             my $data = $h -> data (); # get a reference to the object contents
413             my %data = $h -> data (); # or - if it's a hash - put a copy in a hash
414             my @data = $h -> data (); # or put a copy in an array
415              
416             Returns the object contents. In scalar context, the reference (either a hashref or an arrayref,
417             depending on the data structure's root) will be returned - note that this is the actual data as
418             used in the object, modifications will effect the object's data. In list context L's
419             C function will be used to create a copy of the data, the copy's root will be
420             dereferenced and the resulting list will be returned. Please see L's documentation for
421             limitations.
422              
423             If there is no data, C (or an empty list) will be returned.
424              
425             =cut
426              
427             sub data {
428 247     247 1 9146 my ($self) = @_;
429 247 100       989 return unless $self -> {'DATA'};
430 127 100       277 if (wantarray) {
431 2         4479 require Storable;
432 2         12493 my $new = Storable::dclone ($self -> {'DATA'});
433 2 100       9 return _hashref ($new) ? %$new : @$new;
434             }
435 125         556 return $self -> {'DATA'};
436             }
437              
438             =head2 does_exist
439              
440             if ($h -> does_exist ($key)) { ... }
441              
442             Returns a true value if the element specified by the key exists in the data structure. If it does
443             not exist, an undefined value will be returned. Instead of a key you may also specify an arrayref
444             containing the path to the element to check. Using a key is recommended, though. The key will be
445             normalized before it is used, see the C method below.
446              
447             =over
448              
449             Actually, the value returned is a reference: if the element is itself a hashref or an arrayref,
450             that reference is returned, in all other cases, a reference to the element is returned (unless the
451             element does not exist, of course):
452              
453             # for a Data::SimplePath object with the following data:
454             my $data = {
455             'a' => {
456             'a1' => 'scalar value for a1'
457             },
458             'b' => 'scalar value for b',
459             };
460              
461             my $ref1 = $h -> does_exist ('a');
462             my $ref2 = $h -> does_exist ('b');
463              
464             In this example C<$ref2> will be set to a reference to C<'scalar value for b'>, changing this
465             value is possible:
466              
467             $$ref2 = 'another value for b';
468              
469             C<$ref1> will contain the same reference as C<< $data -> {'a'} >>, so you can change the contents
470             of this (sub-) hashref, but not C<< $data -> {'a'} >> itself.
471              
472             However, it is recommended to use the C method to change the data structure, the behaviour
473             of C may change in future versions.
474              
475             =back
476              
477             =cut
478              
479             sub does_exist {
480 329     329 1 38364 my ($self, $key) = @_;
481 329         883 my @path = $self -> _path ($key);
482 329         605 my $root = $self -> {'DATA'};
483 329         917 while (defined (my $top = shift @path)) {
484 630 100       1659 return unless $root = $self -> _find_element ($root, $top);
485             }
486 155         496 return $root;
487             }
488              
489             # _find_element ($root, $key) - find an element directly under $root
490             # $root the current hashref or arrayref
491             # $key the key (or array index) to look for
492             # if either $root -> {$key} or $root -> [$key] exists, a reference will be returned, as described
493             # in the pod for the does_exist () method above (ie. hashref and arrayref will be returned
494             # directly, else a ref to the scalar will be returned). if the key does not exist, undef will be
495             # returned. additionally, a warning will be printed (if enabled) if the $root is an arrayref and
496             # the $key is not a number. if $root is invalid, undef will be returned, too.
497              
498             sub _find_element {
499 701     701   1048 my ($self, $root, $key) = @_;
500 701 100       1232 if (_hashref ($root)) {
    100          
501 335 100       1081 return unless exists $root -> {$key};
502 297 100       812 return $root -> {$key} if _valid_root ($root -> {$key});
503 53         322 return \($root -> {$key});
504             }
505             elsif (_arrayref ($root)) {
506 263 100       6835 return unless $key = _is_number ($key);
507 231 100       308 return unless @{$root} > $key;
  231         663  
508 210 100       428 return $root -> [$key] if _valid_root ($root -> [$key]);
509 62         343 return \($root -> [$key]);
510             }
511 103         425 return;
512             } # complaining about the returns: that's a paddling...
513              
514             =head2 get
515              
516             my $value = get ($key);
517              
518             Returns the value of the element specified by the key C<$key>. If the element does not exist an
519             undefined value will be returned (which may be the actual value of the element, so better use the
520             C method to check for existence if this is required). Instead of a key you may also
521             specify an arrayref containing the path to the element to check. Using a key is recommended,
522             though. The key will be normalized before it is used, see the C method below.
523              
524             If the element specified by the key (or path) is itself a hashref or an arrayref, this reference
525             will be returned if the method is called in scalar context. In list context, it will be copied
526             (using L's C function) and the resulting (dereferenced) list will be returned.
527             (See L's documentation for limitations.)
528              
529             Note that if called with an empty key (or an empty path) C works like the C
530             method, see above for details.
531              
532             =cut
533              
534             sub get {
535 229     229 1 31023 my ($self, $key) = @_;
536 229         423 my $ref = $self -> does_exist ($key);
537 229 100       980 return unless $ref;
538 92 100       141 if (_valid_root ($ref)) {
539 45 100       223 return $ref unless wantarray;
540 6         1401 require Storable;
541 6         4258 my $new = Storable::dclone ($ref);
542 6 100       21 return _hashref ($new) ? %$new : @$new;
543             }
544 47         220 return $$ref;
545             }
546              
547             =head2 set
548              
549             my $success = $h -> set ($key, $value);
550              
551             Sets the element specified by C<$key> (may be an arrayref to the element's path, as usual) to the
552             value C<$value>. All required intermediate arrayrefs and/or hashrefs will be created:
553              
554             # starting with an empty arrayref as the data structure...
555              
556             $h -> set ('0/hash/0', 'value');
557              
558             # the data structure now contains:
559             # [
560             # { # 0
561             # 'hash' => [ # 0/hash
562             # 'value' # 0/hash/0
563             # ]
564             # }
565             # ]
566              
567             Note that in the example above the AUTO_ARRAY option is turned on. Another option that modifies the
568             behaviour of C is REPLACE_LEAF. See the L section for a description of both
569             options and some example code.
570              
571             The method will return true if the operation was successful, and false if an error occured. If
572             warnings are enabled (see the L section below), a warning will be printed in case of an
573             error.
574              
575             If you specify an empty key or path, the value must be a hashref or arrayref and the object's data
576             will be set to this new data structure.
577              
578             =cut
579              
580             sub set { ## no critic (Subroutines::RequireFinalReturn) - we always return, believe it or not...
581              
582 35     35 1 32494 my ($self, $key, $value) = @_;
583 35         108 my @path = $self -> _path ($key);
584              
585             # path is empty, the root element must be changed. but only if the new value is either a
586             # hashref or an arrayref:
587 35 100       105 unless (@path) {
588 6 100       11 return unless _valid_root ($value);
589 1         2 $self -> {'DATA'} = $value;
590 1         4 return 1;
591             }
592              
593             # if root is not yet set, we need to create it before we start:
594 29 100       96 unless ($self -> {'DATA'}) {
595 4 100 100     12 $self -> {'DATA'} = ($self -> auto_array () and _number ($path [0])) ? [] : {};
596             }
597              
598             # path is not empty, start iterating along the path, start at the root:
599 29         98 my $root = $self -> {'DATA'};
600              
601             # don't forget the defined, the key may be 0. test cases would catch it, though...
602 29         113 while (defined (my $top = shift @path)) {
603              
604             # if REPLACE_LEAF is disabled, root may be something else than a hashref or an
605             # arrayref, print a warning and return in this case:
606 84 100       167 unless (_valid_root ($root)) {
607 4         10 _warn 'Trying to add an element beneath a scalar value';
608 4         26 return;
609             }
610              
611             # path is empty, $top was the last element -> set the value:
612 80 100       230 unless (@path) {
613 23 100       44 if (_arrayref ($root)) {
614 5 100       13 return unless $top = _is_number ($top);
615 3         9 $root -> [$top] = $value;
616             }
617             else {
618 18         53 $root -> {$top} = $value;
619             }
620 21         261 return 1;
621             }
622              
623             # path is not yet empty, search a child with the key $top in current $root:
624 57         141 my $child = $self -> _find_element ($root, $top);
625              
626             # child may now be an arrayref or a hashref, in that case we can just use it as the
627             # new root element (skip the if block below). if child is undef it does not yet
628             # exist and we need to create it. in all other cases, ie. it exists but is not an
629             # array- or a hashref, we override it with an array- or hashref if the REPLACE_LEAF
630             # option is set.
631              
632 57 100 100     252 if (
      66        
633             not $child or # child doesn't exist
634             (
635             $self -> replace_leaf () and # REPLACE_LEAF is set
636             not _valid_root ($child) # and it's no hash- or arrayref
637             )
638             ) {
639              
640              
641 22 100       40 if (_arrayref ($root)) {
642              
643             # important: _find_element will also return false if the root is an
644             # array and the key is no valid number, we need to check this:
645 8 100       18 return unless $top = _number ($top);
646              
647             # note that the type of the child (ie. arrayref or hashref) depends
648             # on the AUTO_ARRAY setting and the value of the next key:
649            
650 6 100 100     27 if ($self -> auto_array () and _number ($path [0])) {
651 1         3 $child = $root -> [$top] = [];
652             }
653             else {
654 5         16 $child = $root -> [$top] = {};
655             }
656            
657             }
658             else {
659              
660 14 100 100     36 if ($self -> auto_array () and _number ($path [0])) {
661 3         10 $child = $root -> {$top} = [];
662             }
663             else {
664 11         39 $child = $root -> {$top} = {};
665             }
666              
667             }
668              
669             }
670              
671             # at this point $child can be used as the next root element, if it is no arrayref
672             # or hashref we exit at the start of the next loop.
673              
674 55         235 $root = $child;
675              
676             }
677              
678             }
679              
680             =head2 remove
681              
682             my $removed = $h -> remove ($key);
683              
684             Deletes the element specified by the key C<$key> (you may also specify an arrayref containing the
685             element's path in the data structure, usage of the key is recommended, though). The value of the
686             removed element will be returned. If the element does not exist, C will be returned. If the
687             key (or path) is empty, the root reference will be returned and the data structure will be removed
688             from the object.
689              
690             This function basically works like Perl's C function for hashes and like the
691             C function for arrays (removing one element and not adding anything to the array, of
692             course).
693              
694             =cut
695              
696             sub remove { ## no critic (Subroutines::RequireFinalReturn)
697 16     16 1 37421 my ($self, $key) = @_;
698 16         59 my @path = $self -> _path ($key);
699 16         35 my $root = $self -> {'DATA'};
700 16 100       50 unless (@path) {
701 2         5 $self -> {'DATA'} = undef;
702 2         8 return $root;
703             }
704 14         162 while (defined (my $top = shift @path)) {
705 27 100       81 unless (@path) {
706 13 100       27 if (_hashref ($root)) {
    100          
707 5         60 return delete $root -> {$top};
708             }
709             elsif (_arrayref ($root)) {
710 7 100       18 return unless $top = _is_number ($top);
711 5 100       35 return splice (@$root, $top, 1) if @$root > $top;
712             }
713 2         10 return;
714             }
715 14 100       52 return unless $root = $self -> _find_element ($root, $top);
716             }
717             }
718              
719             =head2 path
720              
721             my @path = $h -> path ($key);
722              
723             Returns an array containing the path elements for the specified key C<$key>, ie. the normalized key
724             (see C below) split at the separator. Note that the resulting array may be empty.
725              
726             =cut
727              
728             sub path {
729 303     303 1 68531 my ($self, $key) = @_;
730 303         850 $key = $self -> normalize_key ($key);
731 303         586 my $s = $self -> {'SEPARATOR'};
732 303         2025 return split /\Q$s\E/, $key;
733             }
734              
735             =head2 key
736              
737             my $key = $h -> key (@path);
738              
739             Joins the array with the current separator string and returns the resulting string. The example
740             above can be written as:
741              
742             my $key = join $h -> separator (), @path;
743              
744             Additionally, you may use this function with an arrayref, the following will return the same
745             string as the first example:
746              
747             my $key = $h -> key (\@path);
748              
749             Note that - unlike the C function - no further processing is done. For example, if the
750             array contains empty strings, the resulting string will contain multiple consecutive separators.
751             Use C to remove these if required.
752              
753             =cut
754              
755             sub key {
756 112     112 1 39104 my ($self, @path) = @_;
757 112 100       382 @path = @{$path [0]} if _arrayref ($path [0]);
  56         189  
758 112         627 return join $self -> {'SEPARATOR'}, @path;
759             }
760              
761             =head2 normalize_key
762              
763             $key = $h -> normalize_key ($key);
764              
765             Removes separator string(s) at the beginning and end of the specified key and replaces all
766             occurrences of multiple consecutive separator strings in the key with a single one. For example,
767             the normalized version of C (with the separator C) would be C.
768              
769             =cut
770              
771             sub normalize_key {
772 424     424 1 13594 my ($self, $key) = @_;
773 424         731 my $s = $self -> {'SEPARATOR'};
774 424         5381 $key =~ s{^(?:\Q$s\E)*(.*?)(?:\Q$s\E)*$}{$1};
775 424         3614 $key =~ s{(?:\Q$s\E)+}{$s}g;
776 424         1702 return $key;
777             }
778              
779             # _path ($key_or_path) - get path array
780             # $key_or_path if this is an array reference, the array will be returned, if not, it is
781             # assumed to be a scalar, split at the separator and the array is returned
782             # some minor improvement: if an arrayref is used, the array will be cleaned of all invalid
783             # elements, ie. only non-empty scalar values will be returned.
784              
785             sub _path {
786 429     429   12376 my ($self, $key) = @_;
787 429 100 100     1492 if ($key and _arrayref ($key)) {
788 178         232 my @new;
789 178         628 foreach (@$key) {
790 433 100 100     3500 push @new, $_ if defined $_ and not ref $_ and $_ ne '';
      100        
791             }
792 178         789 return @new;
793             }
794 251         646 return $self -> path ($key);
795             }
796              
797             =head1 WARNINGS
798              
799             C can print warnings if something is wrong, eg. if you try to access an array
800             element with a non-numeric key or if you call the C function with C<$initial> being not a
801             hashref or arrayref. If you enable warnings (ie. C) these warnings will be enabled,
802             too. You may use the C command to enable only the warnings of
803             this module, and if you want to enable warnings in general but disable C's ones,
804             use C.
805              
806             =head1 AUTHOR
807              
808             Stefan Goebel
809              
810             =head1 COPYRIGHT & LICENSE
811              
812             Copyright (C) 2009 - 2013 Stefan Goebel, all rights reserved.
813              
814             This program is free software; you can redistribute it and/or modify it under the same terms as
815             Perl itself.
816              
817             =cut
818              
819             1;