File Coverage

blib/lib/Data/Context/Util.pm
Criterion Covered Total %
statement 76 83 91.5
branch 35 40 87.5
condition 8 15 53.3
subroutine 13 15 86.6
pod 3 3 100.0
total 135 156 86.5


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 4     4   25647 use strict;
  4         6  
  4         127  
10 4     4   42 use warnings;
  4         5  
  4         141  
11 4     4   569 use version;
  4         2221  
  4         35  
12 4     4   275 use Carp;
  4         7  
  4         261  
13 4     4   23 use Scalar::Util qw/blessed/;
  4         6  
  4         256  
14 4     4   20 use List::Util;
  4         6  
  4         228  
15 4     4   16 use Data::Dumper qw/Dumper/;
  4         5  
  4         963  
16 4     4   465 use English qw/ -no_match_vars /;
  4         2841  
  4         46  
17 4     4   3768 use Class::Inspector;
  4         12712  
  4         152  
18 4     4   32 use base qw/Exporter/;
  4         4  
  4         3126  
19              
20             our $VERSION = version->new('0.1.10');
21             our @EXPORT_OK = qw/lol_path lol_iterate do_require/;
22              
23             sub lol_path {
24 9     9 1 2263 my ($lol, $path) = @_;
25 9         37 my @path = split /[.]/xms, $path;
26 9         12 my $point = $lol;
27 9         6 my $replacer;
28              
29             POINT:
30 9   33     44 while ( $point && @path ) {
31              
32             # ignore empty path parts
33 21 50 33     69 if ( ! defined $path[0] || $path[0] eq '' ) {
34 0         0 shift @path;
35 0         0 next POINT;
36             }
37              
38 21         24 my $item = shift @path;
39 21         17 my $current = $point;
40              
41             # process the point
42 21 50 33     66 if ( !ref $point ) {
    100          
    100          
    50          
43 0         0 return;
44             }
45             elsif ( ref $point eq 'HASH' ) {
46 15     0   39 $replacer = sub { $current->{$item} = shift };
  0         0  
47 15         27 $point = $point->{$item};
48             }
49             elsif ( ref $point eq 'ARRAY' ) {
50 5     0   12 $replacer = sub { $current->[$item] = shift };
  0         0  
51 5         15 $point = $point->[$item];
52             }
53             elsif ( blessed $point && $point->can( $item ) ) {
54 1         3 $replacer = undef;
55 1         29 $point = $point->$item();
56             }
57             else {
58 0         0 confess "Don't know how to deal with $point";
59             }
60              
61 21 50       103 return wantarray ? ($point, $replacer) : $point if !@path;
    100          
62             }
63              
64             # nothing found
65 0         0 return;
66             }
67              
68             sub lol_iterate {
69 33     33 1 2794 my ($lol, $code, $path) = @_;
70 33         31 my $point = $lol;
71              
72 33 100 100     87 if ( !$path && defined $point ) {
73 6         17 $code->( $point, $path );
74             }
75              
76 33 100       78 $path = $path ? "$path." : '';
77              
78 33 100       47 if ( $point ) {
79 31 100 66     95 if ( !ref $point ) {
    100          
    100          
    100          
80 1         2 $code->( $point, $path );
81             }
82             elsif ( ref $point eq 'HASH' ) {
83 23         66 for my $key ( keys %$point ) {
84 58         149 $code->( $point->{$key}, "$path$key" );
85 58 100       220 lol_iterate( $point->{$key}, $code, "$path$key" ) if ref $point->{$key};
86             }
87             }
88             elsif ( ref $point eq 'ARRAY' ) {
89 5         19 for my $i ( 0 .. @$point - 1 ) {
90 10         32 $code->( $point->[$i], "$path$i" );
91 10 100       42 lol_iterate( $point->[$i], $code, "$path$i" ) if ref $point->[$i];
92             }
93             }
94 2         3 elsif ( blessed $point && eval { %{$point} } ) {
  2         14  
95 1         3 for my $key ( keys %$point ) {
96 1         7 $code->( $point->{$key}, "$path$key" );
97 1 50       7 lol_iterate( $point->{$key}, $code, "$path$key" ) if ref $point->{$key};
98             }
99             }
100             }
101              
102 33         55 return;
103             }
104              
105             our %required;
106             sub do_require {
107 18     18 1 377 my ($module) = @_;
108              
109 18 100       66 return if $required{$module}++;
110              
111             # check if namespace appears to be loaded
112 7 100       64 return if Class::Inspector->loaded($module);
113              
114             # Try loading namespace
115 2         129 $module =~ s{::}{/}gxms;
116 2         5 $module .= '.pm';
117 2         4 eval {
118 2         1036 require $module
119             };
120 2 100       12 if (my $e = $@) {
121 1         247 confess $e;
122             }
123              
124 1         6 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.10.
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