Skip to content

Commit 8db698e

Browse files
author
Artur Khabibullin
committed
Support URI with a dot in a pattern
Fixes #14
1 parent cefd437 commit 8db698e

7 files changed

Lines changed: 55 additions & 37 deletions

File tree

Changes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
0.94
22
* Add support for form input;
3+
* Add support for URIs with a dot in route pattern;
34

45
0.93
56
* Take `result_class` of `DBIx::Class::ResultSet` instead of asking for columns info on the actual data row (#110);

examples/pod-synopsis-app/darth.pl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,4 +119,18 @@
119119
};
120120
};
121121

122+
123+
resource 'domain' => sub {
124+
params requires('name', type => Str, regex => qr/[^.]+\.[^.]+/); # ^/domain/(?<name>(?:[.]+.[.]+))(?:\.[^.]+?)?$
125+
# params requires('name', type => Str, regex => qr/google.com/); # ^/domain/(?<name>(?:google.com))(?:\.[^.]+?)?$
126+
# params requires('name', type => Str); # ^/domain/(?<name>[^/]+?)(?:\.[^.]+?)?$
127+
route_param 'name' => sub {
128+
get sub {
129+
my $params = shift;
130+
$params;
131+
};
132+
};
133+
};
134+
135+
122136
run;

lib/Raisin.pm

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ sub psgi {
187187
$self->hook('before_validation')->($self);
188188

189189
# Validation and coercion of declared params
190-
if (!$req->prepare_params($route->params, $route->named)) {
190+
if (!$req->build_params($route)) {
191191
$res->status(HTTP_BAD_REQUEST);
192192
$res->body('Invalid Parameters');
193193
return $res->finalize;
@@ -230,7 +230,7 @@ sub before_finalize {
230230
my $self = shift;
231231

232232
$self->res->status(HTTP_OK) unless $self->res->status;
233-
$self->res->header('X-Framework' => 'Raisin ' . __PACKAGE__->VERSION);
233+
$self->res->header('X-Framework' => 'Raisin ' . (__PACKAGE__->VERSION || 'dev'));
234234

235235
if ($self->api_version) {
236236
$self->res->header('X-API-Version' => $self->api_version);

lib/Raisin/Request.pm

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,31 +9,26 @@ package Raisin::Request;
99

1010
use parent 'Plack::Request';
1111

12-
sub prepare_params {
13-
my ($self, $declared, $named) = @_;
12+
sub build_params {
13+
my ($self, $endpoint) = @_;
1414

15-
$self->{'raisin.declared'} = $declared;
16-
17-
# PRECEDENCE:
18-
# - path
19-
# - query
20-
# - body
2115
my %params = (
22-
%{ $self->env->{'raisinx.body_params'} || {} },
23-
%{ $self->query_parameters->as_hashref_mixed || {} },
24-
%{ $named || {} },
16+
%{ $self->env->{'raisinx.body_params'} || {} }, # 3. Body
17+
%{ $self->query_parameters->as_hashref_mixed || {} }, # 2. Query
18+
%{ $endpoint->named || {} }, # 1. Path
2519
);
2620

2721
$self->{'raisin.parameters'} = \%params;
22+
$self->{'raisin.declared'} = $endpoint->params;
2823

29-
my $retval = 1;
24+
my $success = 1;
3025

31-
foreach my $p (@$declared) {
26+
foreach my $p (@{ $endpoint->params }) {
3227
my $name = $p->name;
3328
my $value = $params{$name};
3429

3530
if (not $p->validate(\$value)) {
36-
$retval = 0;
31+
$success = 0;
3732
$p->required ? return : next;
3833
}
3934

@@ -43,7 +38,7 @@ sub prepare_params {
4338
$self->{'raisin.declared_params'}{$name} = $value;
4439
}
4540

46-
$retval;
41+
$success;
4742
}
4843

4944
sub declared_params { shift->{'raisin.declared_params'} }
@@ -65,7 +60,7 @@ Extends L<Plack::Request>.
6560
6661
=head3 declared_params
6762
68-
=head3 prepare_params
63+
=head3 build_params
6964
7065
=head3 raisin_parameters
7166

lib/Raisin/Routes/Endpoint.pm

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,7 @@ sub new {
3636
# Populate params index
3737
for my $p (@{ $self->params }) {
3838
if ($p->named && (my $re = $p->regex)) {
39-
$re =~ s/[\$^]//g;
40-
$self->{check}{ $p->name } = $re;
39+
$self->{check}{$p->name} = $re;
4140
}
4241
}
4342

@@ -99,18 +98,15 @@ sub match {
9998
return if $path !~ $self->regex;
10099

101100
my %captured = %+;
102-
103-
foreach my $p (@{ $self->params }) {
104-
next unless $p->named;
105-
my $copy = $captured{ $p->name };
106-
return unless $p->validate(\$copy, 'quite');
107-
}
108-
109101
$self->named(\%captured);
110102

111103
1;
112104
}
113105

106+
# TODO Rename methods:
107+
# named -> captured
108+
# path -> pattern
109+
114110
1;
115111

116112
__END__

t/unit/request.t

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ subtest 'precedence' => sub {
7171
my $req = Raisin::Request->new($case->{env});
7272

7373
$r->match($case->{env}{REQUEST_METHOD}, $case->{env}{PATH_INFO});
74-
$req->prepare_params($r->params, $r->named);
74+
$req->build_params($r);
7575

7676
is $req->raisin_parameters->{id}, $case->{expected};
7777
}
@@ -156,7 +156,7 @@ subtest 'validation' => sub {
156156
my $req = Raisin::Request->new($case->{env});
157157

158158
$r->match($case->{env}{REQUEST_METHOD}, $case->{env}{PATH_INFO});
159-
is $req->prepare_params($r->params, $r->named), $case->{expected}{ret};
159+
is $req->build_params($r), $case->{expected}{ret};
160160

161161
next unless $case->{expected}{ret};
162162

t/unit/routes/endpoint.t

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use warnings;
44

55
use Test::More;
66

7-
use Types::Standard qw(Int);
7+
use Types::Standard qw(Int Str);
88

99
use Raisin::Param;
1010
use Raisin::Routes::Endpoint;
@@ -75,13 +75,12 @@ my @CASES = (
7575
input => { method => 'put', path => '/api/item/42' },
7676
expected => undef,
7777
},
78-
# TODO: GitHub issue #14
7978
{
8079
object => {
8180
method => 'GET',
82-
path => '/api/user/:id',
81+
path => '/domain/:name',
8382
},
84-
input => { method => 'get', path => '/api/user/i.d'},
83+
input => { method => 'get', path => '/domain/example.com'},
8584
expected => 1,
8685
},
8786
);
@@ -94,7 +93,6 @@ sub _make_object {
9493
subtest 'accessors' => sub {
9594
for my $case (@CASES) {
9695
my $e = _make_object($case->{object});
97-
#isa_ok $e, 'Raisin::Routes::Endpoint', 'e';
9896

9997
subtest '-' => sub {
10098
for my $m (keys %{ $case->{object} }) {
@@ -108,21 +106,35 @@ subtest 'match' => sub {
108106
for my $case (@CASES) {
109107
subtest "$case->{object}{method}:$case->{object}{path}" => sub {
110108
my $e = _make_object($case->{object});
111-
#isa_ok $e, 'Raisin::Routes::Endpoint', 'e';
112109

113110
my $is_matched = $e->match($case->{input}{method}, $case->{input}{path});
114-
115111
is $is_matched, $case->{expected}, 'match';
116112

117113
# named params
118114
if ($is_matched && @{ $e->params }) {
119115
for my $p (@{ $e->params }) {
120-
# TODO: GitHub issue #14
121116
ok $e->named->{$p->name}, 'named: ' . $p->name;
122117
}
123118
}
124119
};
125120
}
126121
};
127122

123+
subtest '_build_regex' => sub {
124+
my $e = Raisin::Routes::Endpoint->new(
125+
code => sub { 1 },
126+
method => 'GET',
127+
params => [
128+
Raisin::Param->new(
129+
named => 1,
130+
required => 1,
131+
spec => {name => 'name', type => Str, regex => qr/[^.]+\.[^.]+/,},
132+
type => 'requires',
133+
),
134+
],
135+
path => '/domain/:name',
136+
);
137+
is $e->regex, '(?^:^/domain/(?<name>(?^:[^.]+\.[^.]+))(?:\.[^.]+?)?$)', 'regex';
138+
};
139+
128140
done_testing;

0 commit comments

Comments
 (0)