Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Support URI with a dot in a pattern #112

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Changes
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
0.94
* Add support for form input;
* Add support for URIs with a dot in route pattern;

0.93
* Take `result_class` of `DBIx::Class::ResultSet` instead of asking for columns info on the actual data row (#110);
Expand Down
14 changes: 14 additions & 0 deletions examples/pod-synopsis-app/darth.pl
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,18 @@
};
};


resource 'domain' => sub {
params requires('name', type => Str, regex => qr/[^.]+\.[^.]+/); # ^/domain/(?<name>(?:[.]+.[.]+))(?:\.[^.]+?)?$
# params requires('name', type => Str, regex => qr/google.com/); # ^/domain/(?<name>(?:google.com))(?:\.[^.]+?)?$
# params requires('name', type => Str); # ^/domain/(?<name>[^/]+?)(?:\.[^.]+?)?$
route_param 'name' => sub {
get sub {
my $params = shift;
$params;
};
};
};


run;
4 changes: 2 additions & 2 deletions lib/Raisin.pm
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ sub psgi {
$self->hook('before_validation')->($self);

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

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

if ($self->api_version) {
$self->res->header('X-API-Version' => $self->api_version);
Expand Down
27 changes: 11 additions & 16 deletions lib/Raisin/Request.pm
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,26 @@ package Raisin::Request;

use parent 'Plack::Request';

sub prepare_params {
my ($self, $declared, $named) = @_;
sub build_params {
my ($self, $endpoint) = @_;

$self->{'raisin.declared'} = $declared;

# PRECEDENCE:
# - path
# - query
# - body
my %params = (
%{ $self->env->{'raisinx.body_params'} || {} },
%{ $self->query_parameters->as_hashref_mixed || {} },
%{ $named || {} },
%{ $self->env->{'raisinx.body_params'} || {} }, # 3. Body
%{ $self->query_parameters->as_hashref_mixed || {} }, # 2. Query
%{ $endpoint->named || {} }, # 1. Path
);

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

my $retval = 1;
my $success = 1;

foreach my $p (@$declared) {
foreach my $p (@{ $endpoint->params }) {
my $name = $p->name;
my $value = $params{$name};

if (not $p->validate(\$value)) {
$retval = 0;
$success = 0;
$p->required ? return : next;
}

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

$retval;
$success;
}

sub declared_params { shift->{'raisin.declared_params'} }
Expand All @@ -65,7 +60,7 @@ Extends L<Plack::Request>.

=head3 declared_params

=head3 prepare_params
=head3 build_params

=head3 raisin_parameters

Expand Down
14 changes: 5 additions & 9 deletions lib/Raisin/Routes/Endpoint.pm
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@ sub new {
# Populate params index
for my $p (@{ $self->params }) {
if ($p->named && (my $re = $p->regex)) {
$re =~ s/[\$^]//g;
$self->{check}{ $p->name } = $re;
$self->{check}{$p->name} = $re;
}
}

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

my %captured = %+;

foreach my $p (@{ $self->params }) {
next unless $p->named;
my $copy = $captured{ $p->name };
return unless $p->validate(\$copy, 'quite');
}

$self->named(\%captured);

1;
}

# TODO Rename methods:
# named -> captured
# path -> pattern

1;

__END__
Expand Down
4 changes: 2 additions & 2 deletions t/unit/request.t
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ subtest 'precedence' => sub {
my $req = Raisin::Request->new($case->{env});

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

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

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

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

Expand Down
28 changes: 20 additions & 8 deletions t/unit/routes/endpoint.t
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use warnings;

use Test::More;

use Types::Standard qw(Int);
use Types::Standard qw(Int Str);

use Raisin::Param;
use Raisin::Routes::Endpoint;
Expand Down Expand Up @@ -75,13 +75,12 @@ my @CASES = (
input => { method => 'put', path => '/api/item/42' },
expected => undef,
},
# TODO: GitHub issue #14
{
object => {
method => 'GET',
path => '/api/user/:id',
path => '/domain/:name',
},
input => { method => 'get', path => '/api/user/i.d'},
input => { method => 'get', path => '/domain/example.com'},
expected => 1,
},
);
Expand All @@ -94,7 +93,6 @@ sub _make_object {
subtest 'accessors' => sub {
for my $case (@CASES) {
my $e = _make_object($case->{object});
#isa_ok $e, 'Raisin::Routes::Endpoint', 'e';

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

my $is_matched = $e->match($case->{input}{method}, $case->{input}{path});

is $is_matched, $case->{expected}, 'match';

# named params
if ($is_matched && @{ $e->params }) {
for my $p (@{ $e->params }) {
# TODO: GitHub issue #14
ok $e->named->{$p->name}, 'named: ' . $p->name;
}
}
};
}
};

subtest '_build_regex' => sub {
my $e = Raisin::Routes::Endpoint->new(
code => sub { 1 },
method => 'GET',
params => [
Raisin::Param->new(
named => 1,
required => 1,
spec => {name => 'name', type => Str, regex => qr/[^.]+\.[^.]+/,},
type => 'requires',
),
],
path => '/domain/:name',
);
is $e->regex, '(?^:^/domain/(?<name>(?^:[^.]+\.[^.]+))(?:\.[^.]+?)?$)', 'regex';
};

done_testing;