File Coverage

blib/lib/Blessed/Merge.pm
Criterion Covered Total %
statement 82 82 100.0
branch 52 52 100.0
condition 18 18 100.0
subroutine 12 12 100.0
pod 2 2 100.0
total 166 166 100.0


line stmt bran cond sub pod time code
1             package Blessed::Merge;
2              
3 5     5   602077 use 5.006;
  5         58  
4              
5             our $VERSION = '1.00';
6 5     5   29 use strict;
  5         12  
  5         121  
7 5     5   36 use warnings;
  5         10  
  5         168  
8 5     5   26 use Scalar::Util qw/reftype/;
  5         33  
  5         332  
9 5     5   36 use Carp qw/croak/;
  5         15  
  5         243  
10 5     5   2354 use Combine::Keys qw/combine_keys/;
  5         94741  
  5         42  
11 5     5   2934 use Tie::IxHash;
  5         21219  
  5         4947  
12              
13             sub new {
14 6 100 100 6 1 4503 my ($pkg, $args) = (shift, reftype $_[0] || "" eq 'HASH' ? $_[0] : {@_});
15 6         22 my $self = bless $args, $pkg;
16 6   100     63 $self->{$_} = $self->{$_} // 1 foreach (qw/same blessed/);
17 6   100     45 $self->{$_} = $self->{$_} // 0 foreach(qw/unique_array unique_hash/);
18 6         14 $self->{itterator} = 1;
19 6         20 return $self;
20             }
21              
22             sub merge {
23 11     11 1 11993 my ($self, $base_bless, $new) = (shift, ref $_[0], shift);
24 11         55 tie my %isa, 'Tie::IxHash';
25 11         219 $isa{$base_bless} = $new;
26             map {
27 11 100       209 if ( $self->{same} ) {
  17         71  
28 9 100       191 croak 'Attempting to merge two different *packages*' unless $base_bless eq ref $_;
29             } else {
30 8         15 my $r = ref $_;
31 8 100       51 $isa{$r} = $_ unless $r =~ m/HASH|ARRAY|SCALAR/;
32             }
33 16         141 $new = $self->_merge($new, $_);
34             } @_;
35 10         65 for my $f (keys %isa) {
36 16 100       260 my $check = $isa{$f} or next;
37 15         167 for (keys %isa) {
38 33 100       406 $_ eq $f and next;
39 18 100       90 delete $isa{$_} if $check->isa($_);
40             }
41             }
42 10 100       57 return $self->{blessed} ? scalar keys %isa == 1 ? bless $new, $base_bless : do {
    100          
43 2         60 my $class = sprintf "Blessed::Merge::__ANON__::%s", $self->{itterator}++;
44 2         8 eval sprintf('package %s; our @ISA = qw/%s/; 1;', $class, join ' ', keys %isa);
45 2         23 return bless $new, $class;
46             } : $new;
47             }
48              
49             sub _merge {
50 80     80   379 my ($self, $new, $merger) = @_;
51 80 100       196 return $new unless defined $merger;
52 70   100     209 my $new_ref = reftype($new) || '';
53 70   100     169 my $merger_ref = reftype($merger) || 'SCALAR';
54             $merger_ref eq 'HASH' ? do {
55 39 100       68 $new = {} if ( $new_ref ne 'HASH' );
56             return {
57             $self->{unique_hash}
58             ? $self->_unique_merge($merger_ref, $new, $merger)
59 39 100       129 : map +( $_ => $self->_merge( $new->{$_}, $merger->{$_} ) ), combine_keys($new, $merger)
60             };
61 70 100       203 } : $merger_ref eq 'ARRAY' ? do {
    100          
62             $new_ref eq 'ARRAY' ? do {
63 11 100   11   14 my $length = sub {$_[0] < $_[1] ? $_[1] : $_[0]}->(scalar @{$new}, scalar @{$merger});
  11         39  
  11         20  
  11         43  
64             [ $self->{unique_array}
65             ? $self->_unique_merge($merger_ref, $new, $merger, $length)
66 11 100       53 : map { $self->_merge($new->[$_], $merger->[$_]) } 0 .. $length - 1
  6         13  
67             ];
68 13 100       25 } : [ map { $self->_merge('', $_ ) } @{ $merger } ]; # destroy da references
  6         13  
  2         14  
69             } : $merger;
70             }
71              
72             sub _unique_merge {
73 28     28   55 my ($s, $r, $n, $m, $l) = @_;
74 28 100       54 ($r eq 'ARRAY') && do {
75 9         15 my (@z, %u, $x1, $x2);
76 9         21 for (my $i = 0; $i < $l; $i++) {
77             my $c = grep {
78 24         39 my ($x) = reftype(\$_);
  48         90  
79 48 100 100     144 $x eq 'SCALAR' ? !$_ || exists $u{$_} ? 1 : do { $u{$_} = 1; push @z, $_; } : 0;
  27 100       49  
  27         50  
80             } ($n->[$i], $m->[$i]);
81 24 100       53 do { ($x1, $x2) = (reftype($n->[$i]), reftype($m->[$i])); $c == 0 }
  5 100       46  
  5 100       33  
    100          
82             ? $x1 eq $x2
83             ? push @z, $s->_merge($n->[$i], $m->[$i])
84             : push @z, $n->[$i], $m->[$i]
85             : $x1
86             ? push @z, $n->[$i]
87             : push @z, $m->[$i] if $c != 2;
88             }
89 9         49 return @z;
90             };
91 19         22 my %z = %{ $n };
  19         57  
92             map {
93 31   100     94 my $x = reftype($m->{$_}) || 'SCALAR';
94             exists $z{$_} ? $x ne 'SCALAR' && $x eq reftype($z{$_})
95 31 100 100     124 ? do { $z{$_} = $s->_merge($z{$_}, $m->{$_}) } : '*\o/*' : do { $z{$_} = $m->{$_} }
  21 100       49  
  4         18  
96 19         33 } keys %{ $m };
  19         37  
97 19         89 return %z;
98             }
99              
100             1;
101              
102             __END__