NAME
URI::Dispatch - determine which code to execute based upon path
SYNOPSIS
my $dispatch = URI::Dispatch->new();
$dispatch->add( '/', 'Homepage' );
# common matching patterns are available
$dispatch->add( '/user/#id', 'Profile' );
# optional parts of the path
$dispatch->add( '/article/#id[/#slug]', 'Article' );
# named captures
$dispatch->add( '/tag/#name:slug', 'Tag' );
# use a custom regexp
$dispatch->add( '/a-z/#letter:([a-z])', 'AZ::Page' );
# pass in a path and determine what matches
my( $handler, $options)
= $dispatch->handler( '/article/5/awesome-article' );
# handler='Article', options=['5','awesome-article']
# automatically calls Tag::get (as that matches the path)
my $response = $dispatch->dispatch( '/tag/perl' );
# construct paths
my $uri = $dispatch->url( 'article', [ '1', 'some-article' ] );
# uri='/article/1/some-article'
METHODS
add( path, handler )
Add path that can be handled by handler. The $path string will be matched literally, except for the special markers described below. They have been specially chosen because they are not legal URI path characters, so should never break your actual chosen URI scheme.
- captures
-
To capture part of the path for later use, mark it with a hash (#) and the capture type. Builtin types are:
- id
-
matches digits
- hex
-
matches digits and the letters a, b, c, d, e, and f case insensitively
- slug
-
matches lowercase letters, digits and hyphens
- year
-
matches four digits
- month
-
matches numbers 01 through 12
- day
-
matches numbers 01 through 31
- date
-
matches year, month and day separated by dashes
- hour
-
matches numbers 00 through 23
- minute
-
matches numbers 00 through 59
- second
-
matches numbers 00 through 59
- time
-
matches hour, minute and second separated by any of colons, periods or dashes
- *
-
matches anything
- (regexp)
-
matches a custom regular expression
- named captures
-
Rather than relying on the order of the captures, they can be named. The name goes immediately after the hash (#), is formed of "word" characters (alphanumeric plus underscore) and is followed by a colon and then the capture type. Some examples:
#id:id
#title:slug
#letter:([a-z])
- optional segments
-
To mark part of the path as optional, surround it with square brackets. Optional segments cannot be nested.
Limitations
Adding a new path with the same handler will overwrite the previous path.
Different handlers having the same path will result in unpredictable behaviour.
handler( path )
Determine which handler should be used for the given path.
Returns the handler string, and either an array of the captured elements, or a hash if the captures were named. For example, this code:
$dispatch->add( '/article/#key:id/#title:slug', 'article' );
my( $handler, $captures )
= $dispatch->handler( '/article/5/awesome-article' );
would return $captures
set to:
{
key => '5',
title => 'awesome-article',
}
dispatch( path or request, [ ... ] )
Call the handler that matches the given argument, which can either be a simple string that represents a path, or it can be a Plack::Request object.
The handler is interpreted as a class, and the HTTP method is the subroutine within the class to call.
Any extra arguments to dispatch()
are passed to the handler routine first, then the reference to the array of captures or hash of named captures.
path string
When dispatch()
is called with a simple string, the method is assumed to be an HTTP GET. For example:
$dispatch->add( '/tag/#name:slug', 'Tags::SingleTag' );
my $response = $dispatch->dispatch( '/tag/perl', $obj );
would set $response
to the return value of
Tags::SingleTag::get( $obj, { name => 'perl' } );
Plack::Request
When dispatch()
is called with a Plack::Request object, the path and method are determined automatically; and the object is passed to the handler before the captures, but after any extra arguments to dispatch(). For example:
$dispatch->add( '/tag/#name:slug', 'Tags::SingleTag' );
# $env contains the environment of an HTTP DELETE
# request on /tag/perl
my $request = Plack::Request->new( $env );
my $response = $dispatch->dispatch( $request, $obj );
would set $response
to the return value of
Tags::SingleTag::delete( $obj, $request, { name => 'perl' } );
url( handler, $arguments )
Build a path that handler would accept. If the path contains captures, you can pass them as an arrayref (or hashref if they are named captures).
The $arguments are tested to ensure they would match. If they would not, an Ouch exception is thrown. This can be caught in your code like so:
use Ouch qw( :traditional );
...
$dispatch->add( '/list/#letter:([a-z])', 'az-page' );
try { $url = $dispatch->url( 'az-page', 'too big' ); };
if ( catch 'wrong_input' ) {
# handle errors
}
EXCEPTIONS
- cannot_mix
-
Named and positional captures cannot be mixed. An attempt to do so will throw this exception.
- unmatched_brackets
-
Thrown if the opening and closing square brackets representing optional segments of a path do not match up.
- wrong_input
-
A provided argument when calling url() will not match the relevant capture type.
- args_short
-
Not enough arguments are provided when calling url().
- args_wrong
-
The wrong type of arguments (arrayref versus hashref) were provided when calling url().
- no_param
-
An unknown builtin parameter type was requested.
AUTHOR
Mark Norman Francis, norm@cackhanded.net.
COPYRIGHT AND LICENSE
Copyright 2011 Mark Norman Francis.
This program is free software, you can redistribute it and/or modify it under the terms of the Artistic License version 2.0.