This file is indexed.

/usr/share/perl5/Catalyst/RouteMatching.pod is in libcatalyst-perl 5.90115-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
=encoding UTF-8

=head1 Name

Catalyst::RouteMatching - How Catalyst maps an incoming URL to actions in controllers.

=head1 Description

This is a WIP document intended to help people understand the logic that L<Catalyst>
uses to determine how to match in incoming request to an action (or action chain)
in a controller.

=head2 Request to Controller/Action Matching

L<Catalyst> maps requests to action using a 'longest path wins' approach.  That means
that if the request is '/foo/bar/baz' That means the action 'baz' matches:

    package MyApp::Controller::Foo;

    use Moose;
    use MooseX::MethodAttributes

    extends 'Catalyst::Controller';

    sub bar :Path('bar') Args(1) { ...}
    sub baz :Path('bar/baz') Args(0) { ... }

Path length matches take precedence over all other types of matches (included HTTP
Method, Scheme, etc.).  The same holds true for Chained actions.  Generally the
chain that matches the most PathParts wins.

=head2 Args(N) versus Args

'Args' matches any number of args.  Because this functions as a sort of catchall, we
treat 'Args' as the lowest precedence of any Args(N) when N is 0 to infinity.  An
action with 'Args' always get the last chance to match.

=head2 When two or more actions match a given Path

Sometimes two or more actions match the same path and all have the same PathPart
length.  For example:

    package MyApp::Controller::Root;

    use Moose;
    use MooseX::MethodAttributes

    extends 'Catalyst::Controller';

    sub root :Chained(/) CaptureArgs(0) { }

      sub one :Chained(root) PathPart('') Args(0) { }
      sub two :Chained(root) PathPart('') Args(0) { }
      sub three :Chained(root) PathPart('') Args(0) { }

    __PACKAGE__->meta->make_immutable;

In this case the last defined action wins (for the example that is action 'three').

This is most common to happen when you are using action matching beyond paths, such as
when using method matching:

    package MyApp::Controller::Root;

    use Moose;
    use MooseX::MethodAttributes

    extends 'Catalyst::Controller';

    sub root :Chained(/) CaptureArgs(0) { }

      sub any :Chained(root) PathPart('') Args(0) { }
      sub get :GET Chained(root) PathPart('') Args(0) { }

    __PACKAGE__->meta->make_immutable;

In the above example GET /root could match both actions.  In this case you should define
your 'catchall' actions higher in the controller.

=head2 Type Constraints in Args and Capture Args

Beginning in Version 5.90090+ you may use L<Moose>, L<MooseX::Types> or L<Type::Tiny>
type constraints to further declare allowed matching for Args or CaptureArgs.  Here
is a simple example:

    package MyApp::Controller::User;

    use Moose;
    use MooseX::MethodAttributes;
    use MooseX::Types::Moose qw(Int);

    extends 'Catalyst::Controller';

    sub find :Path('') Args(Int) {
      my ($self, $c, $int) = @_;
    }

    __PACKAGE__->meta->make_immutable;

In this case the incoming request "http://localhost:/user/100" would match the action
C<find> but "http://localhost:/user/not_a_number" would not. You may find declaring
constraints in this manner aids with debugging, automatic generation of documentation
and reducing the amount of manual checking you might need to do in your actions.  For
example if the argument in the given action was going to be used to lookup a row
in a database, if the matching field expected an integer, a string might cause a database
exception, prompting you to add additional checking of the argument prior to using it.
In general it is hoped this feature can lead to reduced validation boilerplate and more
easily understood and declarative actions.

More than one argument may be added by comma separating your type constraint names, for
example:

    use Types::Standard qw/Int Str/;

    sub find :Path('') Args(Int,Int,Str) {
      my ($self, $c, $int1, $int2, $str) = @_;
    }

Would require three arguments, an integer, integer and a string.  Note in this example we
constrained the args using imported types via L<Types::Standard>.  Although you may use
stringy Moose types, we recommend imported types since this is less ambiguous to your readers.
If you want to use Moose stringy types. you must quote them (either "Int" or 'Int' is fine).

Conversely, you should not quote types that are imported!

=head3 Using type constraints in a controller

By default L<Catalyst> allows all the standard, built-in, named type constraints that come
bundled with L<Moose>.  However it is trivial to create your own Type constraint libraries
and export them to a controller that wishes to use them.  We recommend using L<Type::Tiny> or
L<MooseX::Types> for this.  Here is an example using some extended type constraints via
the L<Types::Standard> library that is packaged with L<Type::Tiny>:

    package MyApp::Controller::User;

    use Moose;
    use MooseX::MethodAttributes;
    use Types::Standard qw/StrMatch Int/;
    
    extends 'Catalyst::Controller';

    sub looks_like_a_date :Path('') Args(StrMatch[qr{\d\d-\d\d-\d\d}]) {
      my ($self, $c, $int) = @_;
    }

    __PACKAGE__->meta->make_immutable;

This would match URLs like "http://localhost/user/11-11-2015" for example.  If you've been
missing the old RegExp matching, this can emulate a good chunk of that ability, and more.

A tutorial on how to make custom type libraries is outside the scope of this document.  I'd
recommend looking at the copious documentation in L<Type::Tiny> or in L<MooseX::Types> if
you prefer that system.  The author recommends L<Type::Tiny> if you are unsure which to use.

=head3 Type constraint namespace.

By default we assume the namespace which defines the type constraint is in the package
which contains the action declaring the arg or capture arg.  However if you do not wish
to import type constraints into you package, you may use a fully qualified namespace for
your type constraint.  If you do this you must install L<Type::Tiny> which defines the
code used to lookup and normalize the various types of Type constraint libraries.

Example:

    package MyApp::Example;

    use Moose;
    use MooseX::MethodAttributes;

    extends 'Catalyst::Controller';

    sub an_int_ns :Local Args(MyApp::Types::Int) {
      my ($self, $c, $int) = @_;
      $c->res->body('an_int (withrole)');
    }

Would basically work the same as:

    package MyApp::Example;

    use Moose;
    use MooseX::MethodAttributes;
    use MyApp::Types 'Int';

    extends 'Catalyst::Controller';

    sub an_int_ns :Local Args(Int) {
      my ($self, $c, $int) = @_;
      $c->res->body('an_int (withrole)');
    }

=head3 namespace::autoclean

If you want to use L<namespace::autoclean> in your controllers you must 'except' imported
type constraints since the code that resolves type constraints in args / capture args
run after the cleaning.  For example:

    package MyApp::Controller::Autoclean;

    use Moose;
    use MooseX::MethodAttributes;
    use namespace::autoclean -except => 'Int';
    use MyApp::Types qw/Int/;

    extends 'Catalyst::Controller';

    sub an_int :Local Args(Int) {
      my ($self, $c, $int) = @_;
      $c->res->body('an_int (autoclean)');
    }

=head3 Using roles and base controller with type constraints

If your controller is using a base class or a role that has an action with a type constraint
you should declare your use of the type constraint in that role or base controller in the
same way as you do in main controllers.  Catalyst will try to find the package with declares
the type constraint first by looking in any roles and then in superclasses.  It will use the
first package that defines the type constraint.  For example:

    package MyApp::Role;

    use Moose::Role;
    use MooseX::MethodAttributes::Role;
    use MyApp::Types qw/Int/;

    sub an_int :Local Args(Int) {
      my ($self, $c, $int) = @_;
      $c->res->body('an_int (withrole)');
    }

    sub an_int_ns :Local Args(MyApp::Types::Int) {
      my ($self, $c, $int) = @_;
      $c->res->body('an_int (withrole)');
    }

    package MyApp::BaseController;

    use Moose;
    use MooseX::MethodAttributes;
    use MyApp::Types qw/Int/;

    extends 'Catalyst::Controller';

    sub from_parent :Local Args(Int) {
      my ($self, $c, $id) = @_;
      $c->res->body('from_parent $id');
    }

    package MyApp::Controller::WithRole;

    use Moose;
    use MooseX::MethodAttributes;

    extends 'MyApp::BaseController';

    with 'MyApp::Role';

If you have complex controller hierarchy, we
do not at this time attempt to look for all packages with a match type constraint, but instead
take the first one found.  In the future we may add code that attempts to insure a sane use
of subclasses with type constraints but right now there are no clear use cases so report issues
and interests.

=head3 Match order when more than one Action matches a path.

As previously described, L<Catalyst> will match 'the longest path', which generally means
that named path / path_parts will take precedence over Args or CaptureArgs.  However, what
will happen if two actions match the same path with equal args?  For example:

    sub an_int :Path(user) Args(Int) {
    }

    sub an_any :Path(user) Args(1) {
    }

In this case L<Catalyst> will check actions starting from the LAST one defined.  Generally
this means you should put your most specific action rules LAST and your 'catch-alls' first.
In the above example, since Args(1) will match any argument, you will find that that 'an_int'
action NEVER gets hit.  You would need to reverse the order:

    sub an_any :Path(user) Args(1) {
    }

    sub an_int :Path(user) Args(Int) {
    }

Now requests that match this path would first hit the 'an_int' action and will check to see if
the argument is an integer.  If it is, then the action will execute, otherwise it will pass and
the dispatcher will check the next matching action (in this case we fall through to the 'an_any'
action).

=head3 Type Constraints and Chained Actions

Using type constraints in Chained actions works the same as it does for Path and Local or Global
actions.  The only difference is that you may declare type constraints on CaptureArgs as
well as Args.  For Example:

  use Types::Standard qw/Int Tuple/;
  
  sub chain_base :Chained(/) CaptureArgs(1) { }

    sub any_priority_chain :GET Chained(chain_base) PathPart('') Args(1) {  }

    sub int_priority_chain :Chained(chain_base) PathPart('') Args(Int) {  }

    sub link_any :Chained(chain_base) PathPart('') CaptureArgs(1) { }

      sub any_priority_link_any :Chained(link_any) PathPart('') Args(1) {  }

      sub int_priority_link_any :Chained(link_any) PathPart('') Args(Int) {  }
    
    sub link_int :Chained(chain_base) PathPart('') CaptureArgs(Int) { }

      sub any_priority_link :Chained(link_int) PathPart('') Args(1) {  }

      sub int_priority_link :Chained(link_int) PathPart('') Args(Int) {  }

    sub link_int_int :Chained(chain_base) PathPart('') CaptureArgs(Int,Int) { }

      sub any_priority_link2 :Chained(link_int_int) PathPart('') Args(1) {  }

      sub int_priority_link2 :Chained(link_int_int) PathPart('') Args(Int) {  }

    sub link_tuple :Chained(chain_base) PathPart('') CaptureArgs(Tuple[Int,Int,Int]) { }

      sub any_priority_link3 :Chained(link_tuple) PathPart('') Args(1) {  }

      sub int_priority_link3 :Chained(link_tuple) PathPart('') Args(Int) {  }

These chained actions might create match tables like the following:

    [debug] Loaded Chained actions:
    .-------------------------------------+--------------------------------------.
    | Path Spec                           | Private                              |
    +-------------------------------------+--------------------------------------+
    | /chain_base/*/*                     | /chain_base (1)                      |
    |                                     | => GET /any_priority_chain (1)       |
    | /chain_base/*/*/*                   | /chain_base (1)                      |
    |                                     | -> /link_int (Int)                   |
    |                                     | => /any_priority_link (1)            |
    | /chain_base/*/*/*/*                 | /chain_base (1)                      |
    |                                     | -> /link_int_int (Int,Int)           |
    |                                     | => /any_priority_link2 (1)           |
    | /chain_base/*/*/*/*/*               | /chain_base (1)                      |
    |                                     | -> /link_tuple (Tuple[Int,Int,Int])  |
    |                                     | => /any_priority_link3 (1)           |
    | /chain_base/*/*/*                   | /chain_base (1)                      |
    |                                     | -> /link_any (1)                     |
    |                                     | => /any_priority_link_any (1)        |
    | /chain_base/*/*/*/*/*/*             | /chain_base (1)                      |
    |                                     | -> /link_tuple (Tuple[Int,Int,Int])  |
    |                                     | -> /link2_int (UserId)               |
    |                                     | => GET /finally (Int)                |
    | /chain_base/*/*/*/*/*/...           | /chain_base (1)                      |
    |                                     | -> /link_tuple (Tuple[Int,Int,Int])  |
    |                                     | -> /link2_int (UserId)               |
    |                                     | => GET /finally2 (...)               |
    | /chain_base/*/*                     | /chain_base (1)                      |
    |                                     | => /int_priority_chain (Int)         |
    | /chain_base/*/*/*                   | /chain_base (1)                      |
    |                                     | -> /link_int (Int)                   |
    |                                     | => /int_priority_link (Int)          |
    | /chain_base/*/*/*/*                 | /chain_base (1)                      |
    |                                     | -> /link_int_int (Int,Int)           |
    |                                     | => /int_priority_link2 (Int)         |
    | /chain_base/*/*/*/*/*               | /chain_base (1)                      |
    |                                     | -> /link_tuple (Tuple[Int,Int,Int])  |
    |                                     | => /int_priority_link3 (Int)         |
    | /chain_base/*/*/*                   | /chain_base (1)                      |
    |                                     | -> /link_any (1)                     |
    |                                     | => /int_priority_link_any (Int)      |
    '-------------------------------------+--------------------------------------'

As you can see the same general path could be matched by various action chains.  In this case
the rule described in the previous section should be followed, which is that L<Catalyst>
will start with the last defined action and work upward.  For example the action C<int_priority_chain>
would be checked before C<any_priority_chain>.  The same applies for actions that are midway links
in a longer chain.  In this case C<link_int> would be checked before C<link_any>.  So as always we
recommend that you place you priority or most constrained actions last and you least or catch-all
actions first.

Although this reverse order checking may seen counter intuitive it does have the added benefit that
when inheriting controllers any new actions added would take check precedence over those in your
parent controller or consumed role.

Please note that your declared type constraint names will now appear in the debug console.

=head1 Author

John Napiorkowski L<jjnapiork@cpan.org|email:jjnapiork@cpan.org>

=cut