The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
Forward::Routes provides routes for framework developers.

The following feature refers to the Github version and is experimental:
https://github.com/forwardever/Forward-Routes


Forward::Routes supports the nesting of routes, which can result in better performance and maintainability.

However, as your project grows, route stuctures can quickly become confusing.

The following routes:

    my $r = Forward::Routes->new;
    my $authors = $r->add_route('/authors');

    $authors->add_route->to('Author#index');
    my $author = $authors->add_route('/:author_name');

    $author->add_route->to('Author#show');
    my $articles = $author->add_route('articles');

    $articles->add_route->to('Article#index');
    my $article = $articles->add_route('/:article_id');

    $article->add_route->to('Article#show');
    my $comments = $article->add_route('comments');

    $comments->add_route->to('Comment#index');
    $comments->add_route('/:comment_id')->to('Comment#show');

match:

    # tests
    my $m = $r->match(get => '/authors');
    is_deeply $m->[0]->params, {controller => 'Author', action => 'index'};

    $m = $r->match(get => '/authors/steven');
    is_deeply $m->[0]->params, {controller => 'Author', action => 'show', author_name => 'steven'};

    $m = $r->match(get => '/authors/steven/articles');
    is_deeply $m->[0]->params, {controller => 'Article', action => 'index', author_name => 'steven'};

    $m = $r->match(get => '/authors/steven/articles/4');
    is_deeply $m->[0]->params, {controller => 'Article', action => 'show', author_name => 'steven', article_id => 4};

    $m = $r->match(get => '/authors/steven/articles/4/comments');
    is_deeply $m->[0]->params, {controller => 'Comment', action => 'index', author_name => 'steven', article_id => 4};

    $m = $r->match(get => '/authors/steven/articles/4/comments/3');
    is_deeply $m->[0]->params, {controller => 'Comment', action => 'show', author_name => 'steven', article_id => 4, comment_id => 3};



Therefore, with two additional lines of code:

    sub new {
        ...
        my $code_ref = pop @_ if @_ && ref $_[-1] eq 'CODE';
        $code_ref->($self) if $code_ref;
        ...
    }


I have added a block syntax to the module, so the code can now also be written like this:

    my $b = Forward::Routes->new;

    $b->add_route('/authors', sub {
        my $authors = shift;

        $authors->add_route->to('Author#index');
        $authors->add_route('/:author_name', sub {
            my $author = shift;

            $author->add_route->to('Author#show');
            $author->add_route('articles', sub {
                my $articles = shift;

                $articles->add_route->to('Article#index');
                $articles->add_route('/:article_id', sub {
                    my $article = shift;

                    $article->add_route->to('Article#show');
                    $article->add_route('comments', sub {
                        my $comments = shift;

                        $comments->add_route->to('Comment#index');
                        $comments->add_route('/:comment_id')->to('Comment#show');

                    });

                });

            });

        });
    });


And in order to make it more simple, use Method::Signatures::Simple

    use Method::Signatures::Simple;

    my $ms = Forward::Routes->new;

    $ms->add_route('/authors', func($authors) {

        $authors->add_route->to('Author#index');
        $authors->add_route('/:author_name', func($author) {

            $author->add_route->to('Author#show');
            $author->add_route('articles', func($articles) {

                $articles->add_route->to('Article#index');
                $articles->add_route('/:article_id', func($article) {

                    $article->add_route->to('Article#show');
                    $article->add_route('comments', func($comments) {

                        $comments->add_route->to('Comment#index');
                        $comments->add_route('/:comment_id')->to('Comment#show');

                    });

                });

            });

        });
    });