Name

Forward::Routes

Description

Forward::Routes: routes for framework builders, experimental, so API might change

Features

Basic Routes

$r = Forward::Routes->new;
$r->add_route('foo/bar');

my $m = $r->match(get => 'foo/bar');
is_deeply $m->[0]->params => {};

my $m = $r->match(get => 'foo/hello');
is $m, undef;

Placeholders

$r = Forward::Routes->new;
$r->add_route(':foo/:bar');

$m = $r->match(get => 'hello/there');
is_deeply $m->[0]->params => {foo => 'hello', bar => 'there'};

Format Constraints and Detection

$r = Forward::Routes->new->format('html','xml');
$r->add_route(':foo/:bar');

$m = $r->match(get => 'hello/there.html');
is_deeply $m->[0]->params => {foo => 'hello', bar => 'there', format => 'html'};

$m = $r->match(get => 'hello/there.xml');
is_deeply $m->[0]->params => {foo => 'hello', bar => 'there', format => 'xml'};

$m = $r->match(get => 'hello/there.jpeg');
is $m, undef;

Nested Routes

$r = Forward::Routes->new;
$nested = $r->add_route(':foo');
$nested->add_route(':bar');

$m = $r->match(get => 'hello/there');
is_deeply $m->[0]->params => {foo => 'hello', bar => 'there'};

Bridges

$r = Forward::Routes->new;
my $bridge = $r->bridge('admin')->to('check#authentication');
$bridge->add_route('foo')->to('my#stuff');

$m = $r->match(get => 'admin/foo');
is_deeply $m->[0]->params, {controller => 'check', action => 'authentication'};
is_deeply $m->[1]->params, {controller => 'my', action => 'stuff'};

Defaults for action and controller params

$r = Forward::Routes->new;
$r->add_route('articles')->to('foo#bar');

$m = $r->match(get => 'articles');
is_deeply $m->[0]->params => {controller => 'foo', action => 'bar'};

Constraints

$r = Forward::Routes->new;
$r->add_route('articles/:id')->constraints(id => qr/\d+/);

$m = $r->match(get => 'articles/abc');
ok not defined $m;

$m = $r->match(get => 'articles/123');
is_deeply $m->[0]->params => {id => 123};

Grouping

$r = Forward::Routes->new;
$r->add_route('world/(:country)-(:cities)')->name('hello');

$m = $r->match(get => 'world/us-new_york');
is_deeply $m->[0]->params => {country => 'us', cities => 'new_york'};

Path Building

# build path
is $r->build_path('hello', country => 'us', cities => 'new_york')->{path},
  'world/us-new_york';

Optional Placeholders

$r = Forward::Routes->new;
$r->add_route(':year(/:month/:day)?')->name('foo');

$m = $r->match(get => '2009');
is_deeply $m->[0]->params => {year => 2009};

$m = $r->match(get => '2009/12');
ok !defined $m;

$m = $r->match(get => '2009/12/10');
is_deeply $m->[0]->params => {year => 2009, month => 12, day => 10};



$r = Forward::Routes->new;
$r->add_route('/hello/world(-:city)?')->name('foo');

$m = $r->match(get => 'hello/world');
is_deeply $m->[0]->params => {};

$m = $r->match(get => 'hello/world-paris');
is_deeply $m->[0]->params => {city => 'paris'};   

Optional Placeholders and Defaults

$r = Forward::Routes->new;
$r->add_route(':year(/:month)?/:day')->defaults(month => 1);

$m = $r->match(get => '2009');
ok not defined $m;

$m = $r->match(get => '2009/12');
is_deeply $m->[0]->params => {year => 2009, month => 1, day => 12};

$m = $r->match(get => '2009/2/3');
is_deeply $m->[0]->params => {year => 2009, month => 2, day => 3};

Method Matching

$r = Forward::Routes->new;
$r->add_route('logout')->via('get');
ok $r->match(get => 'logout');
ok !$r->match(post => 'logout');

Chaining

$r = Forward::Routes->new;
my $articles = $r->add_route('articles/:id')
  ->defaults(first_name => 'foo', last_name => 'bar')
  ->constraints(id => qr/\d+/)
  ->name('hot')
  ->to('hello#world')
  ->via('get','post');

Resources

$r = Forward::Routes->new;
$r->add_resources('users','photos','tags');

$m = $r->match(get => 'photos');
is_deeply $m->[0]->params => {controller => 'photos', action => 'index'};

$m = $r->match(get => 'photos/1');
is_deeply $m->[0]->params => {controller => 'photos', action => 'show', id => 1};

$m = $r->match(put => 'photos/1');
is_deeply $m->[0]->params => {controller => 'photos', action => 'update', id => 1};

Path Building and Resources

$r = Forward::Routes->new;
$r->add_resources('users','photos','tags');

is $r->build_path('photos_update', id => 987)->{path} => 'photos/987';

Nested Resources

$r = Forward::Routes->new;
my $magazines = $r->add_resources('magazines');
$magazines->add_resources('ads');

$m = $r->match(get => 'magazines/1/ads/4');
is_deeply $m->[0]->params =>
  {controller => 'ads', action => 'show', magazines_id => 1, ads_id => 4};

Author

ForwardEver

Copyright and License

Copyright (C) 2011, ForwardEver

This program is free software, you can redistribute it and/or modify it under the terms of the Artistic License version 2.0.

Credits

Path matching and path building inspired by Viacheslav Tykhanovskyi's Router module https://github.com/vti/router

Concept of nested routes and bridges inspired by Sebastian Riedel's Mojolicious::Routes module https://github.com/kraih/mojo/tree/master/lib/Mojolicious/Routes

Concept of restful resources inspired by Ruby on Rails