NAME

Gears::Router - Pattern matching system

SYNOPSIS

use My::Gears::Router;

my $router = My::Gears::Router->new;

# Add locations with patterns
$router->add('/user/:id', { code => sub { ... } });
$router->add('/blog/*path', { code => sub { ... } });

# Match against a path
my @matches = $router->match('/user/123');

# Flat match returns all matches in a flat list
my @flat = $router->flat_match('/blog/2025/01/post');

# Clear all locations
$router->clear;

DESCRIPTION

Gears::Router is the main routing component that manages URL pattern matching. It serves as the root of a routing tree structure and maintains a collection of locations (patterns) that can be matched against incoming paths.

The router supports hierarchical matching where locations can have child locations (bridges), allowing for nested route structures. Bridges are matched even if there are no matching routes underneath them, and routes are always matched in the order of declaration and nesting.

EXTENDING

This router is abstract and very basic by design. A subclass of it must be created, and it must implement the _build_location method. Some example location implementations are included in the Gears::Router::Location:: namespace.

Take a look at Gears::Router::Location::SigilMatch, which implements a similar placeholders system to Kelp. You may want to create a subclass of it as well, so that the location contains any useful data. Locations included with Gears do not make any assumptions about what kind of data you want to hold in them.

Here is how a minimal working router subclass could be implemented:

package My::Gears::Router;

use v5.40;
use Mooish::Base -standard;
use My::Gears::Router::Location;

extends 'Gears::Router';

# "%args" will contain everything that was passed to a "add" call as the
# second argument, but may contain additional keys which are needed for
# internal bookkeeping:
#
# $router->add($pattern => { %args })

sub _build_location ($self, %args)
{
	return My::Gears::Router::Location->new(%args);
}

Here is how a minimal location subclass could be implemented, extending Gears::Router::Location::SigilMatch and adding a mandatory code reference to it:

package My::Gears::Router::Location;

use v5.40;
use Mooish::Base -standard;

extends 'Gears::Router::Location::SigilMatch';

# - "param" marks mandatory constructor argument
# - use "option" instead to mark optional ones
# - "CodeRef" is a Type::Tiny type (optional)

has param 'code' => (
	isa => CodeRef,
);

The router implementation above can be used as shown in "SYNOPSIS".

INTERFACE

Attributes

locations

An array reference of Gears::Router::Location objects representing the registered route patterns.

Not available in constructor

Methods

new

$object = $class->new(%args)

A standard Mooish constructor. Consult "Attributes" section to learn what keys can key passed in %args.

pattern

$str = $router->pattern()

Returns the pattern string for this router. Since this is the root router, it always returns an empty string.

add

$location = $router->add($pattern, $data = {})

Adds a new location with the specified pattern to the router. The $pattern is a string that may contain placeholders, but the exact behavior depends on the used Gears::Router::Location implementation. The optional $data hash reference contains additional metadata for the location.

Returns the newly created Gears::Router::Location object. Since locations share some common interface with the router, "add" can be called again on the resulted location. It is a preferred way of structuring routes in the application.

match

@matches = $router->match($path)

Matches the given path string against all registered locations. Returns a nested array structure where matches that have child locations (bridges) are represented as array references containing the parent match as the first element, and its children's matches as subsequent elements. Each match is a Gears::Router::Match object.

Since Gears make no assumptions about the intended use of the router, matching does not stop at first non-bridge hit. This means the matching performance is stable at O(n), n being the number of routes. That additional cost may be alleviated by organizing routes under bridges. If the bridge does not match, its children will not be checked at all, so the application is rewarded for having a well-organized routing tree. If required, rewriting matching to stop at first hit should be easy enough.

flat_match

@matches = $router->flat_match($path)

Similar to "match", but returns all matches in a flat list instead of a nested structure. Matches should be processed from index 0 up. With this structure, there is no way to tell which matches were part of which bridges without inspecting the router locations manually.

This is useful when you want to process all matching locations without dealing with the hierarchical structure. Alternatively, "flatten" can be called on the result of "match" to obtain the same result.

flatten

@flat_matches = $router->flatten($matches)

Takes a nested array structure of matches (as returned by "match") and flattens it into a single-level list. This is used internally by "flat_match".

clear

$router = $router->clear()

Clears the router - this includes removing all registered locations from the router. Returns the router object for method chaining.