File Coverage

blib/lib/Data/ModeMerge/Mode/Base.pm
Criterion Covered Total %
statement 342 362 94.4
branch 181 196 92.3
condition 116 132 87.8
subroutine 20 25 80.0
pod 7 10 70.0
total 666 725 91.8


line stmt bran cond sub pod time code
1             package Data::ModeMerge::Mode::Base;
2              
3             our $DATE = '2021-08-15'; # DATE
4             our $VERSION = '0.360'; # VERSION
5              
6 31     31   16006 use 5.010;
  31         101  
7 31     31   130 use strict;
  31         74  
  31         573  
8 31     31   144 use warnings;
  31         86  
  31         876  
9              
10             #use Data::Dmp;
11              
12             #use Log::Any '$log';
13 31     31   150 use Mo qw(build default);
  31         50  
  31         148  
14              
15             #use Data::Clone qw/clone/;
16              
17             has merger => (is => 'rw');
18             has prefix => (is => 'rw');
19             has prefix_re => (is => 'rw');
20             has check_prefix_sub => (is => 'rw');
21             has add_prefix_sub => (is => 'rw');
22             has remove_prefix_sub => (is => 'rw');
23              
24             sub name {
25 0     0 1 0 die "Subclass must provide name()";
26             }
27              
28             sub precedence_level {
29 0     0 1 0 die "Subclass must provide precedence_level()";
30             }
31              
32             sub default_prefix {
33 0     0 1 0 die "Subclass must provide default_prefix()";
34             }
35              
36             sub default_prefix_re {
37 0     0 1 0 die "Subclass must provide default_prefix_re()";
38             }
39              
40             sub BUILD {
41 1980     1980 0 69668 my ($self) = @_;
42 1980         4394 $self->prefix($self->default_prefix);
43 1980         9509 $self->prefix_re($self->default_prefix_re);
44             }
45              
46             sub check_prefix {
47 11471     11471 1 21866 my ($self, $hash_key) = @_;
48 11471 50       16016 if ($self->check_prefix_sub) {
49 0         0 $self->check_prefix_sub->($hash_key);
50             } else {
51 11471         34939 $hash_key =~ $self->prefix_re;
52             }
53             }
54              
55             sub add_prefix {
56 101     101 1 1182 my ($self, $hash_key) = @_;
57 101 100       253 if ($self->add_prefix_sub) {
58 4         15 $self->add_prefix_sub->($hash_key);
59             } else {
60 97         401 $self->prefix . $hash_key;
61             }
62             }
63              
64             sub remove_prefix {
65 942     942 1 2863 my ($self, $hash_key) = @_;
66 942 100       1658 if ($self->remove_prefix_sub) {
67 10         34 $self->remove_prefix_sub->($hash_key);
68             } else {
69 932         3006 my $re = $self->prefix_re;
70 932         4298 $hash_key =~ s/$re//;
71 932         2152 $hash_key;
72             }
73             }
74              
75             sub merge_ARRAY_ARRAY {
76 13     13 0 28 my ($self, $key, $l, $r) = @_;
77 13         34 my $mm = $self->merger;
78 13         88 my $c = $mm->config;
79 13 100       54 return $self->merge_SCALAR_SCALAR($key, $l, $r) unless $c->recurse_array;
80 4 50 33     41 return if $c->wanted_path && !$mm->_path_is_included($mm->path, $c->wanted_path);
81              
82 4         46 my @res;
83             my @backup;
84 4         9 my $la = @$l;
85 4         15 my $lb = @$r;
86 4         7 push @{ $mm->path }, -1;
  4         12  
87 4 100       76 for my $i (0..($la > $lb ? $la : $lb)-1) {
88             #print "DEBUG: merge_A_A: #$i: a->[$i]=".Data::Dumper->new([$l->[$i]])->Indent(0)->Terse(1)->Dump.", b->[$i]=".Data::Dumper->new([$r->[$i]])->Indent(0)->Terse(1)->Dump."\n";
89 6         45 $mm->path->[-1] = $i;
90 6 100 66     70 if ($i < $la && $i < $lb) {
    50          
91 5         12 push @backup, $l->[$i];
92 5         15 my ($subnewkey, $subres, $subbackup, $is_circular) = $mm->_merge($i, $l->[$i], $r->[$i], $c->default_mode);
93 5 50       9 last if @{ $mm->errors };
  5         10  
94 5 50       56 if ($is_circular) {
95 0         0 push @res, undef;
96             #print "DEBUG: pushing todo to mem<".$mm->cur_mem_key.">\n";
97 0         0 push @{ $mm->mem->{ $mm->cur_mem_key }{todo} }, sub {
98 0     0   0 my ($subnewkey, $subres, $subbackup) = @_;
99             #print "DEBUG: Entering todo subroutine (i=$i)\n";
100 0         0 $res[$i] = $subres;
101             }
102 0         0 } else {
103 5         14 push @res, $subres;# if defined($newkey); = we allow DELETE on array?
104             }
105             } elsif ($i < $la) {
106 1         3 push @res, $l->[$i];
107             } else {
108 0         0 push @res, $r->[$i];
109             }
110             }
111 4         5 pop @{ $mm->path };
  4         27  
112 4         35 ($key, \@res, \@backup);
113             }
114              
115             sub _prefilter_hash {
116 18     18   63 my ($self, $h, $desc, $sub) = @_;
117 18         22 my $mm = $self->merger;
118              
119 18 100       59 if (ref($sub) ne 'CODE') {
120 3         11 $mm->push_error("$desc failed: filter must be a coderef");
121 3         5 return;
122             }
123              
124 15         22 my $res = {};
125 15         32 for (keys %$h) {
126 17         33 my @r = $sub->($_, $h->{$_});
127 17         105 while (my ($k, $v) = splice @r, 0, 2) {
128 21 100       41 next unless defined $k;
129 17 100       23 if (exists $res->{$k}) {
130 1         13 $mm->push_error("$desc failed; key conflict: ".
131             "$_ -> $k, but key $k already exists");
132 1         3 return;
133             }
134 16         51 $res->{$k} = $v;
135             }
136             }
137              
138 14         25 $res;
139             }
140              
141             # turn {[prefix]key => val, ...} into { key => [MODE, val], ...}, push
142             # error if there's conflicting key
143             sub _gen_left {
144 566     566   1212 my ($self, $l, $mode, $esub, $ep, $ip, $epr, $ipr) = @_;
145 566         984 my $mm = $self->merger;
146 566         1892 my $c = $mm->config;
147              
148             #print "DEBUG: Entering _gen_left(".dmp($l).", $mode, ...)\n";
149              
150 566 100       1812 if ($c->premerge_pair_filter) {
151 11         41 $l = $self->_prefilter_hash($l, "premerge filter left hash",
152             $c->premerge_pair_filter);
153 11 100       19 return if @{ $mm->errors };
  11         24  
154             }
155              
156 562         1933 my $hl = {};
157 562 100       1047 if ($c->parse_prefix) {
158 553         2539 for (keys %$l) {
159 1171         1452 my $do_parse = 1;
160 1171 100 66     3183 $do_parse = 0 if $do_parse && $ep && $mm->_in($_, $ep);
      100        
161 1171 100 100     2936 $do_parse = 0 if $do_parse && $ip && !$mm->_in($_, $ip);
      66        
162 1171 100 100     2902 $do_parse = 0 if $do_parse && $epr && /$epr/;
      100        
163 1171 100 100     2834 $do_parse = 0 if $do_parse && $ipr && !/$ipr/;
      100        
164              
165 1171 100       1597 if ($do_parse) {
166 1128         1359 my $old = $_;
167 1128         1197 my $m2;
168 1128         2162 ($_, $m2) = $mm->remove_prefix($_);
169 1127 100 66     8298 next if $esub && !$esub->($_);
170 538 50 66     1118 if ($old ne $_ && exists($l->{$_})) {
171 0         0 $mm->push_error("Conflict when removing prefix on left-side ".
172             "hash key: $old -> $_ but $_ already exists");
173 0         0 return;
174             }
175 538         1642 $hl->{$_} = [$m2, $l->{$old}];
176             } else {
177 43 100 66     97 next if $esub && !$esub->($_);
178 41         125 $hl->{$_} = [$mode, $l->{$_}];
179             }
180             }
181             } else {
182 9         56 for (keys %$l) {
183 27 100 66     50 next if $esub && !$esub->($_);
184 21         60 $hl->{$_} = [$mode, $l->{$_}];
185             }
186             }
187              
188             #print "DEBUG: Leaving _gen_left, result = ".dmp($hl)."\n";
189 561         1237 $hl;
190             }
191              
192             # turn {[prefix]key => val, ...} into { key => {MODE=>val, ...}, ...},
193             # push error if there's conflicting key+MODE
194             sub _gen_right {
195 561     561   1101 my ($self, $r, $mode, $esub, $ep, $ip, $epr, $ipr) = @_;
196 561         988 my $mm = $self->merger;
197 561         1738 my $c = $mm->config;
198              
199             #print "DEBUG: Entering _gen_right(".dmp($r).", $mode, ...)\n";
200              
201 561 100       1736 if ($c->premerge_pair_filter) {
202 7         25 $r = $self->_prefilter_hash($r, "premerge filter right hash",
203             $c->premerge_pair_filter);
204 7 50       12 return if @{ $mm->errors };
  7         12  
205             }
206              
207 561         1844 my $hr = {};
208 561 100       970 if ($c->parse_prefix) {
209 552         3313 for (keys %$r) {
210 1201         1490 my $do_parse = 1;
211 1201 100 66     3129 $do_parse = 0 if $do_parse && $ep && $mm->_in($_, $ep);
      100        
212 1201 100 100     2879 $do_parse = 0 if $do_parse && $ip && !$mm->_in($_, $ip);
      100        
213 1201 100 100     2945 $do_parse = 0 if $do_parse && $epr && /$epr/;
      100        
214 1201 100 100     2969 $do_parse = 0 if $do_parse && $ipr && !/$ipr/;
      100        
215              
216 1201 100       1625 if ($do_parse) {
217 1155         1367 my $old = $_;
218 1155         1209 my $m2;
219 1155         2122 ($_, $m2) = $mm->remove_prefix($_);
220 1155 100 66     4678 next if $esub && !$esub->($_);
221 550 50       1362 if (exists $hr->{$_}{$m2}) {
222 0         0 $mm->push_error("Conflict when removing prefix on right-side ".
223             "hash key: $old($m2) -> $_ ($m2) but $_ ($m2) ".
224             "already exists");
225 0         0 return;
226             }
227 550         1473 $hr->{$_}{$m2} = $r->{$old};
228             } else {
229 46 100 66     83 next if $esub && !$esub->($_);
230 44         113 $hr->{$_} = {$mode => $r->{$_}};
231             }
232             }
233             } else {
234 9         47 for (keys %$r) {
235 25 100 66     49 next if $esub && !$esub->($_);
236 20         64 $hr->{$_} = {$mode => $r->{$_}}
237             }
238             }
239             #print "DEBUG: Leaving _gen_right, result = ".dmp($hr)."\n";
240 561         1096 $hr;
241             }
242              
243             # merge two hashes which have been prepared by _gen_left and
244             # _gen_right, will result in { key => [final_mode, val], ... }
245             sub _merge_gen {
246 554     554   1009 my ($self, $hl, $hr, $mode, $em, $im, $emr, $imr) = @_;
247 554         1020 my $mm = $self->merger;
248 554         1731 my $c = $mm->config;
249              
250             #print "DEBUG: Entering _merge_gen(".dmp($hl).", ".dmp($hr).", $mode, ...)\n";
251              
252 554         1553 my $res = {};
253 554         786 my $backup = {};
254              
255 554         1664 my %k = map {$_=>1} keys(%$hl), keys(%$hr);
  1186         2380  
256 554         853 push @{ $mm->path }, "";
  554         1037  
257             K:
258 554         2963 for my $k (keys %k) {
259 706         856 my @o;
260 706         1216 $mm->path->[-1] = $k;
261 706         3089 my $do_merge = 1;
262 706 100 66     2005 $do_merge = 0 if $do_merge && $em && $mm->_in($k, $em);
      100        
263 706 100 100     1762 $do_merge = 0 if $do_merge && $im && !$mm->_in($k, $im);
      100        
264 706 100 100     1804 $do_merge = 0 if $do_merge && $emr && $k =~ /$emr/;
      100        
265 706 100 100     1776 $do_merge = 0 if $do_merge && $imr && $k !~ /$imr/;
      100        
266              
267 706 100       1049 if (!$do_merge) {
268 47 100       128 $res->{$k} = $hl->{$k} if $hl->{$k};
269 47         75 next K;
270             }
271              
272 659 100 100     2020 $backup->{$k} = $hl->{$k}[1] if $hl->{$k} && $hr->{$k};
273 659 100       1189 if ($hl->{$k}) {
274 553         859 push @o, $hl->{$k};
275             }
276 659 100       1029 if ($hr->{$k}) {
277 541         948 my %m = map {$_=>$mm->modes->{$_}->precedence_level} keys %{ $hr->{$k} };
  561         1121  
  541         1398  
278             #print "DEBUG: \\%m=".Data::Dumper->new([\%m])->Indent(0)->Terse(1)->Dump."\n";
279 541         1244 push @o, map { [$_, $hr->{$k}{$_}] } sort { $m{$b} <=> $m{$a} } keys %m;
  561         1607  
  26         79  
280             }
281 659         1745 my $final_mode;
282             my $is_circular;
283 659         0 my $v;
284             #print "DEBUG: k=$k, o=".Data::Dumper->new([\@o])->Indent(0)->Terse(1)->Dump."\n";
285 659         1331 for my $i (0..$#o) {
286 1112 100       1715 if ($i == 0) {
287 659         1244 my $mh = $mm->modes->{$o[$i][0]};
288 659 100 100     4936 if (@o == 1 &&
      100        
289             (($hl->{$k} && $mh->can("merge_left_only")) ||
290             ($hr->{$k} && $mh->can("merge_right_only")))) {
291             # there's only left-side or right-side
292 3 100       8 my $meth = $hl->{$k} ? "merge_left_only" : "merge_right_only";
293 3         8 my ($subnewkey, $v1, $subbackup, $is_circular, $newmode) = $mh->$meth($k, $o[$i][1]); # XXX handle circular?
294 3 50       14 next K unless defined($subnewkey);
295 0         0 $final_mode = $newmode;
296 0         0 $v = $v1;
297             } else {
298 656         928 $final_mode = $o[$i][0];
299 656         1031 $v = $o[$i][1];
300             }
301             } else {
302             my $m = $mm->combine_rules->{"$final_mode+$o[$i][0]"}
303 453 100       809 or do {
304 8         67 $mm->push_error("Can't merge $final_mode + $o[$i][0]");
305 8         31 return;
306             };
307             #print "DEBUG: merge $final_mode+$o[$i][0] = $m->[0], $m->[1]\n";
308 445         1970 my ($subnewkey, $subbackup);
309 445         1170 ($subnewkey, $v, $subbackup, $is_circular) = $mm->_merge($k, $v, $o[$i][1], $m->[0]);
310 445 100       615 return if @{ $mm->errors };
  445         723  
311 409 100       2121 if ($is_circular) {
312 3 100       5 if ($i < $#o) {
313 1         5 $mm->push_error("Can't handle circular at $i of $#o merges (mode $m->[0]): not the last merge");
314 1         5 return;
315             }
316             #print "DEBUG: pushing todo to mem<".$mm->cur_mem_key.">\n";
317 2         4 push @{ $mm->mem->{ $mm->cur_mem_key }{todo} }, sub {
318 2     2   4 my ($subnewkey, $subres, $subbackup) = @_;
319             #print "DEBUG: Entering todo subroutine (k=$k)\n";
320 2         4 my $final_mode = $m->[1];
321             #XXX return unless defined($subnewkey);
322 2         3 $res->{$k} = [$m->[1], $subres];
323 2 50       4 if ($c->readd_prefix) {
324             # XXX if there is a conflict error in
325             # _readd_prefix, how to adjust path?
326 2         10 $self->_readd_prefix($res, $k, $c->default_mode);
327             } else {
328 0         0 $res->{$k} = $res->{$k}[1];
329             }
330 2         3 };
331 2         41 delete $res->{$k};
332             }
333 408 100       866 next K unless defined $subnewkey;
334 351         677 $final_mode = $m->[1];
335             }
336             }
337 554 100       1979 $res->{$k} = [$final_mode, $v] unless $is_circular;
338             }
339 509         691 pop @{ $mm->path };
  509         831  
340             #print "DEBUG: Leaving _merge_gen, res = ".dmp($res)."\n";
341 509         3256 ($res, $backup);
342             }
343              
344             # hh is {key=>[MODE, val], ...} which is the format returned by _merge_gen
345             sub _readd_prefix {
346 508     508   2492 my ($self, $hh, $k, $defmode) = @_;
347 508         789 my $mm = $self->merger;
348 508         1475 my $c = $mm->config;
349              
350 508         1366 my $m = $hh->{$k}[0];
351 508 100       781 if ($m eq $defmode) {
352 443         934 $hh->{$k} = $hh->{$k}[1];
353             } else {
354 65         112 my $kp = $mm->modes->{$m}->add_prefix($k);
355 65 50       300 if (exists $hh->{$kp}) {
356 0         0 $mm->push_error("BUG: conflict when re-adding prefix after merge: $kp");
357 0         0 return;
358             }
359 65         124 $hh->{$kp} = $hh->{$k}[1];
360 65         158 delete $hh->{$k};
361             }
362             }
363              
364             sub merge_HASH_HASH {
365 304     304 0 591 my ($self, $key, $l, $r, $mode) = @_;
366 304         637 my $mm = $self->merger;
367 304         1087 my $c = $mm->config;
368 304   66     1342 $mode //= $c->default_mode;
369             #print "DEBUG: entering merge_H_H(".dmp($l).", ".dmp($r).", $mode), config=($c)=",dmp($c),"\n";
370             #$log->trace("using config($c)");
371              
372 304 100       1947 return $self->merge_SCALAR_SCALAR($key, $l, $r) unless $c->recurse_hash;
373 300 100 100     813 return if $c->wanted_path && !$mm->_path_is_included($mm->path, $c->wanted_path);
374              
375             # STEP 1. MERGE LEFT & RIGHT OPTIONS KEY
376 298         1169 my $config_replaced;
377 298         374 my $orig_c = $c;
378 298         552 my $ok = $c->options_key;
379             {
380 298 100       572 last unless defined $ok;
  298         554  
381              
382 297     611   1511 my $okl = $self->_gen_left ($l, $mode, sub {$_[0] eq $ok});
  611         2082  
383 296 100       787 return if @{ $mm->errors };
  296         595  
384              
385 292     626   2340 my $okr = $self->_gen_right($r, $mode, sub {$_[0] eq $ok});
  626         2210  
386 292 50       723 return if @{ $mm->errors };
  292         583  
387              
388 292         1563 push @{ $mm->path }, $ok;
  292         509  
389 292         1459 my ($res, $backup);
390             {
391 292         355 local $c->{readd_prefix} = 0;
  292         634  
392 292         825 ($res, $backup) = $self->_merge_gen($okl, $okr, $mode);
393             }
394 292         422 pop @{ $mm->path };
  292         484  
395 292 100       1215 return if @{ $mm->errors };
  292         519  
396              
397             #print "DEBUG: merge options key (".dmp($okl).", ".dmp($okr).") = ".dmp($res)."\n";
398              
399 291 100       1658 $res = $res->{$ok} ? $res->{$ok}[1] : undef;
400 291 100 100     864 if (defined($res) && ref($res) ne 'HASH') {
401 6         15 $mm->push_error("Invalid options key after merge: value must be hash");
402 6         22 return;
403             }
404 285 100       984 last unless keys %$res;
405             #$log->tracef("cloning config ...");
406             # Data::Clone by default does *not* deep-copy object
407             #my $c2 = clone($c);
408 62         416 my $c2 = bless({ %$c }, ref($c));
409              
410 62         137 for (keys %$res) {
411 62 100       112 if ($c->allow_override) {
412 5         20 my $re = $c->allow_override;
413 5 100       28 if (!/$re/) {
414 2         8 $mm->push_error("Configuration in options key `$_` not allowed by allow_override $re");
415 2         9 return;
416             }
417             }
418 60 100       239 if ($c->disallow_override) {
419 4         15 my $re = $c->disallow_override;
420 4 100       20 if (/$re/) {
421 2         9 $mm->push_error("Configuration in options key `$_` not allowed by disallow_override $re");
422 2         9 return;
423             }
424             }
425 58 100       212 if ($mm->_in($_, $c->_config_config)) {
426 4         27 $mm->push_error("Configuration not allowed in options key: $_");
427 4         18 return;
428             }
429 54 100 66     140 if ($_ ne $ok && !$mm->_in($_, $c->_config_ok)) {
430 1         4 $mm->push_error("Unknown configuration in options key: $_");
431 1         10 return;
432             }
433 53 50       225 $c2->$_($res->{$_}) unless $_ eq $ok;
434             }
435 53         273 $mm->config($c2);
436 53         146 $config_replaced++;
437 53         128 $c = $c2;
438             #$log->trace("config now changed to $c2");
439             }
440              
441 277         619 my $sp = $c->set_prefix;
442 277         838 my $saved_prefixes;
443 277 100       503 if (defined($sp)) {
444 7 100       25 if (ref($sp) ne 'HASH') {
445 2         6 $mm->push_error("Invalid config value `set_prefix`: must be a hash");
446 2         7 return;
447             }
448 5         9 $saved_prefixes = {};
449 5         8 for my $mh (values %{ $mm->modes }) {
  5         10  
450 30         119 my $n = $mh->name;
451 30 100       67 if ($sp->{$n}) {
452 7         13 $saved_prefixes->{$n} = {
453             prefix => $mh->prefix,
454             prefix_re => $mh->prefix_re,
455             check_prefix_sub => $mh->check_prefix_sub,
456             add_prefix_sub => $mh->add_prefix_sub,
457             remove_prefix_sub => $mh->remove_prefix_sub,
458             };
459 7         91 $mh->prefix($sp->{$n});
460 7         26 my $re = quotemeta($sp->{$n});
461 7         103 $mh->prefix_re(qr/^$re/);
462 7         32 $mh->check_prefix_sub(undef);
463 7         24 $mh->add_prefix_sub(undef);
464 7         23 $mh->remove_prefix_sub(undef);
465             }
466             }
467             }
468              
469 275         540 my $ep = $c->exclude_parse;
470 275         1000 my $ip = $c->include_parse;
471 275 100 100     972 if (defined($ep) && ref($ep) ne 'ARRAY') {
472 2         4 $mm->push_error("Invalid config value `exclude_parse`: must be an array");
473 2         5 return;
474             }
475 273 100 100     902 if (defined($ip) && ref($ip) ne 'ARRAY') {
476 2         6 $mm->push_error("Invalid config value `include_parse`: must be an array");
477 2         4 return;
478             }
479              
480 271         477 my $epr = $c->exclude_parse_regex;
481 271         899 my $ipr = $c->include_parse_regex;
482 271 100       906 if (defined($epr)) {
483 5         6 eval { $epr = qr/$epr/ };
  5         82  
484 5 100       14 if ($@) {
485 1         13 $mm->push_error("Invalid config value `exclude_parse_regex`: invalid regex: $@");
486 1         3 return;
487             }
488             }
489 270 100       453 if (defined($ipr)) {
490 5         7 eval { $ipr = qr/$ipr/ };
  5         63  
491 5 100       12 if ($@) {
492 1         4 $mm->push_error("Invalid config value `include_parse_regex`: invalid regex: $@");
493 1         3 return;
494             }
495             }
496              
497             # STEP 2. PREPARE LEFT HASH
498 269 100   586   1114 my $hl = $self->_gen_left ($l, $mode, sub {defined($ok) ? $_[0] ne $ok : 1}, $ep, $ip, $epr, $ipr);
  586         1801  
499 269 50       671 return if @{ $mm->errors };
  269         551  
500              
501             # STEP 3. PREPARE RIGHT HASH
502 269 100   600   2028 my $hr = $self->_gen_right($r, $mode, sub {defined($ok) ? $_[0] ne $ok : 1}, $ep, $ip, $epr, $ipr);
  600         1866  
503 269 50       624 return if @{ $mm->errors };
  269         526  
504              
505             #print "DEBUG: hl=".Data::Dumper->new([$hl])->Indent(0)->Terse(1)->Dump."\n";
506             #print "DEBUG: hr=".Data::Dumper->new([$hr])->Indent(0)->Terse(1)->Dump."\n";
507              
508 269         1551 my $em = $c->exclude_merge;
509 269         853 my $im = $c->include_merge;
510 269 100 100     1040 if (defined($em) && ref($em) ne 'ARRAY') {
511 2         7 $mm->push_error("Invalid config value `exclude_marge`: must be an array");
512 2         8 return;
513             }
514 267 100 100     572 if (defined($im) && ref($im) ne 'ARRAY') {
515 2         6 $mm->push_error("Invalid config value `include_merge`: must be an array");
516 2         7 return;
517             }
518              
519 265         493 my $emr = $c->exclude_merge_regex;
520 265         861 my $imr = $c->include_merge_regex;
521 265 100       846 if (defined($emr)) {
522 13         22 eval { $emr = qr/$emr/ };
  13         104  
523 13 100       32 if ($@) {
524 2         20 $mm->push_error("Invalid config value `exclude_merge_regex`: invalid regex: $@");
525 2         9 return;
526             }
527             }
528 263 100       452 if (defined($imr)) {
529 7         10 eval { $imr = qr/$imr/ };
  7         88  
530 7 100       19 if ($@) {
531 1         4 $mm->push_error("Invalid config value `include_merge_regex`: invalid regex: $@");
532 1         3 return;
533             }
534             }
535              
536             # STEP 4. MERGE LEFT & RIGHT
537 262         525 my ($res, $backup) = $self->_merge_gen($hl, $hr, $mode, $em, $im, $emr, $imr);
538 262 100       569 return if @{ $mm->errors };
  262         462  
539              
540             #print "DEBUG: intermediate res(5) = ".Data::Dumper->new([$res])->Indent(0)->Terse(1)->Dump."\n";
541              
542             # STEP 5. TURN BACK {key=>[MODE=>val]}, ...} INTO {(prefix)key => val, ...}
543 218 100       1179 if ($c->readd_prefix) {
544 197         596 for my $k (keys %$res) {
545 506         872 $self->_readd_prefix($res, $k, $c->default_mode);
546             }
547             } else {
548 21         155 $res->{$_} = $res->{$_}[1] for keys %$res;
549             }
550              
551 218 100       484 if ($saved_prefixes) {
552 5         13 for (keys %$saved_prefixes) {
553 7         22 my $mh = $mm->modes->{$_};
554 7         27 my $s = $saved_prefixes->{$_};
555 7         27 $mh->prefix($s->{prefix});
556 7         42 $mh->prefix_re($s->{prefix_re});
557 7         32 $mh->check_prefix_sub($s->{check_prefix_sub});
558 7         24 $mh->add_prefix_sub($s->{add_prefix_sub});
559 7         23 $mh->remove_prefix_sub($s->{remove_prefix_sub});
560             }
561             }
562              
563             # restore config
564 218 100       726 if ($config_replaced) {
565 44         66 $mm->config($orig_c);
566             #print "DEBUG: Restored config, config=", dmp($mm->config), "\n";
567             }
568              
569             #print "DEBUG: backup = ".Data::Dumper->new([$backup])->Indent(0)->Terse(1)->Dump."\n";
570             #print "DEBUG: leaving merge_H_H, result = ".dmp($res)."\n";
571 218         1175 ($key, $res, $backup);
572             }
573              
574             1;
575             # ABSTRACT: Base class for Data::ModeMerge mode handler
576              
577             __END__
578              
579             =pod
580              
581             =encoding UTF-8
582              
583             =head1 NAME
584              
585             Data::ModeMerge::Mode::Base - Base class for Data::ModeMerge mode handler
586              
587             =head1 VERSION
588              
589             This document describes version 0.360 of Data::ModeMerge::Mode::Base (from Perl distribution Data-ModeMerge), released on 2021-08-15.
590              
591             =head1 SYNOPSIS
592              
593             use Data::ModeMerge;
594              
595             =head1 DESCRIPTION
596              
597             This is the base class for mode type handlers.
598              
599             =for Pod::Coverage ^(BUILD|merge_.+)$
600              
601             =head1 ATTRIBUTES
602              
603             =head2 merger
604              
605             =head2 prefix
606              
607             =head2 prefix_re
608              
609             =head2 check_prefix_sub
610              
611             =head2 add_prefix_sub
612              
613             =head2 remove_prefix_sub
614              
615             =head1 METHODS
616              
617             =head2 name
618              
619             Return name of mode. Subclass must override this method.
620              
621             =head2 precedence_level
622              
623             Return precedence level, which is a number. The greater the number,
624             the higher the precedence. Subclass must override this method.
625              
626             =head2 default_prefix
627              
628             Return default prefix. Subclass must override this method.
629              
630             =head2 default_prefix_re
631              
632             Return default prefix regex. Subclass must override this method.
633              
634             =head2 check_prefix($hash_key)
635              
636             Return true if hash key has prefix for this mode.
637              
638             =head2 add_prefix($hash_key)
639              
640             Return hash key with added prefix of this mode.
641              
642             =head2 remove_prefix($hash_key)
643              
644             Return hash key with prefix of this mode prefix removed.
645              
646             =head1 HOMEPAGE
647              
648             Please visit the project's homepage at L<https://metacpan.org/release/Data-ModeMerge>.
649              
650             =head1 SOURCE
651              
652             Source repository is at L<https://github.com/perlancar/perl-Data-ModeMerge>.
653              
654             =head1 BUGS
655              
656             Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-ModeMerge>
657              
658             When submitting a bug or request, please include a test-file or a
659             patch to an existing test-file that illustrates the bug or desired
660             feature.
661              
662             =head1 AUTHOR
663              
664             perlancar <perlancar@cpan.org>
665              
666             =head1 COPYRIGHT AND LICENSE
667              
668             This software is copyright (c) 2021, 2016, 2015, 2013, 2012, 2011, 2010 by perlancar <perlancar@cpan.org>.
669              
670             This is free software; you can redistribute it and/or modify it under
671             the same terms as the Perl 5 programming language system itself.
672              
673             =cut