File Coverage

blib/lib/Data/Context/Util.pm
Criterion Covered Total %
statement 77 83 92.7
branch 36 40 90.0
condition 8 15 53.3
subroutine 14 15 93.3
pod 3 3 100.0
total 138 156 88.4


line stmt bran cond sub pod time code
1             package Data::Context::Util;
2              
3             # Created on: 2012-04-12 15:59:08
4             # Create by: Ivan Wills
5             # $Id$
6             # $Revision$, $HeadURL$, $Date$
7             # $Revision$, $Source$, $Date$
8              
9 8     8   26551 use strict;
  8         12  
  8         403  
10 8     8   69 use warnings;
  8         11  
  8         307  
11 8     8   433 use version;
  8         1490  
  8         67  
12 8     8   660 use Carp;
  8         12  
  8         556  
13 8     8   48 use Scalar::Util qw/blessed/;
  8         11  
  8         426  
14 8     8   43 use List::Util;
  8         12  
  8         526  
15 8     8   42 use Data::Dumper qw/Dumper/;
  8         11  
  8         432  
16 8     8   537 use English qw/ -no_match_vars /;
  8         2879  
  8         139  
17 8     8   8883 use Class::Inspector;
  8         29916  
  8         350  
18 8     8   74 use base qw/Exporter/;
  8         15  
  8         7297  
19              
20             our $VERSION = version->new('0.1.8');
21             our @EXPORT_OK = qw/lol_path lol_iterate do_require/;
22              
23             sub lol_path {
24 75     75 1 2619 my ($lol, $path) = @_;
25 75         301 my @path = split /[.]/xms, $path;
26 75         146 my $point = $lol;
27 75         72 my $replacer;
28              
29             POINT:
30 75   33     407 while ( $point && @path ) {
31              
32             # ignore empty path parts
33 174 50 33     651 if ( ! defined $path[0] || $path[0] eq '' ) {
34 0         0 shift @path;
35 0         0 next POINT;
36             }
37              
38 174         220 my $item = shift @path;
39 174         190 my $current = $point;
40              
41             # process the point
42 174 50 33     519 if ( !ref $point ) {
    100          
    100          
    50          
43 0         0 return;
44             }
45             elsif ( ref $point eq 'HASH' ) {
46 147     45   459 $replacer = sub { $current->{$item} = shift };
  45         4871450  
47 147         380 $point = $point->{$item};
48             }
49             elsif ( ref $point eq 'ARRAY' ) {
50 26     0   85 $replacer = sub { $current->[$item] = shift };
  0         0  
51 26         105 $point = $point->[$item];
52             }
53             elsif ( blessed $point && $point->can( $item ) ) {
54 1         2 $replacer = undef;
55 1         24 $point = $point->$item();
56             }
57             else {
58 0         0 confess "Don't know how to deal with $point";
59             }
60              
61 174 100       899 return wantarray ? ($point, $replacer) : $point if !@path;
    100          
62             }
63              
64             # nothing found
65 0         0 return;
66             }
67              
68             sub lol_iterate {
69 93     93 1 4271 my ($lol, $code, $path) = @_;
70 93         112 my $point = $lol;
71              
72 93 100 100     296 if ( !$path && defined $point ) {
73 26         107 $code->( $point, $path );
74             }
75              
76 93 100       197 $path = $path ? "$path." : '';
77              
78 93 100       361 if ( $point ) {
79 91 100 66     290 if ( !ref $point ) {
    100          
    100          
    100          
80 1         4 $code->( $point, $path );
81             }
82             elsif ( ref $point eq 'HASH' ) {
83 75         209 for my $key ( keys %$point ) {
84 190         598 $code->( $point->{$key}, "$path$key" );
85 190 100       671 lol_iterate( $point->{$key}, $code, "$path$key" ) if ref $point->{$key};
86             }
87             }
88             elsif ( ref $point eq 'ARRAY' ) {
89 13         49 for my $i ( 0 .. @$point - 1 ) {
90 26         81 $code->( $point->[$i], "$path$i" );
91 26 100       101 lol_iterate( $point->[$i], $code, "$path$i" ) if ref $point->[$i];
92             }
93             }
94 2         3 elsif ( blessed $point && eval { %{$point} } ) {
  2         18  
95 1         4 for my $key ( keys %$point ) {
96 1         8 $code->( $point->{$key}, "$path$key" );
97 1 50       15 lol_iterate( $point->{$key}, $code, "$path$key" ) if ref $point->{$key};
98             }
99             }
100             }
101              
102 93         185 return;
103             }
104              
105             our %required;
106             sub do_require {
107 88     88 1 700 my ($module) = @_;
108              
109 88 100       340 return if $required{$module}++;
110              
111             # check if namespace appears to be loaded
112 27 100       198 return if Class::Inspector->loaded($module);
113              
114             # Try loading namespace
115 13         967 $module =~ s{::}{/}gxms;
116 13         26 $module .= '.pm';
117 13         23 eval {
118 13         4910 require $module
119             };
120 13 100       92 if (my $e = $@) {
121 1         304 confess $e;
122             }
123              
124 12         71 return;
125             }
126              
127             1;
128              
129             __END__
130              
131             =head1 NAME
132              
133             Data::Context::Util - Helper functions for Data::Context
134              
135             =head1 VERSION
136              
137             This documentation refers to Data::Context::Util version 0.1.8.
138              
139             =head1 SYNOPSIS
140              
141             use Data::Context::Util qw/lol_path lol_iterate/;
142              
143             my $lol = {
144             data => [
145             {
146             structure => 'item',
147             },
148             ],
149             };
150              
151             my $value = lol_path($lol, 'data.0.structure');
152             # value == item
153              
154             lol_iterate(
155             $lol,
156             sub {
157             my ($value, $path) = @_;
158             print "$path = $value" if !ref $value;
159             }
160             );
161             # would print data.0.structure = item
162              
163             =head1 DESCRIPTION
164              
165             =head1 SUBROUTINES/METHODS
166              
167             =head2 C<lol_path ( $lol, $path )>
168              
169             =over 4
170              
171             =item C<$lol>
172              
173             List of lists ie an arbitrary data structure
174              
175             =item C<$path>
176              
177             A string encoded as a dotted path through the data structure
178              
179             =back
180              
181             C<lol_path> tries to extract data from an arbitrary Perl data structure based
182             on the specified path. It will try yo do what makes sense ie if the current
183             context of the lol is a hash the path part will be used as a key, similarly
184             if the context is an array the path part will be used as an index. If the
185             context is a blessed reference then it try to call the path part as a method.
186              
187             All errors result in returning no value.
188              
189             =head2 C<lol_iterate ($lol, $code)>
190              
191             =over 4
192              
193             =item C<$lol>
194              
195             Arbitrary perl data structure
196              
197             =item C<$code>
198              
199             A subroutine that is called against all values found in the data structure.
200             It is called as:
201              
202             $code->($value, $path);
203              
204             =back
205              
206             Recursively iterates through a data structure calling C<$code> for each value
207             encountered.
208              
209             =head2 C<do_require ($module)>
210              
211             Requires the specified module (if not previously required
212              
213             =head1 DIAGNOSTICS
214              
215             =head1 CONFIGURATION AND ENVIRONMENT
216              
217             =head1 DEPENDENCIES
218              
219             =head1 INCOMPATIBILITIES
220              
221             =head1 BUGS AND LIMITATIONS
222              
223             There are no known bugs in this module.
224              
225             Please report problems to Ivan Wills (ivan.wills@gmail.com).
226              
227             Patches are welcome.
228              
229             =head1 AUTHOR
230              
231             Ivan Wills - (ivan.wills@gmail.com)
232              
233             =head1 LICENSE AND COPYRIGHT
234              
235             Copyright (c) 2012 Ivan Wills (14 Mullion Close, Hornsby Heights, NSW Australia 2077).
236             All rights reserved.
237              
238             This module is free software; you can redistribute it and/or modify it under
239             the same terms as Perl itself. See L<perlartistic>. This program is
240             distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
241             without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
242             PARTICULAR PURPOSE.
243              
244             =cut