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