File Coverage

blib/lib/Blessed/Merge.pm
Criterion Covered Total %
statement 80 80 100.0
branch 46 48 95.8
condition 23 26 88.4
subroutine 12 12 100.0
pod 2 2 100.0
total 163 168 97.0


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