File Coverage

blib/lib/Regexp/Pattern.pm
Criterion Covered Total %
statement 84 85 98.8
branch 67 70 95.7
condition 4 5 80.0
subroutine 3 3 100.0
pod 1 1 100.0
total 159 164 96.9


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