File Coverage

lib/Morpheus/Utils.pm
Criterion Covered Total %
statement 85 90 94.4
branch 26 30 86.6
condition 10 12 83.3
subroutine 7 7 100.0
pod 0 3 0.0
total 128 142 90.1


line stmt bran cond sub pod time code
1             package Morpheus::Utils;
2             {
3             $Morpheus::Utils::VERSION = '0.46';
4             }
5 6     6   113759 use strict;
  6         14  
  6         335  
6              
7             # ABSTRACT: some common functions which don't fit anywhere else
8              
9             sub normalize ($);
10             sub adjust ($$);
11             sub merge ($$;$);
12              
13 6     6   32 use base qw(Exporter);
  6         11  
  6         982  
14             our @EXPORT = qw(normalize merge adjust);
15              
16 6     6   4446 use Symbol qw(gensym);
  6         4672  
  6         507  
17              
18 6     6   2241 use Morpheus::Key qw(key);
  6         14  
  6         5545  
19              
20             sub normalize ($) {
21 112     112 0 1344 my ($data) = @_;
22 112 100       373 return $data unless ref $data eq "HASH";
23 91         323 my $result = { %$data };
24 91         362 for my $key ( keys %$data) {
25 124         142 my @keys = @{key($key)};
  124         333  
26 124 100 100     919 next if @keys == 1 and $keys[0] eq $key; # "/a//" -> "a"
27 54         115 my $value = delete $result->{$key};
28 54         161 my $p = my $patch = {};
29 54         306 $p = $p->{$_} = {} for splice @keys, 0, -1;
30 54         151 $p->{$keys[0]} = $value;
31 54         110 $result = merge($result, $patch);
32             # {"a/b/c"=>"d"} -> {a=>{b=>{c=>"d"}}}
33             }
34 91         313 return $result;
35             }
36              
37             sub adjust ($$) {
38 950     950 0 1803 my ($value, $delta) = @_;
39 950 50       2136 return $value unless $delta;
40 950         1012 for (@{key($delta)}) {
  950         2109  
41 2486 100 100     11175 if (defined $value and ref $value eq "HASH") {
    100 66        
42 1802         3835 $value = $value->{$_};
43             } elsif (defined $value and ref $value eq "GLOB") {
44 1         2 $value = ${*$value}{$_};
  1         9  
45             } else {
46 683         1854 return (undef);
47             }
48             }
49 267         1221 return $value;
50             }
51              
52             sub merge ($$;$) {
53 1573     1573 0 10994 my ($value, $patch, $die_on_collision) = @_;
54             #TODO: support $die_on_collision!
55              
56 1573 100       6435 return $patch unless defined $value;
57 621 100       1660 return $value unless defined $patch;
58              
59 516         791 my %refs = map { $_ => 1 } qw(GLOB HASH ARRAY);
  1548         3273  
60            
61             # TODO: return a glob itself instead of a globref!
62            
63 516         941 my $ref_value = ref $value;
64 516 100       1203 $ref_value = "" unless $refs{$ref_value};
65 516         713 my $ref_patch = ref $patch;
66 516 100       1069 $ref_patch = "" unless $refs{$ref_patch};
67            
68 516 100       1063 if ($ref_value eq "GLOB") {
69 1         3 my $result = gensym;
70 1         9 *{$result} = *{$value};
  1         2  
  1         2  
71 1 50       4 if ($ref_patch eq "GLOB") {
72 1         2 my $hash = merge(*{$value}{HASH}, *{$patch}{HASH});
  1         2  
  1         3  
73 1 50       3 *{$result} = $hash if $hash;
  1         3  
74 1         20 my $array = merge(*{$value}{ARRAY}, *{$patch}{ARRAY});
  1         3  
  1         2  
75 1 50       4 *{$result} = $array if $array;
  1         2  
76 1         1 ${*{$result}} = merge(${*{$value}}, ${*{$patch}});
  1         1  
  1         3  
  1         2  
  1         3  
  1         2  
  1         3  
77             } else {
78 0         0 ${*{$result}} = merge(${*{$value}}, $patch);
  0         0  
  0         0  
  0         0  
  0         0  
79             }
80 1         4 return $result;
81             }
82            
83 515 100       960 if ($ref_patch eq "GLOB") {
84 1         3 my $result = gensym;
85 1         9 *{$result} = *{$patch};
  1         3  
  1         2  
86 1         1 ${*{$result}} = merge($value, ${*{$patch}});
  1         1  
  1         3  
  1         2  
  1         3  
87 1         4 return $result;
88             }
89              
90 514 100 66     1645 if ($ref_value eq "HASH" and $ref_patch eq "HASH") {
91 234         808 my $result = { %$value };
92 234         642 for (keys %$patch) {
93 498         1310 $result->{$_} = merge($value->{$_}, $patch->{$_});
94             }
95 234         1287 return $result;
96             }
97              
98 280         1117 return $value;
99             }
100              
101             1;
102              
103             __END__