File Coverage

blib/lib/App/Greple/xlate/Mask.pm
Criterion Covered Total %
statement 11 63 17.4
branch 0 20 0.0
condition 0 5 0.0
subroutine 4 9 44.4
pod 0 5 0.0
total 15 102 14.7


line stmt bran cond sub pod time code
1             package App::Greple::xlate::Mask;
2              
3 11     11   182 use v5.24;
  11         47  
4 11     11   67 use warnings;
  11         36  
  11         825  
5 11     11   90 use Data::Dumper;
  11         21  
  11         787  
6              
7 11     11   60 use Hash::Util qw(lock_keys);
  11         65  
  11         127  
8              
9             my %default = (
10             TAG => 'm',
11             INDEX => 'id',
12             NUMBER => 0,
13             PATTERN => [],
14             TABLE => [],
15             AUTORESET => 0,
16             );
17              
18             sub new {
19 0     0 0   my $class = shift;
20 0           my $obj = bless { %default }, $class;
21 0           lock_keys %{$obj};
  0            
22 0           $obj->configure(@_);
23 0           $obj;
24             }
25              
26             sub reset {
27 0     0 0   my $obj = shift;
28 0           $obj->{NUMBER} = 0;
29 0           $obj->{TABLE} = [];
30 0           $obj;
31             }
32              
33             sub configure {
34 0     0 0   my $obj = shift;
35 0           while (my($a, $b) = splice @_, 0, 2) {
36 0 0         if ($a eq 'pattern') {
    0          
37 0 0         my @pattern = ref $b ? @$b : $b;
38 0           push @{$obj->{PATTERN}}, @pattern;
  0            
39             }
40             elsif ($a eq 'file') {
41 0 0         open my $fh, '<:encoding(utf8)', $b or die "$b: $!\n";
42 0           my @p = map s/\\(?=\n)//gr, split /(? };
  0            
  0            
43 0           push @{$obj->{PATTERN}}, @p;
  0            
44             }
45             else {
46 0           $obj->{$a} = $b;
47             }
48             }
49             }
50              
51             sub mask {
52 0     0 0   my $obj = shift;
53 0   0       my $pattern = $obj->{PATTERN} // die;
54 0 0         my @patterns = ref $pattern ? @$pattern : $pattern;
55 0           my $fromto = $obj->{TABLE};
56             # edit parameters in place
57 0           for (@_) {
58 0           for my $pat (@patterns) {
59 0 0         next if $pat =~ /^\s*(#|$)/;
60 0           s{$pat}{
61             my $tag = sprintf("<%s %s=%d />",
62 0           $obj->{TAG}, $obj->{INDEX}, ++$obj->{NUMBER});
63 0           push @$fromto, [ $tag, ${^MATCH} ];
64 0           $tag;
65             }gpe;
66             }
67             }
68 0           return $obj;
69             }
70              
71             sub unmask {
72 0     0 0   my $obj = shift;
73 0           my @tags = map $_->[0], @{$obj->{TABLE}};
  0            
74 0           my %tags = map { $_ => 1 } @tags;
  0            
75             # edit parameters in place
76 0           for (@_) {
77 0           for my $fromto (reverse @{$obj->{TABLE}}) {
  0            
78 0           my($from, $to) = @$fromto;
79             # update the first one
80 0 0         if (my $n = s/\Q$from/$to/) {
81 0 0 0       if ($n > 1 or not exists $tags{$from}) {
82 0           warn "Masking error: \"$from\" duplicated.\n";
83             }
84 0           delete $tags{$from};
85             }
86             }
87             }
88 0 0         if (%tags) {
89 0           die sprintf("Masking error: \"%s\" missing in the output(%s).\n",
90             join('", "', keys %tags),
91             join('', @_),
92             );
93             }
94 0 0         $obj->reset if $obj->{AUTORESET};
95 0           return $obj;
96             }
97              
98             1;