File Coverage

blib/lib/Catalyst/DispatchType/Regex.pm
Criterion Covered Total %
statement 66 77 85.7
branch 19 26 73.0
condition n/a
subroutine 11 12 91.6
pod 5 5 100.0
total 101 120 84.1


line stmt bran cond sub pod time code
1             package Catalyst::DispatchType::Regex;
2              
3 4     4   3452404 use Moose;
  4         7  
  4         32  
4             extends 'Catalyst::DispatchType::Path';
5              
6 4     4   18940 use Text::SimpleTable;
  4         9  
  4         70  
7 4     4   22 use Catalyst::Utils;
  4         4  
  4         73  
8 4     4   2538 use Text::Balanced ();
  4         28400  
  4         235  
9              
10             has _compiled => (
11             is => 'rw',
12             isa => 'ArrayRef',
13             required => 1,
14             default => sub{ [] },
15             );
16             has _attr => (
17             is => 'ro',
18             isa => 'Str',
19             required => 1,
20             default => 'Regex',
21             );
22 4     4   30 no Moose;
  4         4  
  4         31  
23              
24             # Version needs to be in a format such that $VERSION gt '5.90020' => true
25             # We use in Catalyst::Dispatcher ($VERSION le '5.90020')
26             our $VERSION = '5.90035';
27              
28             =head1 NAME
29              
30             Catalyst::DispatchType::Regex - Regex DispatchType
31              
32             =for html
33             <a href="https://travis-ci.org/mvgrimes/catalyst-dispatch-regex"><img src="https://travis-ci.org/mvgrimes/catalyst-dispatch-regex.svg?branch=master" alt="Build Status"></a>
34              
35             =head1 SYNOPSIS
36              
37             See L<Catalyst::DispatchType>.
38              
39             =head1 DESCRIPTION
40              
41             B<Status: Deprecated.> Regex dispatch types have been deprecated and removed
42             from Catalyst core. It is recommend that you use Chained methods or other
43             techniques instead. As part of the refactoring, the dispatch priority of
44             Regex vs Regexp vs LocalRegex vs LocalRegexp may have changed. Priority is now
45             influenced by when the dispatch type is first seen in your application.
46              
47             When loaded, a warning about the deprecation will be printed to STDERR. To
48             suppress the warning set the CATALYST_NOWARN_DEPRECATE environment variable to
49             a true value.
50              
51             Dispatch type managing path-matching behaviour using regexes. For
52             more information on dispatch types, see:
53              
54             =over 4
55              
56             =item * L<Catalyst::Manual::Intro> for how they affect application authors
57              
58             =item * L<Catalyst::DispatchType> for implementation information.
59              
60             =back
61              
62             =head1 METHODS
63              
64             =head2 $self->list($c)
65              
66             Output a table of all regex actions, and their private equivalent.
67              
68             =cut
69              
70             sub list {
71 0     0 1 0 my ( $self, $c ) = @_;
72 0         0 my $avail_width = Catalyst::Utils::term_width() - 9;
73 0 0       0 my $col1_width = ($avail_width * .50) < 35 ? 35 : int($avail_width * .50);
74 0         0 my $col2_width = $avail_width - $col1_width;
75 0         0 my $re = Text::SimpleTable->new(
76             [ $col1_width, $self->_attr ], [ $col2_width, 'Private' ]
77             );
78 0         0 for my $regex ( @{ $self->_compiled } ) {
  0         0  
79 0         0 my $action = $regex->{action};
80 0         0 $re->row( $regex->{path}, "/$action" );
81             }
82 0         0 $c->log->debug( "Loaded Regex actions:\n" . $re->draw . "\n" )
83 0 0       0 if ( @{ $self->_compiled } );
84             }
85              
86             =head2 $self->match( $c, $path )
87              
88             Checks path against every compiled regex, and offers the action for any regex
89             which matches a chance to match the request. If it succeeds, sets action,
90             match and captures on $c->req and returns 1. If not, returns 0 without
91             altering $c.
92              
93             =cut
94              
95             sub match {
96 12     12 1 119251 my ( $self, $c, $path ) = @_;
97              
98             # Check path against plain text first
99 12 50       37 return if $self->SUPER::match( $c, $path );
100              
101 12         405 foreach my $compiled ( @{ $self->_compiled } ) {
  12         316  
102 52 100       187 if ( my @captures = ( $path =~ $compiled->{re} ) ) {
103 5 50       23 next unless $compiled->{action}->match($c);
104 5         154 $c->req->action( $compiled->{path} );
105 5         222 $c->req->match($path);
106 5         203 $c->req->captures( \@captures );
107 5         286 $c->action( $compiled->{action} );
108 5         119 $c->namespace( $compiled->{action}->namespace );
109 5         144 return 1;
110             }
111             }
112              
113 7         13 return 0;
114             }
115              
116             =head2 $self->register( $c, $action )
117              
118             Registers one or more regex actions for an action object.
119             Also registers them as literal paths.
120              
121             Returns 1 if any regexps were registered.
122              
123             =cut
124              
125             sub register {
126 238     238 1 89715 my ( $self, $c, $action ) = @_;
127              
128 238         423 $self->_display_deprecation_warning;
129              
130 238         416 my @register = $self->_get_attributes( $c, $action );
131              
132 238         286 foreach my $r (@register) {
133 39         133 $self->register_path( $c, $r, $action );
134 39         5698 $self->register_regex( $c, $r, $action );
135             }
136              
137 238 100       391 return 1 if @register;
138 199         277 return 0;
139             }
140              
141             sub _get_attributes {
142 238     238   189 my ($self, $c, $action) = @_;
143 238         5232 my $attrs = $action->attributes;
144 238         7139 my $attr = $self->_attr;
145 238 100       344 return @{ $attrs->{$attr} || [] };
  238         901  
146             }
147              
148             =head2 $self->register_regex($c, $re, $action)
149              
150             Register an individual regex on the action. Usually called from the
151             register method.
152              
153             =cut
154              
155             sub register_regex {
156 39     39 1 50 my ( $self, $c, $re, $action ) = @_;
157 39         1181 push(
158 39         36 @{ $self->_compiled }, # and compiled regex for us
159             {
160             re => qr#$re#,
161             action => $action,
162             path => $re,
163             }
164             );
165             }
166              
167             =head2 $self->uri_for_action($action, $captures)
168              
169             returns a URI for this action if it can find a regex attributes that contains
170             the correct number of () captures. Note that this may function incorrectly
171             in the case of nested captures - if your regex does (...(..))..(..) you'll
172             need to pass the first and third captures only.
173              
174             =cut
175              
176             sub uri_for_action {
177 23     23 1 15244 my ( $self, $action, $captures ) = @_;
178              
179 23         678 my $attr = $self->_attr;
180 23 100       465 if (my $regexes = $action->attributes->{$attr}) {
181 8         44 REGEX: foreach my $orig (@$regexes) {
182 8         12 my $re = "$orig";
183 8         19 $re =~ s/^\^//;
184 8         19 $re =~ s/\$$//;
185 8         29 $re =~ s/\\([^\\])/$1/g;
186 8         10 my $final = '/';
187 8         11 my @captures = @$captures;
188 8         93 while (my ($front, $rest) = split(/\(/, $re, 2)) {
189 17 100       30 last unless defined $rest;
190 14         34 ($rest, $re) =
191             Text::Balanced::extract_bracketed("(${rest}", '(');
192 14 100       1078 next REGEX unless @captures;
193 12         119 $final .= $front.shift(@captures);
194             }
195 6         9 $final .= $re;
196 6 100       34 next REGEX if @captures;
197 4         25 return $final;
198             }
199             }
200 19         78 return undef;
201             }
202              
203             {
204             my $deprecation_warning_displayed = 0;
205              
206             sub _display_deprecation_warning {
207 238 100   238   412 return if $deprecation_warning_displayed++;
208 3 50       8 return if $ENV{CATALYST_NOWARN_DEPRECATE};
209              
210 3         280 warn "DEPRECATION WARNING: The Regex dispatch type is deprecated.\n"
211             . " It is recommended that you convert Regex and LocalRegex \n"
212             . " methods to Chained methods.";
213             }
214              
215             }
216              
217             =head1 AUTHORS
218              
219             Catalyst Contributors, see Catalyst.pm
220              
221             =head1 COPYRIGHT
222              
223             This library is free software. You can redistribute it and/or modify it under
224             the same terms as Perl itself.
225              
226             =cut
227              
228             __PACKAGE__->meta->make_immutable;
229              
230             1;