File Coverage

blib/lib/Router/Pygmy.pm
Criterion Covered Total %
statement 60 62 96.7
branch 18 22 81.8
condition 5 8 62.5
subroutine 10 10 100.0
pod 5 6 83.3
total 98 108 90.7


line stmt bran cond sub pod time code
1             package Router::Pygmy;
2             $Router::Pygmy::VERSION = '0.04';
3 1     1   954 use strict;
  1         2  
  1         49  
4 1     1   7 use warnings;
  1         2  
  1         42  
5              
6             # ABSTRACT: ultrasimple path router matching paths to names and args
7              
8              
9 1     1   53 use Carp;
  1         2  
  1         92  
10 1     1   630 use Router::Pygmy::Route;
  1         3  
  1         812  
11              
12             my ( $PATH_PART_IDX, $ARG_IDX, $ROUTE_IDX ) = 0 .. 2;
13              
14             sub new {
15 3     3 1 1569 my $class = shift;
16 3         12 my $router = bless(
17             {
18             lookup => [],
19             route_for => {},
20             },
21             $class
22             );
23 3 100       12 if (@_) {
24              
25             # so far only
26             # routes => \%routes
27             # or
28             # { routes => \%routes }
29             # is allowed
30 2 100 66     11 my %args = ref $_[0] && ref $_[0] eq 'HASH' ? %{ $_[0] } : @_;
  1         4  
31              
32 2 50       6 if ( my $routes = $args{routes} ) {
33 2         5 for my $spec ( keys %$routes ) {
34 6         10 $router->add_route( $spec, $routes->{$spec} );
35             }
36             }
37             }
38              
39 3         7 return $router;
40             }
41              
42             sub new_route {
43 11     11 0 11 my $this = shift;
44 11         26 return Router::Pygmy::Route->parse(@_);
45             }
46              
47             sub add_route {
48 13     13 1 1841 my ( $this, $spec, $name ) = @_;
49              
50 13 100       39 if ( my $duplicit_route = $this->{route_for}{$name} ) {
51 2         9 croak sprintf "Duplicit routes for '$name' ('%s', '%s')",
52             $duplicit_route->spec, $spec;
53             }
54              
55 11         20 my $route = $this->new_route($spec);
56 11         18 my $lookup = $this->{lookup};
57 11         11 for my $part ( @{ $route->parts } ) {
  11         21  
58 33 100 100     123 $lookup = (
59             defined($part)
60             ? $lookup->[$PATH_PART_IDX]{$part}
61             : $lookup->[$ARG_IDX]
62             ) ||= [];
63             }
64              
65 11 50       24 if ( my $duplicit_name = $lookup->[$ROUTE_IDX] ) {
66 0         0 my $duplicit_route = $this->{route_for}{$duplicit_name};
67 0         0 croak sprintf "Identical routes '%s', '%s'",
68             $duplicit_route->spec, $route->spec;
69             }
70              
71 11         15 $lookup->[$ROUTE_IDX] = $name;
72 11         26 $this->{route_for}{$name} = $route;
73 11         19 return $route;
74             }
75              
76             # uri for
77             sub path_for {
78 14     14 1 377 my $this = shift;
79 14         20 my $name = shift;
80              
81 14 100       66 my $route = $this->{route_for}{$name}
82             or croak "No route '$name'";
83 13         39 return $route->path_for(@_);
84             }
85              
86             # return (name, \@args)
87             sub match {
88 8     8 1 25 my ( $this, $path ) = @_;
89              
90 8         26 my @parts = grep { $_ } split m{/}, $path;
  26         48  
91 8         10 my @args;
92              
93 8         14 my $lookup = $this->{lookup};
94              
95 8         18 while (@parts) {
96 26         32 my $part = shift @parts;
97              
98 26 100       67 if ( my $by_path_part = $lookup->[$PATH_PART_IDX]{$part} ) {
    100          
99 13         51 $lookup = $by_path_part;
100             }
101             elsif ( my $by_arg = $lookup->[$ARG_IDX] ) {
102 11         16 push @args, $part;
103 11         22 $lookup = $by_arg;
104             }
105             else {
106 2         11 return;
107             }
108             }
109              
110 6   33     606 my $name = $lookup && $lookup->[$ROUTE_IDX];
111 6 50       49 return $name ? ( $name, \@args ) : ();
112             }
113              
114             sub match_named {
115 2     2 1 4 my $this = shift;
116              
117 2 50       6 my ($name, $args) = $this->match(@_) or return;
118 2         6 my $route = $this->{route_for}{$name};
119 2         9 my $names = $route->arg_names;
120 2         3 my $i = 0;
121 2         4 return ( $name, [ map { ($names->[$i++] => $_) } @$args ]);
  3         24  
122             }
123              
124             1;
125             # vim: expandtab:shiftwidth=4:tabstop=4:softtabstop=0:textwidth=78:
126              
127             __END__