File Coverage

blib/lib/Hub/Data/Address.pm
Criterion Covered Total %
statement 3 68 4.4
branch 0 52 0.0
condition 0 16 0.0
subroutine 1 9 11.1
pod 8 8 100.0
total 12 153 7.8


line stmt bran cond sub pod time code
1             package Hub::Data::Address;
2 1     1   5 use Hub qw/:lib/;
  1         2  
  1         6  
3             our $VERSION = '4.00043';
4             our @EXPORT = qw//;
5             our @EXPORT_OK = qw/
6             keydepth
7             vartype
8             varroot
9             varname
10             varparent
11             dotaddr
12             expand
13             collapse
14             /;
15             our $DELIMS = ':/';
16              
17             # ------------------------------------------------------------------------------
18             # keydepth
19             #
20             # For sorting parents and children, this simply lets you know how deep the key
21             # is named.
22             # ------------------------------------------------------------------------------
23             #|test(match,4) keydepth( 'and:then:came:the:rain' )
24             # ------------------------------------------------------------------------------
25              
26             sub keydepth {
27 0 0   0 1   defined $_[0] ? $_[0] =~ tr':/'' : 0;
28             }#keydepth
29              
30             # ------------------------------------------------------------------------------
31             # vartype VARADDR, [DEFAULT]
32             #
33             # Return a variables type (or a default value).
34             # ------------------------------------------------------------------------------
35             #|test(match) vartype( );
36             #|test(match,clr) vartype( "clr-bg" );
37             #|test(match,clr) vartype( "clr-bg", "default" );
38             #|test(match,default) vartype( "whatev", "default" );
39             #|test(match) vartype( "whatev" );
40             #|test(match) vartype( "a:b:c" );
41             #|test(match,x) vartype( "x-a:b:c" );
42             #|test(match,x) vartype( "a:b:x-c" );
43             # ------------------------------------------------------------------------------
44              
45             sub vartype {
46 0 0   0 1   my $str = defined $_[0] ? $_[0] : '';
47 0 0         my $def = defined $_[1] ? $_[1] : '';
48 0           my ($type) = $str =~ /[_]?([^-]+)-/;
49 0 0         $type = '' unless defined $type;
50 0           $type =~ s/.*://;
51 0   0       return $type || $def;
52             }#vartype
53              
54             #-------------------------------------------------------------------------------
55             # varroot VARADDR
56             #
57             # The root portion of the address.
58             #-------------------------------------------------------------------------------
59             #|test(match,p001) varroot( "p001:items:1002:text-description" );
60             #|test(match,p001) varroot( "p001" );
61             #-------------------------------------------------------------------------------
62              
63             sub varroot {
64 0 0   0 1   my $given = defined $_[0] ? $_[0] : '';
65 0           my ($root) = ( $given =~ /([^$DELIMS]+)/ );
66 0   0       return $root || '';
67             }#varroot
68              
69             #-------------------------------------------------------------------------------
70             # varname VARADDR
71             #
72             #-------------------------------------------------------------------------------
73             #|test(match,text-desc) varname( "p001:items:1002:text-desc" );
74             #|test(match,p001) varname( "p001" );
75             #-------------------------------------------------------------------------------
76              
77             sub varname {
78 0 0   0 1   my $given = defined $_[0] ? $_[0] : '';
79 0           my ($name,$end) = ( $given =~ /.*[$DELIMS]([^$DELIMS]+)([$DELIMS])?$/ );
80 0 0 0       return defined $end ? '' : $name || $given;
81             }#varname
82              
83             #-------------------------------------------------------------------------------
84             # varparent VARADDR
85             #
86             # Parent address.
87             #-------------------------------------------------------------------------------
88             #|test(match,p001:items:12) varparent( "p001:items:12:1000" );
89             #|test(match,p001:items:10:subs) varparent( "p001:items:10:subs:100" );
90             #|test(match) varparent( "p001" );
91             #-------------------------------------------------------------------------------
92              
93             sub varparent {
94 0 0   0 1   my $given = defined $_[0] ? $_[0] : '';
95 0           my ($container) = ( $given =~ /(.*)[$DELIMS]/ );
96 0   0       return $container || '';
97             }#varparent
98              
99             # ------------------------------------------------------------------------------
100             # dotaddr VARADDR
101             #
102             # Replace address separators with dots. In essence, protecting the address
103             # from expansion.
104             # ------------------------------------------------------------------------------
105             #|test(match,p004.proj.1000) dotaddr("p004:proj:1000");
106             #|test(match,p004.proj.1000.name) dotaddr("p004:proj:1000:name");
107             #|test(match,p001) dotaddr("p001");
108             #|test(!defined) dotaddr("");
109             # ------------------------------------------------------------------------------
110              
111             sub dotaddr {
112 0   0 0 1   my $address = shift || return;
113 0           $address =~ s/:/./g;
114 0           return $address;
115             }#dotaddr
116              
117             # ------------------------------------------------------------------------------
118             # expand HASHREF, [OPTIONS]
119             #
120             # Expands keys which are formatted as names (see naming.txt) into subhashes
121             # and subarrays as necessary.
122             #
123             # OPTIONS:
124             #
125             # meta => 1 # add '.address' and '.id' metadata to hashes
126             # root => SCALAR # use this as a prefix for '.address'
127             #
128             # Returns HASHREF
129             # ------------------------------------------------------------------------------
130              
131             sub expand {
132 0   0 0 1   my $src = shift || return; # source data
133 0           my $new = {}; # destination data
134 0           my %ops = @_;
135 0           my %meta = ();
136 0 0         if( ref($src) eq 'HASH' ) {
137 0           foreach my $k ( sort Hub::keydepth_sort keys %$src ) {
138 0           my $v = $$src{$k};
139 0           my @addr = split /[$DELIMS]/, $k;
140 0           my @nest = map { "->{'$_'}" } @addr;
  0            
141 0           my $dest = "\$new@nest";
142 0           eval( "$dest = \$v" );
143             # Create metadata
144 0 0         if( $ops{'meta'} ) {
145 0           pop @addr; # remove field key
146 0 0         if( @addr ) {
147 0           my $meta_addr = join ':', @addr;
148 0 0         unshift( @addr, $ops{'root'} ) if $ops{'root'};
149 0           my $meta_addr_val = join ':', @addr;
150 0           $meta{"$meta_addr:.address"} = $meta_addr_val;
151 0           $meta{"$meta_addr:.id"} = pop @addr;
152             }#if
153             }#if
154             }#foreach
155             }#if
156 0 0         if( %meta ) {
157 0           my $metadata = Hub::expand( \%meta );
158 0           Hub::merge( $new, $metadata );
159             }#if
160 0           return $new;
161             }#expand
162              
163             # ------------------------------------------------------------------------------
164             # collapse - Collapse a nested structure into key/value pairs
165             # collapse ?ref, [options]
166             #
167             # options
168             #
169             # -containers=1 Just return containers
170             #
171             # Returns a hash reference.
172             # ------------------------------------------------------------------------------
173              
174             sub collapse {
175 0     0 1   my ($opts, $ref, $addr, $result) = Hub::opts(\@_, {'containers'=>0});
176 0 0         croak "Provide a reference" unless ref($ref);
177             # my $addr = shift || '';
178             # my $result = shift;
179 0   0       $addr ||= '';
180 0 0         unless (defined $result) {
181 0           my %sh; tie %sh, 'Hub::Knots::SortedHash';
  0            
182 0           $result = \%sh;
183             }
184 0 0         if (isa($ref, 'HASH')) {
    0          
    0          
185 0 0         $addr .= '/' if $addr;
186 0           foreach my $k (keys %$ref) {
187 0 0         if (ref($$ref{$k})) {
188 0 0         $$result{$addr.$k} = $ref if $$opts{'containers'};
189 0           collapse($$ref{$k}, $addr.$k, $result, -opts => $opts);
190             } else {
191 0 0         $$result{$addr.$k} = $$ref{$k}
192             unless $$opts{'containers'};
193             }
194             }
195             } elsif (isa($ref, 'ARRAY')) {
196 0           for (my $idx = 0; $idx <= @$ref; $idx++) {
197 0 0         if (ref($$ref[$idx])) {
198 0 0         $$result{"$addr/$idx"} = $ref if $$opts{'containers'};
199 0           collapse($$ref[$idx], "$addr/$idx", $result, -opts => $opts);
200             } else {
201 0 0         $$result{"$addr/$idx"} = $$ref[$idx]
202             unless $$opts{'containers'};
203             }
204             }
205             } elsif (isa($ref, 'SCALAR')) {
206 0 0         $$result{$addr} = $$ref
207             unless $$opts{'containers'};
208             } else {
209 0           die "Cannot collapse: $ref";
210             }
211 0           return $result;
212             }
213              
214             1;