File Coverage

blib/lib/Regexp/Pattern.pm
Criterion Covered Total %
statement 87 88 98.8
branch 71 74 95.9
condition 4 5 80.0
subroutine 3 3 100.0
pod 1 1 100.0
total 166 171 97.0


line stmt bran cond sub pod time code
1             package Regexp::Pattern;
2              
3             our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
4             our $DATE = '2020-04-01'; # DATE
5             our $DIST = 'Regexp-Pattern'; # DIST
6             our $VERSION = '0.2.14'; # VERSION
7              
8 1     1   65117 use strict 'subs', 'vars';
  1         10  
  1         1045  
9             #use warnings;
10              
11             sub re {
12 48     48 1 11611 my $name = shift;
13 48 100       111 my %args = ref($_[0]) eq 'HASH' ? %{$_[0]} : @_;
  41         73  
14              
15 48 50       258 my ($mod, $patname) = $name =~ /(.+)::(.+)/
16             or die "Invalid pattern name '$name', should be 'MODNAME::PATNAME'";
17              
18 48         98 $mod = "Regexp::Pattern::$mod";
19 48         138 (my $mod_pm = "$mod.pm") =~ s!::!/!g;
20 48         555 require $mod_pm;
21              
22 48         59 my $var = \%{"$mod\::RE"};
  48         155  
23              
24 48 100       116 exists($var->{$patname})
25             or die "No regexp pattern named '$patname' in package '$mod'";
26              
27 47         51 my $pat;
28 47 100       100 if ($var->{$patname}{pat}) {
    50          
29 34         47 $pat = $var->{$patname}{pat};
30             } elsif ($var->{$patname}{gen}) {
31 13         42 $pat = $var->{$patname}{gen}->(%args);
32             } else {
33 0         0 die "Bug in module '$mod': pattern '$patname': no pat/gen declared";
34             }
35              
36 47 100       87 if ($args{-anchor}) {
37 3 100       11 if ($args{-anchor} eq 'left') {
    100          
38 1         20 $pat = qr/\A(?:$pat)/;
39             } elsif ($args{-anchor} eq 'right') {
40 1         17 $pat = qr/(?:$pat)\z/;
41             } else {
42 1         47 $pat = qr/\A(?:$pat)\z/;
43             }
44             }
45              
46 47         94 return $pat;
47             }
48              
49             sub import {
50 24     24   25212 my $package = shift;
51              
52 24         66 my $caller = caller();
53              
54 24         451 my @args = @_;
55 24 50       53 @args = ('re') unless @args;
56              
57 24         47 while (@args) {
58 25         40 my $arg = shift @args;
59 25         38 my ($mod, $name0, $as, $prefix, $suffix,
60             $has_tag, $lacks_tag, $has_tag_matching, $lacks_tag_matching, $gen_args);
61 25 100       188 if ($arg eq 're') {
    100          
62 1         2 *{"$caller\::re"} = \&re;
  1         4  
63 1         4 next;
64             } elsif ($arg =~ /\A(\w+(?:::\w+)*)::(\w+|\*)\z/) {
65 22         67 ($mod, $name0) = ($1, $2);
66 22         44 ($as, $prefix, $suffix, $has_tag, $lacks_tag, $has_tag_matching, $lacks_tag_matching) =
67             (undef, undef, undef, undef, undef);
68 22         31 $gen_args = {};
69 22   66     110 while (@args >= 2 && $args[0] =~ /\A-?\w+\z/) {
70 20         50 my ($k, $v) = splice @args, 0, 2;
71 20 100       76 if ($k eq '-as') {
    100          
    100          
    100          
    100          
    100          
    100          
    100          
72 3 100       17 die "Cannot use -as on a wildcard import '$arg'"
73             if $name0 eq '*';
74 2 100       14 die "Please use a simple identifier for value of -as"
75             unless $v =~ /\A\w+\z/;
76 1         3 $as = $v;
77             } elsif ($k eq '-prefix') {
78 3         10 $prefix = $v;
79             } elsif ($k eq '-suffix') {
80 2         6 $suffix = $v;
81             } elsif ($k eq '-has_tag') {
82 4         12 $has_tag = $v;
83             } elsif ($k eq '-lacks_tag') {
84 2         5 $lacks_tag = $v;
85             } elsif ($k eq '-has_tag_matching') {
86 2 100       55 $has_tag_matching = ref $v eq 'Regexp' ? $v : qr/$v/;
87             } elsif ($k eq '-lacks_tag_matching') {
88 2 100       21 $lacks_tag_matching = ref $v eq 'Regexp' ? $v : qr/$v/;
89             } elsif ($k !~ /\A-/) {
90 1         5 $gen_args->{$k} = $v;
91             } else {
92 1         12 die "Unknown import option '$k'";
93             }
94             }
95             } else {
96 2         27 die "Invalid import '$arg', either specify 're' or a qualified ".
97             "pattern name e.g. 'Foo::bar', which can be followed by ".
98             "name-value pairs";
99             }
100              
101 19         21 *{"$caller\::RE"} = \%{"$caller\::RE"};
  19         40  
  19         47  
102              
103 19         24 my @names;
104 19 100       38 if ($name0 eq '*') {
105 12         23 my $mod = "Regexp::Pattern::$mod";
106 12         47 (my $mod_pm = "$mod.pm") =~ s!::!/!g;
107 12         64 require $mod_pm;
108 12         20 my $var = \%{"$mod\::RE"};
  12         30  
109 12         62 for my $n (sort keys %$var) {
110 60   100     133 my $tags = $var->{$n}{tags} || [];
111 60 100       87 if (defined $has_tag) {
112 20 100       67 next unless grep { $_ eq $has_tag } @$tags;
  28         56  
113             }
114 45 100       66 if (defined $lacks_tag) {
115 7 100       12 next if grep { $_ eq $lacks_tag } @$tags;
  11         47  
116             }
117 43 100       59 if (defined $has_tag_matching) {
118 10 100       18 next unless grep { $_ =~ $has_tag_matching } @$tags;
  14         52  
119             }
120 37 100       55 if (defined $lacks_tag_matching) {
121 7 100       10 next if grep { $_ =~ $lacks_tag_matching } @$tags;
  11         33  
122             }
123 34         50 push @names, $n;
124             }
125 12 100       30 unless (@names) {
126 1         39 warn "No patterns imported in wildcard import '$mod\::*'";
127             }
128             } else {
129 7         14 @names = ($name0);
130             }
131 19         38 for my $n (@names) {
132 41 100       231 my $name = defined($as) ? $as :
    100          
    100          
133             (defined $prefix ? $prefix : "") . $n .
134             (defined $suffix ? $suffix : "");
135 41 100       49 if (exists ${"$caller\::RE"}{$name}) {
  41         90  
136 1         58 warn "Overwriting pattern '$name' by importing '$mod\::$n'";
137             }
138 41         95 ${"$caller\::RE"}{$name} = re("$mod\::$n", $gen_args);
  41         2799  
139             }
140             }
141             }
142              
143             1;
144             # ABSTRACT: Convention/framework for modules that contain collection of regexes
145              
146             __END__