From 9bd7d896791e941cb0b52c6ed730af2cd71eaf8a Mon Sep 17 00:00:00 2001 From: bbrtj Date: Thu, 20 Jun 2024 07:51:00 +0200 Subject: [PATCH] Tidy up source code This commit will show up in git blame a lot. --- ex/router_bench.pl | 25 +- lib/Kelp.pm | 178 +++++++----- lib/Kelp/Base.pm | 29 +- lib/Kelp/Exception.pm | 6 +- lib/Kelp/Generator.pm | 11 +- lib/Kelp/Less.pm | 111 ++++---- lib/Kelp/Module.pm | 23 +- lib/Kelp/Module/Config.pm | 115 ++++---- lib/Kelp/Module/Config/Null.pm | 3 +- lib/Kelp/Module/JSON.pm | 9 +- lib/Kelp/Module/Logger.pm | 37 ++- lib/Kelp/Module/Logger/Simple.pm | 9 +- lib/Kelp/Module/Null.pm | 7 +- lib/Kelp/Module/Routes.pm | 11 +- lib/Kelp/Module/Template.pm | 30 +- lib/Kelp/Module/Template/Null.pm | 12 +- lib/Kelp/Request.pm | 134 +++++---- lib/Kelp/Response.pm | 131 +++++---- lib/Kelp/Routes.pm | 215 +++++++------- lib/Kelp/Routes/Location.pm | 7 +- lib/Kelp/Routes/Pattern.pm | 113 ++++---- lib/Kelp/Template.pm | 27 +- lib/Kelp/Test.pm | 142 ++++++---- lib/Kelp/Test/CookieJar.pm | 17 +- lib/Kelp/Util.pm | 38 +-- t/base.t | 28 +- t/bin_tests.t | 11 +- t/conf/deployment_no_templates/config.pl | 2 +- t/conf/disable/test2.pl | 2 +- t/conf/error/test.pl | 2 +- t/conf/f/config.pl | 2 +- t/conf/stack_trace_enabled/test.pl | 4 +- t/custom_req_resp.t | 10 +- t/exceptions.t | 45 ++- t/json-encode-error.t | 10 +- t/less.t | 56 ++-- t/lib/JsonError.pm | 37 ++- t/lib/MyApp.pm | 31 ++- t/lib/MyApp/Module/Null.pm | 7 +- t/lib/MyApp/Response.pm | 4 +- t/lib/MyApp/Routes.pm | 5 +- t/lib/MyApp/Routes2.pm | 5 +- t/lib/MyApp2.pm | 17 +- t/lib/MyApp2/Controller/Bar.pm | 3 +- t/lib/StringifyingException.pm | 5 +- t/middleware.t | 18 +- t/module.t | 28 +- t/module_config.t | 24 +- t/module_config_get.t | 12 +- t/module_config_merge.t | 137 ++++----- t/module_config_null.t | 2 +- t/module_config_process_mode.t | 8 +- t/module_json.t | 2 +- t/module_load.t | 13 +- t/module_logger.t | 19 +- t/module_template.t | 6 +- t/module_template_null.t | 4 +- t/new_anonymous.t | 29 +- t/params.t | 60 ++-- t/pattern_build.t | 118 ++++---- t/pattern_cache.t | 79 +++--- t/pattern_match.t | 338 ++++++++++++----------- t/psgi.t | 152 +++++----- t/redefine_attrs.t | 8 +- t/request.t | 122 ++++---- t/request_session.t | 71 ++--- t/response.t | 96 +++---- t/response_error.t | 200 +++++++------- t/response_finalize.t | 4 +- t/response_redirect.t | 22 +- t/routes_add.t | 219 +++++++-------- t/routes_controller.t | 34 +-- t/routes_invalid.t | 18 +- t/routes_match.t | 73 ++--- t/routes_url.t | 21 +- t/run.t | 198 +++++++------ t/run_bridge.t | 51 ++-- t/safe_param.t | 7 +- t/subclassed.t | 24 +- t/template.t | 6 +- t/test_psgi.t | 4 +- t/test_request.t | 17 +- t/unicode.t | 45 ++- t/util.t | 70 ++--- 84 files changed, 2206 insertions(+), 1879 deletions(-) diff --git a/ex/router_bench.pl b/ex/router_bench.pl index d0dd6a0..79c6d64 100644 --- a/ex/router_bench.pl +++ b/ex/router_bench.pl @@ -6,24 +6,27 @@ my $path = join '', map { "/$_" } 1 .. $depth, 'handler'; { + package TestApp; use Kelp::Base 'Kelp'; sub hello { 'hello' } - sub hi { 'hi' } + sub hi { 'hi' } } my $app = TestApp->new; -sub prepare_match { +sub prepare_match +{ my $r = shift; return sub { $r->match($path) }; } -sub prepare_dispatch { +sub prepare_dispatch +{ my $r = shift; - my @routes = @{ $r->match($path) }; + my @routes = @{$r->match($path)}; return sub { $r->dispatch($app, $_) for @routes }; } @@ -52,17 +55,19 @@ sub prepare_dispatch { '/handler' => 'hello', ); - $r->add('' => { - to => sub { 1 }, - tree => $tree_base, - }); + $r->add( + '' => { + to => sub { 1 }, + tree => $tree_base, + } + ); - say "$class matches: " . join ', ', map { '"' . $_->name . '"' } @{ $r->match($path) }; + say "$class matches: " . join ', ', map { '"' . $_->name . '"' } @{$r->match($path)}; $cases{"$class->match"} = prepare_match($r); $cases{"$class->dispatch"} = prepare_dispatch($r); } -cmpthese -2, \%cases; +cmpthese - 2, \%cases; # benchmarks different implementations of Kelp::Routes # usage: ex/router_bench.pl [ ...] diff --git a/lib/Kelp.pm b/lib/Kelp.pm index b2edd02..289db8e 100644 --- a/lib/Kelp.pm +++ b/lib/Kelp.pm @@ -16,11 +16,11 @@ our $VERSION = '2.01'; # Basic attributes attr -host => hostname; -attr mode => $ENV{KELP_ENV} // $ENV{PLACK_ENV} // 'development'; +attr mode => $ENV{KELP_ENV} // $ENV{PLACK_ENV} // 'development'; attr -path => $FindBin::Bin; -attr -name => sub { ( ref( $_[0] ) =~ /(\w+)$/ ) ? $1 : 'Noname' }; -attr request_obj => 'Kelp::Request'; -attr response_obj => 'Kelp::Response'; +attr -name => sub { (ref($_[0]) =~ /(\w+)$/) ? $1 : 'Noname' }; +attr request_obj => 'Kelp::Request'; +attr response_obj => 'Kelp::Response'; # Debug attr long_error => $ENV{KELP_LONG_ERROR} // 0; @@ -45,7 +45,8 @@ attr req => undef; attr res => undef; # Initialization -sub new { +sub new +{ my $self = shift->SUPER::new(@_); # Always load these modules, but allow client to override @@ -53,7 +54,7 @@ sub new { $self->_load_routes(); # Load the modules from the config - if ( defined( my $modules = $self->config('modules') ) ) { + if (defined(my $modules = $self->config('modules'))) { $self->load_module($_) for (@$modules); } @@ -61,17 +62,18 @@ sub new { return $self; } -sub new_anon { +sub new_anon +{ state $last_anon = 0; my $class = shift; # make sure we don't eval something dodgy die "invalid class for new_anon" - if ref $class # not a string - || !$class # not an empty string, undef or 0 - || !Class::Inspector->loaded($class) # not a loaded class - || !$class->isa(__PACKAGE__) # not a correct class - ; + if ref $class # not a string + || !$class # not an empty string, undef or 0 + || !Class::Inspector->loaded($class) # not a loaded class + || !$class->isa(__PACKAGE__) # not a correct class + ; my $anon_class = "Kelp::Anonymous::$class" . ++$last_anon; my $err = do { @@ -96,28 +98,32 @@ sub new_anon { return $anon_class->new(@_); } -sub _load_config { +sub _load_config +{ my $self = shift; - $self->load_module( $self->config_module, extra => $self->__config ); + $self->load_module($self->config_module, extra => $self->__config); } -sub _load_routes { +sub _load_routes +{ my $self = shift; $self->load_module('Routes'); } # Create a shallow copy of the app, optionally blessed into a # different subclass. -sub _clone { +sub _clone +{ my $self = shift; my $subclass = shift || ref($self); ref $self or croak '_clone requires instance'; - return bless { %$self }, $subclass; + return bless {%$self}, $subclass; } -sub load_module { - my ( $self, $name, %args ) = @_; +sub load_module +{ + my ($self, $name, %args) = @_; # A module name with a leading + indicates it's already fully # qualified (i.e., it does not need the Kelp::Module:: prefix). @@ -126,72 +132,78 @@ sub load_module { # Make sure the module was not already loaded return if $self->loaded_modules->{$name}; - my $class = Plack::Util::load_class( $name, $prefix ); - my $module = $self->loaded_modules->{$name} = $class->new( app => $self ); + my $class = Plack::Util::load_class($name, $prefix); + my $module = $self->loaded_modules->{$name} = $class->new(app => $self); # When loading the Config module itself, we don't have # access to $self->config yet. This is why we check if # config is available, and if it is, then we pull the # initialization hash. my $args_from_config = {}; - if ( $self->can('config') ) { + if ($self->can('config')) { $args_from_config = $self->config("modules_init.$name") // {}; } - $module->build( %$args_from_config, %args ); + $module->build(%$args_from_config, %args); return $module; } # Override this one to add custom initializations -sub build { +sub build +{ } # Override to use a custom request object -sub build_request { - my ( $self, $env ) = @_; +sub build_request +{ + my ($self, $env) = @_; my $package = $self->request_obj; eval qq{require $package}; - return $package->new( app => $self, env => $env); + return $package->new(app => $self, env => $env); } # Override to use a custom response object -sub build_response { +sub build_response +{ my $self = shift; my $package = $self->response_obj; eval qq{require $package}; - return $package->new( app => $self ); + return $package->new(app => $self); } # Override to change what happens before the route is handled -sub before_dispatch { - my ( $self, $destination ) = @_; +sub before_dispatch +{ + my ($self, $destination) = @_; # Log info about the route - if ( $self->can('logger') ) { + if ($self->can('logger')) { my $req = $self->req; $self->info( sprintf "%s: %s - %s %s - %s", - ref $self, - $req->address, $req->method, - $req->path, $destination + ref $self, + $req->address, $req->method, + $req->path, $destination ); } } # Override to manipulate the end response -sub before_finalize { +sub before_finalize +{ my $self = shift; $self->res->header('X-Framework' => 'Perl Kelp'); } # Override this to wrap more middleware around the app -sub run { +sub run +{ my $self = shift; my $app = sub { $self->psgi(@_) }; # Add middleware - if ( defined( my $middleware = $self->config('middleware') ) ) { + if (defined(my $middleware = $self->config('middleware'))) { for my $class (@$middleware) { # Make sure the middleware was not already loaded @@ -201,25 +213,26 @@ sub run { my $mw = Plack::Util::load_class($class, 'Plack::Middleware'); my $args = $self->config("middleware_init.$class") // {}; - $app = $mw->wrap( $app, %$args ); + $app = $mw->wrap($app, %$args); } } return $app; } -sub psgi { - my ( $self, $env ) = @_; +sub psgi +{ + my ($self, $env) = @_; # Create the request and response objects - my $req = $self->req( $self->build_request($env) ); - my $res = $self->res( $self->build_response ); + my $req = $self->req($self->build_request($env)); + my $res = $self->res($self->build_response); # Get route matches - my $match = $self->routes->match( $req->path, $req->method ); + my $match = $self->routes->match($req->path, $req->method); # None found? Show 404 ... - if ( !@$match ) { + if (!@$match) { $res->render_404; return $self->finalize; } @@ -230,26 +243,28 @@ sub psgi { for my $route (@$match) { # Dispatch - $req->named( $route->named ); - $req->route_name( $route->name ); - my $data = $self->routes->dispatch( $self, $route ); + $req->named($route->named); + $req->route_name($route->name); + my $data = $self->routes->dispatch($self, $route); + + if ($route->bridge) { - if ( $route->bridge ) { # Is it a bridge? Bridges must return a true value to allow the # rest of the routes to run. They may also have rendered # something, in which case trust that and don't render 403 (but # still end the execution chain) - if ( !$data ) { + if (!$data) { $res->render_403 unless $res->rendered; } } - elsif ( defined $data ) { + elsif (defined $data) { + # If the non-bridge route returned something, then analyze it and render it # Handle delayed response if CODE return $data if ref $data eq 'CODE'; - $res->render( $data ) unless $res->rendered; + $res->render($data) unless $res->rendered; } # Do not go any further if we got a render @@ -257,16 +272,18 @@ sub psgi { } # If nothing got rendered - if ( !$res->rendered ) { + if (!$res->rendered) { + # render 404 if only briges matched - if ( $match->[-1]->bridge ) { + if ($match->[-1]->bridge) { $res->render_404; } + # or die with error else { - die $match->[-1]->to - . " did not render for method " - . $req->method; + die $match->[-1]->to + . " did not render for method " + . $req->method; } } @@ -282,8 +299,9 @@ sub psgi { $res->headers->clear; if (blessed $exception && $exception->isa('Kelp::Exception')) { + # only log it as an error if the body is present - $self->logger( 'error', $exception->body ) + $self->logger('error', $exception->body) if $self->can('logger') && defined $exception->body; $res->render_exception($exception); @@ -292,7 +310,7 @@ sub psgi { my $message = $self->long_error ? longmess($exception) : $exception; # Log error - $self->logger( 'critical', $message ) if $self->can('logger'); + $self->logger('critical', $message) if $self->can('logger'); # Render an application erorr (hides details on production) $res->render_500($exception); @@ -302,17 +320,18 @@ sub psgi { }; } -sub finalize { +sub finalize +{ my $self = shift; $self->before_finalize; $self->res->finalize; } - #---------------------------------------------------------------- # Request and Response shortcuts #---------------------------------------------------------------- -sub param { +sub param +{ my $self = shift; unshift @_, $self->req; @@ -322,12 +341,14 @@ sub param { sub session { shift->req->session(@_) } -sub stash { +sub stash +{ my $self = shift; @_ ? $self->req->stash->{$_[0]} : $self->req->stash; } -sub named { +sub named +{ my $self = shift; @_ ? $self->req->named->{$_[0]} : $self->req->named; } @@ -336,32 +357,37 @@ sub named { # Utility #---------------------------------------------------------------- -sub is_production { +sub is_production +{ my $self = shift; return any { lc $self->mode eq $_ } qw(deployment production); } -sub url_for { - my ( $self, $name, @args ) = @_; +sub url_for +{ + my ($self, $name, @args) = @_; my $result = $name; - try { $result = $self->routes->url( $name, @args ) }; + try { $result = $self->routes->url($name, @args) }; return $result; } -sub abs_url { - my ( $self, $name, @args ) = @_; - my $url = $self->url_for( $name, @args ); - return URI->new_abs( $url, $self->config('app_url') )->as_string; +sub abs_url +{ + my ($self, $name, @args) = @_; + my $url = $self->url_for($name, @args); + return URI->new_abs($url, $self->config('app_url'))->as_string; } -sub charset_encode { - my ( $self, $string ) = @_; +sub charset_encode +{ + my ($self, $string) = @_; return $string unless $self->charset; return encode $self->charset, $string; } -sub charset_decode { - my ( $self, $string ) = @_; +sub charset_decode +{ + my ($self, $string) = @_; return $string unless $self->charset; return decode $self->charset, $string; } diff --git a/lib/Kelp/Base.pm b/lib/Kelp/Base.pm index a772d65..8978939 100644 --- a/lib/Kelp/Base.pm +++ b/lib/Kelp/Base.pm @@ -6,7 +6,8 @@ use feature (); use Carp; use namespace::autoclean (); -sub import { +sub import +{ my $class = shift; my $caller = caller; @@ -15,16 +16,16 @@ sub import { my $base = shift || $class; - if ( $base ne '-strict' ) { + if ($base ne '-strict') { no strict 'refs'; no warnings 'redefine'; my $file = $base; $file =~ s/::|'/\//g; - require "$file.pm" unless $base->can('new'); # thanks sri + require "$file.pm" unless $base->can('new'); # thanks sri push @{"${caller}::ISA"}, $base; - *{"${caller}::attr"} = sub { attr( $caller, @_ ) }; + *{"${caller}::attr"} = sub { attr($caller, @_) }; } strict->import; @@ -36,14 +37,16 @@ sub import { ); } -sub new { - bless { @_[ 1 .. $#_ ] }, $_[0]; +sub new +{ + bless {@_[1 .. $#_]}, $_[0]; } -sub attr { - my ( $class, $name, $default ) = @_; +sub attr +{ + my ($class, $name, $default) = @_; - if ( ref $default && ref $default ne 'CODE' ) { + if (ref $default && ref $default ne 'CODE') { croak "Default value for '$name' can not be a reference."; } @@ -54,14 +57,14 @@ sub attr { my $readonly = $name =~ s/^\-//; *{"${class}::$name"} = sub { - if ( @_ > 1 && !$readonly ) { + if (@_ > 1 && !$readonly) { $_[0]->{$name} = $_[1]; } return $_[0]->{$name} if exists $_[0]->{$name}; return $_[0]->{$name} = - ref $default eq 'CODE' - ? $default->( $_[0] ) - : $default; + ref $default eq 'CODE' + ? $default->($_[0]) + : $default; }; } diff --git a/lib/Kelp/Exception.pm b/lib/Kelp/Exception.pm index c3d668c..334d9df 100644 --- a/lib/Kelp/Exception.pm +++ b/lib/Kelp/Exception.pm @@ -8,7 +8,8 @@ attr -code => sub { croak 'code is required' }; attr body => undef; -sub new { +sub new +{ my ($class, $code, %params) = @_; croak 'Kelp::Exception can only accept 4XX or 5XX codes' @@ -18,7 +19,8 @@ sub new { return $class->SUPER::new(%params); } -sub throw { +sub throw +{ my $class = shift; my $ex = $class->new(@_); die $ex; diff --git a/lib/Kelp/Generator.pm b/lib/Kelp/Generator.pm index 31e1ab0..550ef3c 100644 --- a/lib/Kelp/Generator.pm +++ b/lib/Kelp/Generator.pm @@ -7,14 +7,16 @@ use Carp; attr -templates_dir => sub { path(__FILE__)->parent . '/templates' }; -sub list_templates { +sub list_templates +{ my ($self) = @_; my $dir = $self->templates_dir; return map { path($_)->basename } glob "$dir/*"; } -sub get_template_files { +sub get_template_files +{ my ($self, $template) = @_; my $dir = $self->templates_dir; @@ -25,7 +27,7 @@ sub get_template_files { my ($index_file) = map { "$dir/$_/template" } grep { $_ eq $template } $self->list_templates - ; + ; return unless $index_file; my $index = path($index_file); @@ -35,7 +37,8 @@ sub get_template_files { return map { "$dir/$template/$_" } grep { length } @files; } -sub get_template { +sub get_template +{ my ($self, $template, $name, %args) = @_; my $vars = {'name' => $name, %args}; diff --git a/lib/Kelp/Less.pm b/lib/Kelp/Less.pm index 6979b6e..266545d 100644 --- a/lib/Kelp/Less.pm +++ b/lib/Kelp/Less.pm @@ -4,32 +4,33 @@ use Kelp; use Kelp::Base -strict; our @EXPORT = qw/ - app - attr - config - del - debug - error - get - module - named - param - post - put - req - res - route - run - session - stash - template - view - /; + app + attr + config + del + debug + error + get + module + named + param + post + put + req + res + route + run + session + stash + template + view + /; our $app; -sub import { - my $class = shift; +sub import +{ + my $class = shift; my $caller = caller; no strict 'refs'; for my $sub (@EXPORT) { @@ -44,52 +45,58 @@ sub import { $app->routes->base('main'); } -sub route { - my ( $path, $to ) = @_; - $app->add_route( $path, $to ); +sub route +{ + my ($path, $to) = @_; + $app->add_route($path, $to); } -sub get { - my ( $path, $to ) = @_; - route ref($path) ? $path : [ GET => $path ], $to; +sub get +{ + my ($path, $to) = @_; + route ref($path) ? $path : [GET => $path], $to; } -sub post { - my ( $path, $to ) = @_; - route ref($path) ? $path : [ POST => $path ], $to; +sub post +{ + my ($path, $to) = @_; + route ref($path) ? $path : [POST => $path], $to; } -sub put { - my ( $path, $to ) = @_; - route ref($path) ? $path : [ PUT => $path ], $to; +sub put +{ + my ($path, $to) = @_; + route ref($path) ? $path : [PUT => $path], $to; } -sub del { - my ( $path, $to ) = @_; - route ref($path) ? $path : [ DELETE => $path ], $to; +sub del +{ + my ($path, $to) = @_; + route ref($path) ? $path : [DELETE => $path], $to; } -sub run { +sub run +{ # If we're running a test, then return the entire app, # otherwise return the PSGI subroutine return $ENV{KELP_TESTING} ? $app : $app->run; } -sub app { $app } -sub attr { Kelp::Base::attr( ref($app), @_ ) } -sub param { $app->param(@_) } -sub session { $app->session(@_) } -sub stash { $app->stash(@_) } -sub named { $app->named(@_) } -sub req { $app->req } -sub res { $app->res } +sub app { $app } +sub attr { Kelp::Base::attr(ref($app), @_) } +sub param { $app->param(@_) } +sub session { $app->session(@_) } +sub stash { $app->stash(@_) } +sub named { $app->named(@_) } +sub req { $app->req } +sub res { $app->res } sub template { $app->res->template(@_) } -sub view { $app->res->template(@_) } -sub debug { $app->debug(@_) if $app->can('debug') } -sub error { $app->error(@_) if $app->can('error') } -sub module { $app->load_module(@_) } -sub config { $app->config(@_) } +sub view { $app->res->template(@_) } +sub debug { $app->debug(@_) if $app->can('debug') } +sub error { $app->error(@_) if $app->can('error') } +sub module { $app->load_module(@_) } +sub config { $app->config(@_) } 1; diff --git a/lib/Kelp/Module.pm b/lib/Kelp/Module.pm index 973ba91..9923960 100644 --- a/lib/Kelp/Module.pm +++ b/lib/Kelp/Module.pm @@ -3,34 +3,37 @@ package Kelp::Module; use Kelp::Base; use Carp; -attr -app => sub { die "app is required" }; +attr -app => sub { die "app is required" }; -sub new { +sub new +{ my $self = shift->SUPER::new(@_); $self->app; return $self; } # Override this to register items -sub build { - my ( $self, %args ) = @_; +sub build +{ + my ($self, %args) = @_; } -sub register { - my ( $self, %items ) = @_; - while ( my ( $name, $item ) = each(%items) ) { +sub register +{ + my ($self, %items) = @_; + while (my ($name, $item) = each(%items)) { no strict 'refs'; no warnings 'redefine'; - my $app = ref $self->app; + my $app = ref $self->app; my $glob = "${app}::$name"; # Manually check if the glob is being redefined - if ( !$ENV{KELP_REDEFINE} && $self->app->can($name) ) { + if (!$ENV{KELP_REDEFINE} && $self->app->can($name)) { croak "Redefining of $glob not allowed"; } - if ( ref $item eq 'CODE' ) { + if (ref $item eq 'CODE') { *{$glob} = $item; } else { diff --git a/lib/Kelp/Module/Config.pm b/lib/Kelp/Module/Config.pm index 6cdc6a9..acf9072 100644 --- a/lib/Kelp/Module/Config.pm +++ b/lib/Kelp/Module/Config.pm @@ -6,7 +6,6 @@ use Try::Tiny; use Test::Deep; use Path::Tiny; - # Extension to look for attr ext => 'pl'; @@ -19,7 +18,7 @@ attr path => sub { $self->app->path, $self->app->path . '/conf', $self->app->path . '/../conf' - ] + ]; }; attr separator => sub { qr/\./ }; @@ -57,9 +56,9 @@ attr data => sub { # JSON JSON => { - allow_blessed => 1, + allow_blessed => 1, convert_blessed => 1, - utf8 => 1 + utf8 => 1 }, }, @@ -72,13 +71,14 @@ attr data => sub { }; }; -sub get { - my ( $self, $path ) = @_; +sub get +{ + my ($self, $path) = @_; return unless $path; - my @a = split( $self->separator, $path ); + my @a = split($self->separator, $path); my $val = $self->data; for my $chunk (@a) { - if ( ref($val) eq 'HASH' ) { + if (ref($val) eq 'HASH') { $val = $val->{$chunk}; } else { @@ -89,8 +89,9 @@ sub get { } # Override this one to use other config formats. -sub load { - my ( $self, $filename ) = @_; +sub load +{ + my ($self, $filename) = @_; # Open and read file my $text; @@ -103,7 +104,7 @@ sub load { return {}; } - my ( $hash, $error ); + my ($hash, $error); { local $@; my $app = $self->app; @@ -111,38 +112,40 @@ sub load { $module =~ s/\W/_/g; $hash = eval "package Kelp::Module::Config::Sandbox::$module;" - . "use Kelp::Base -strict;" - . "sub app; local *app = sub { \$app };" - . "sub include(\$); local *include = sub { \$self->load(\@_) };" - . $text; + . "use Kelp::Base -strict;" + . "sub app; local *app = sub { \$app };" + . "sub include(\$); local *include = sub { \$self->load(\@_) };" + . $text; $error = $@; } die "Config file $filename parse error: " . $error if $error; die "Config file $filename did not return a HASH - $hash" - unless ref $hash eq 'HASH'; + unless ref $hash eq 'HASH'; return $hash; } -sub process_mode { - my ( $self, $mode ) = @_; +sub process_mode +{ + my ($self, $mode) = @_; - my $filename = sub { - my @paths = ref( $self->path ) ? @{ $self->path } : ( $self->path ); + my $filename = sub { + my @paths = ref($self->path) ? @{$self->path} : ($self->path); for my $path (@paths) { next unless defined $path; - my $filename = sprintf( '%s/%s.%s', $path, $mode, $self->ext ); + my $filename = sprintf('%s/%s.%s', $path, $mode, $self->ext); return $filename if -r $filename; } - }->(); + } + ->(); - unless ( $filename ) { - if ( $ENV{KELP_CONFIG_WARN} ) { + unless ($filename) { + if ($ENV{KELP_CONFIG_WARN}) { my $message = - $mode eq 'config' - ? "Main config file not found or not readable" - : "Config file for mode '$mode' not found or not readable"; + $mode eq 'config' + ? "Main config file not found or not readable" + : "Config file for mode '$mode' not found or not readable"; warn $message; } return; @@ -155,15 +158,16 @@ sub process_mode { catch { die "Parsing $filename died with error: '${_}'"; }; - $self->data( _merge( $self->data, $parsed ) ); + $self->data(_merge($self->data, $parsed)); } -sub build { - my ( $self, %args ) = @_; +sub build +{ + my ($self, %args) = @_; # Find, parse and merge 'config' and mode files - for my $name ( 'config', $self->app->mode ) { - $self->process_mode( $name ); + for my $name ('config', $self->app->mode) { + $self->process_mode($name); } # Undocumented! Add 'extra' argument to unlock these special features: @@ -174,19 +178,19 @@ sub build { # the configuration, clear it, or set it to a new value. You can do those # at any point in the life of the app. # - if ( my $extra = delete $args{extra} ) { - $self->data( _merge( $self->data, $extra ) ) if ref($extra) eq 'HASH'; + if (my $extra = delete $args{extra}) { + $self->data(_merge($self->data, $extra)) if ref($extra) eq 'HASH'; $self->register( - # A tiny object containing only merge, clear and set. Very useful when - # you're writing tests and need to add new config options, set the - # entire config hash to a new value, or clear it completely. + # A tiny object containing only merge, clear and set. Very useful when + # you're writing tests and need to add new config options, set the + # entire config hash to a new value, or clear it completely. _cfg => Plack::Util::inline_object( merge => sub { - $self->data( _merge( $self->data, $_[0] ) ); + $self->data(_merge($self->data, $_[0])); }, - clear => sub { $self->data( {} ) }, - set => sub { $self->data( $_[0] ) } + clear => sub { $self->data({}) }, + set => sub { $self->data($_[0]) } ) ); } @@ -198,47 +202,48 @@ sub build { # A wrapper arount the get method config => sub { - my ( $app, $path ) = @_; + my ($app, $path) = @_; return $self->get($path); } ); } -sub _merge { - my ( $a, $b, $sigil ) = @_; +sub _merge +{ + my ($a, $b, $sigil) = @_; return $b - if !ref($a) - || !ref($b) - || ref($a) ne ref($b); + if !ref($a) + || !ref($b) + || ref($a) ne ref($b); - if ( ref $a eq 'ARRAY' ) { + if (ref $a eq 'ARRAY') { return $b unless $sigil; - if ( $sigil eq '+' ) { + if ($sigil eq '+') { for my $e (@$b) { - push @$a, $e unless grep { eq_deeply( $_, $e ) } @$a; + push @$a, $e unless grep { eq_deeply($_, $e) } @$a; } } else { $a = [ grep { my $e = $_; - !grep { eq_deeply( $_, $e ) } @$b + !grep { eq_deeply($_, $e) } @$b } @$a ]; } return $a; } - elsif ( ref $a eq 'HASH' ) { - for my $k ( keys %$b ) { + elsif (ref $a eq 'HASH') { + for my $k (keys %$b) { # If the key is an array then look for a merge sigil my $s = ref($b->{$k}) eq 'ARRAY' && $k =~ s/^(\+|\-)// ? $1 : ''; $a->{$k} = - exists $a->{$k} - ? _merge( $a->{$k}, $b->{"$s$k"}, $s ) - : $b->{$k}; + exists $a->{$k} + ? _merge($a->{$k}, $b->{"$s$k"}, $s) + : $b->{$k}; } return $a; diff --git a/lib/Kelp/Module/Config/Null.pm b/lib/Kelp/Module/Config/Null.pm index d19de90..69b7d07 100644 --- a/lib/Kelp/Module/Config/Null.pm +++ b/lib/Kelp/Module/Config/Null.pm @@ -3,7 +3,8 @@ use Kelp::Base 'Kelp::Module::Config'; attr ext => 'null'; -sub load { +sub load +{ return { injected => 1 }; diff --git a/lib/Kelp/Module/JSON.pm b/lib/Kelp/Module/JSON.pm index e123fd2..ea9af9b 100644 --- a/lib/Kelp/Module/JSON.pm +++ b/lib/Kelp/Module/JSON.pm @@ -4,13 +4,14 @@ use Kelp::Base 'Kelp::Module'; use JSON::MaybeXS; -sub build { - my ( $self, %args ) = @_; +sub build +{ + my ($self, %args) = @_; my $json = JSON::MaybeXS->new(%args); my $json_internal = JSON::MaybeXS->new(%args, utf8 => 0); - $self->register( json => $json ); - $self->register( _json_internal => $json_internal ); + $self->register(json => $json); + $self->register(_json_internal => $json_internal); } 1; diff --git a/lib/Kelp/Module/Logger.pm b/lib/Kelp/Module/Logger.pm index abf12bb..553e05b 100644 --- a/lib/Kelp/Module/Logger.pm +++ b/lib/Kelp/Module/Logger.pm @@ -6,13 +6,15 @@ use Carp; use Log::Dispatch; use Data::Dumper; -sub _logger { - my ( $self, %args ) = @_; +sub _logger +{ + my ($self, %args) = @_; Log::Dispatch->new(%args); } -sub build { - my ( $self, %args ) = @_; +sub build +{ + my ($self, %args) = @_; $self->{logger} = $self->_logger(%args); # Register a few levels @@ -23,7 +25,7 @@ sub build { my $level = $_; $level => sub { shift; - $self->message( $level, @_ ); + $self->message($level, @_); }; } @levels_to_register; @@ -31,15 +33,18 @@ sub build { $self->register(%LEVELS); # Also register the message method as 'logger' - $self->register( logger => sub { - shift; - $self->message(@_); - }); + $self->register( + logger => sub { + shift; + $self->message(@_); + } + ); } -sub message { - my ( $self, $level, @messages ) = @_; - my @a = localtime(time); +sub message +{ + my ($self, $level, @messages) = @_; + my @a = localtime(time); my $date = sprintf( "%4i-%02i-%02i %02i:%02i:%02i", $a[5] + 1900, @@ -49,9 +54,11 @@ sub message { for (@messages) { $self->{logger}->log( - level => $level, - message => sprintf( '%s - %s - %s', - $date, $level, ref($_) ? Dumper($_) : $_ ) + level => $level, + message => sprintf( + '%s - %s - %s', + $date, $level, ref($_) ? Dumper($_) : $_ + ) ); } } diff --git a/lib/Kelp/Module/Logger/Simple.pm b/lib/Kelp/Module/Logger/Simple.pm index b818963..85156f0 100644 --- a/lib/Kelp/Module/Logger/Simple.pm +++ b/lib/Kelp/Module/Logger/Simple.pm @@ -2,15 +2,16 @@ package Kelp::Module::Logger::Simple; use Kelp::Base 'Kelp::Module::Logger'; use Plack::Util; -sub _logger { - my ( $self, %args ) = @_; +sub _logger +{ + my ($self, %args) = @_; return $self->SUPER::_logger( outputs => [ [ 'Screen', min_level => $args{min_level} // 'debug', - newline => 1, - stderr => 1 + newline => 1, + stderr => 1 ] ] ); diff --git a/lib/Kelp/Module/Null.pm b/lib/Kelp/Module/Null.pm index 983d999..578d57b 100644 --- a/lib/Kelp/Module/Null.pm +++ b/lib/Kelp/Module/Null.pm @@ -1,9 +1,10 @@ package Kelp::Module::Null; use Kelp::Base 'Kelp::Module'; -sub build { - my ( $self, %args ) = @_; - $self->register( plus => sub { $_[1] + $args{number} } ); +sub build +{ + my ($self, %args) = @_; + $self->register(plus => sub { $_[1] + $args{number} }); } 1; diff --git a/lib/Kelp/Module/Routes.pm b/lib/Kelp/Module/Routes.pm index 0a166fa..b5e84e5 100644 --- a/lib/Kelp/Module/Routes.pm +++ b/lib/Kelp/Module/Routes.pm @@ -5,19 +5,20 @@ use Plack::Util; my $DEFAULT_ROUTER = 'Kelp::Routes'; -sub build { - my ( $self, %args ) = @_; +sub build +{ + my ($self, %args) = @_; my $router = delete($args{router}) // ('+' . $DEFAULT_ROUTER); - my $router_class = Plack::Util::load_class( $router, $DEFAULT_ROUTER ); - my $r = $router_class->new( %args ); + my $router_class = Plack::Util::load_class($router, $DEFAULT_ROUTER); + my $r = $router_class->new(%args); # Register two methods: # * routes - contains the routes instance # * add_route - a shortcut to the 'add' method $self->register( - routes => $r, + routes => $r, add_route => sub { my $app = shift; return $r->add(@_); diff --git a/lib/Kelp/Module/Template.pm b/lib/Kelp/Module/Template.pm index e458cae..3fda622 100644 --- a/lib/Kelp/Module/Template.pm +++ b/lib/Kelp/Module/Template.pm @@ -6,36 +6,40 @@ use Kelp::Template; attr ext => 'tt'; attr engine => sub { die "'engine' must be initialized" }; -sub build { - my ( $self, %args ) = @_; +sub build +{ + my ($self, %args) = @_; # Build and initialize the engine attribute - $self->engine( $self->build_engine(%args) ); + $self->engine($self->build_engine(%args)); # Register one method - template $self->register( template => sub { - my ( $app, $template, $vars, @rest ) = @_; + my ($app, $template, $vars, @rest) = @_; $vars //= {}; $vars->{app} //= $app; - return $self->render( $self->_rename($template), $vars, @rest ); + return $self->render($self->_rename($template), $vars, @rest); } ); } -sub build_engine { - my ( $self, %args ) = @_; - return Kelp::Template->new( %args ); +sub build_engine +{ + my ($self, %args) = @_; + return Kelp::Template->new(%args); } -sub render { - my ( $self, $template, $vars ) = @_; - return $self->engine->process( $template, $vars ); +sub render +{ + my ($self, $template, $vars) = @_; + return $self->engine->process($template, $vars); } -sub _rename { - my ( $self, $name ) = @_; +sub _rename +{ + my ($self, $name) = @_; $name //= ''; return undef unless length $name; diff --git a/lib/Kelp/Module/Template/Null.pm b/lib/Kelp/Module/Template/Null.pm index b7fce3d..85ebfb5 100644 --- a/lib/Kelp/Module/Template/Null.pm +++ b/lib/Kelp/Module/Template/Null.pm @@ -4,13 +4,15 @@ use Plack::Util; attr ext => 'null'; -sub build_engine { - my ( $self, %args ) = @_; - Plack::Util::inline_object( render => sub { "All the ducks" } ); +sub build_engine +{ + my ($self, %args) = @_; + Plack::Util::inline_object(render => sub { "All the ducks" }); } -sub render { - my ( $self, $template, $vars, @rest ) = @_; +sub render +{ + my ($self, $template, $vars, @rest) = @_; $self->engine->render(); } diff --git a/lib/Kelp/Request.pm b/lib/Kelp/Request.pm index 6de2eff..bff83e7 100644 --- a/lib/Kelp/Request.pm +++ b/lib/Kelp/Request.pm @@ -20,188 +20,210 @@ attr route_name => sub { undef }; attr query_parameters => sub { my $self = shift; - my $raw = $self->_charset_decode_array( $self->_query_parameters ); + my $raw = $self->_charset_decode_array($self->_query_parameters); return Hash::MultiValue->new(@{$raw}); }; attr body_parameters => sub { my $self = shift; - my $raw = $self->_charset_decode_array( $self->_body_parameters ); + my $raw = $self->_charset_decode_array($self->_body_parameters); return Hash::MultiValue->new(@{$raw}); }; attr parameters => sub { my $self = shift; - my $raw_query = $self->_charset_decode_array( $self->_query_parameters ); - my $raw_body = $self->_charset_decode_array( $self->_body_parameters ); + my $raw_query = $self->_charset_decode_array($self->_query_parameters); + my $raw_body = $self->_charset_decode_array($self->_body_parameters); return Hash::MultiValue->new(@{$raw_query}, @{$raw_body}); }; # Raw methods - methods in Plack::Request (without decoding) # in Kelp::Request, they are replaced with decoding versions -sub raw_path { +sub raw_path +{ my $self = shift; - return $self->SUPER::path( @_ ); + return $self->SUPER::path(@_); } -sub raw_body { +sub raw_body +{ my $self = shift; - return $self->SUPER::content( @_ ); + return $self->SUPER::content(@_); } -sub raw_body_parameters { +sub raw_body_parameters +{ my $self = shift; - return $self->SUPER::body_parameters( @_ ); + return $self->SUPER::body_parameters(@_); } -sub raw_query_parameters { +sub raw_query_parameters +{ my $self = shift; - return $self->SUPER::query_parameters( @_ ); + return $self->SUPER::query_parameters(@_); } -sub raw_parameters { +sub raw_parameters +{ my $self = shift; - return $self->SUPER::parameters( @_ ); + return $self->SUPER::parameters(@_); } # If you're running the web app as a proxy, use Plack::Middleware::ReverseProxy -sub address { $_[0]->env->{REMOTE_ADDR} } +sub address { $_[0]->env->{REMOTE_ADDR} } sub remote_host { $_[0]->env->{REMOTE_HOST} } -sub user { $_[0]->env->{REMOTE_USER} } +sub user { $_[0]->env->{REMOTE_USER} } # Interface -sub new { - my ( $class, %args ) = @_; - my $self = $class->SUPER::new( delete $args{env} ); +sub new +{ + my ($class, %args) = @_; + my $self = $class->SUPER::new(delete $args{env}); $self->{$_} = $args{$_} for keys %args; return $self; } -sub is_ajax { +sub is_ajax +{ my $self = shift; return 0 unless my $with = $self->headers->header('X-Requested-With'); return $with =~ m{XMLHttpRequest}i; } -sub is_json { +sub is_json +{ my $self = shift; return 0 unless $self->content_type; return $self->content_type =~ m{^application/json}i; } -sub charset { +sub charset +{ my $self = shift; # charset must be supported by Encode - state $supported = { map { lc $_ => $_ } Encode->encodings(':all') }; + state $supported = {map { lc $_ => $_ } Encode->encodings(':all')}; return undef unless $self->content_type; return undef unless $self->content_type =~ m{;\s*charset=([^;\$]+)}i; return $supported->{lc $1}; } -sub charset_encode { - my ( $self, $string ) = @_; +sub charset_encode +{ + my ($self, $string) = @_; # Worst case scenario is a server error with code 500 return encode $self->charset, $string if $self->charset; - return $self->app->charset_encode($string) + return $self->app->charset_encode($string); } -sub charset_decode { - my ( $self, $string ) = @_; +sub charset_decode +{ + my ($self, $string) = @_; # Worst case scenario is a server error with code 500 return decode $self->charset, $string if $self->charset; - return $self->app->charset_decode($string) + return $self->app->charset_decode($string); } -sub _charset_decode_array { - my ( $self, $arr ) = @_; - return [ map { $self->charset_decode($_) } @$arr ]; +sub _charset_decode_array +{ + my ($self, $arr) = @_; + return [map { $self->charset_decode($_) } @$arr]; } -sub path { +sub path +{ my $self = shift; - return $self->charset_decode( $self->SUPER::path( @_ ) ); + return $self->charset_decode($self->SUPER::path(@_)); } -sub content { +sub content +{ my $self = shift; - return $self->charset_decode( $self->SUPER::content( @_ ) ); + return $self->charset_decode($self->SUPER::content(@_)); } -sub json_content { +sub json_content +{ my $self = shift; return undef unless $self->is_json; return try { - $self->app->_json_internal->decode( $self->content ); + $self->app->_json_internal->decode($self->content); } catch { undef; }; } -sub param { +sub param +{ my $self = shift; - if ( $self->is_json && $self->app->can('json') ) { - return $self->json_param( @_ ); + if ($self->is_json && $self->app->can('json')) { + return $self->json_param(@_); } # safe method without calling Plack::Request::param return $self->parameters->get($_[0]) if @_; - return keys %{ $self->parameters }; + return keys %{$self->parameters}; } -sub cgi_param { - shift->SUPER::param( @_ ); +sub cgi_param +{ + shift->SUPER::param(@_); } -sub query_param { +sub query_param +{ my $self = shift; return $self->query_parameters->get($_[0]) if @_; - return keys %{ $self->query_parameters }; + return keys %{$self->query_parameters}; } -sub body_param { +sub body_param +{ my $self = shift; return $self->body_parameters->get($_[0]) if @_; - return keys %{ $self->body_parameters }; + return keys %{$self->body_parameters}; } -sub json_param { +sub json_param +{ my $self = shift; my $hash = $self->{_param_json_content} //= do { my $hash = $self->json_content // {}; - ref $hash eq 'HASH' ? $hash : { ref $hash, $hash }; + ref $hash eq 'HASH' ? $hash : {ref $hash, $hash}; }; - return $hash->{ $_[0] } if @_; + return $hash->{$_[0]} if @_; if (!wantarray) { - carp "param() called in scalar context on json request is deprecated and will return the number of keys in the future. Use json_content instead"; + carp + "param() called in scalar context on json request is deprecated and will return the number of keys in the future. Use json_content instead"; return $hash; } return keys %$hash; } -sub session { - my $self = shift; +sub session +{ + my $self = shift; my $session = $self->env->{'psgix.session'} - // croak "No Session middleware wrapped"; + // croak "No Session middleware wrapped"; return $session if !@_; - if ( @_ == 1 ) { + if (@_ == 1) { my $value = shift; return $session->{$value} unless ref $value; return $self->env->{'psgix.session'} = $value; diff --git a/lib/Kelp/Response.pm b/lib/Kelp/Response.pm index 463e5b6..385d831 100644 --- a/lib/Kelp/Response.pm +++ b/lib/Kelp/Response.pm @@ -9,23 +9,26 @@ use HTTP::Status qw(status_message); attr -app => sub { croak "app is required" }; attr rendered => 0; -attr partial => 0; +attr partial => 0; -sub new { - my ( $class, %args ) = @_; +sub new +{ + my ($class, %args) = @_; my $self = $class->SUPER::new(); $self->{$_} = $args{$_} for keys %args; return $self; } -sub set_content_type { - my ( $self, $type ) = @_; - $self->content_type( $type ); +sub set_content_type +{ + my ($self, $type) = @_; + $self->content_type($type); return $self; } -sub set_charset { - my ( $self, $charset ) = @_; +sub set_charset +{ + my ($self, $charset) = @_; $charset //= $self->app->charset; my $ct = $self->content_type; @@ -38,56 +41,65 @@ sub set_charset { return $self; } -sub text { +sub text +{ my $self = shift; - return $self->set_content_type( 'text/plain' )->set_charset; + return $self->set_content_type('text/plain')->set_charset; } -sub html { +sub html +{ my $self = shift; - return $self->set_content_type( 'text/html' )->set_charset; + return $self->set_content_type('text/html')->set_charset; } -sub json { +sub json +{ my $self = shift; - return $self->set_content_type( 'application/json' ); + return $self->set_content_type('application/json'); } -sub xml { +sub xml +{ my $self = shift; - return $self->set_content_type( 'application/xml' ); + return $self->set_content_type('application/xml'); } -sub finalize { +sub finalize +{ my $self = shift; - my $arr = $self->SUPER::finalize(@_); + my $arr = $self->SUPER::finalize(@_); pop @$arr if $self->partial; return $arr; } -sub set_header { +sub set_header +{ my $self = shift; $self->SUPER::header(@_); return $self; } -sub no_cache { +sub no_cache +{ my $self = shift; - $self->set_header( 'Cache-Control' => 'no-cache, no-store, must-revalidate' ); - $self->set_header( 'Pragma' => 'no-cache' ); - $self->set_header( 'Expires' => '0' ); + $self->set_header('Cache-Control' => 'no-cache, no-store, must-revalidate'); + $self->set_header('Pragma' => 'no-cache'); + $self->set_header('Expires' => '0'); return $self; } -sub set_code { +sub set_code +{ my $self = shift; $self->SUPER::code(@_); return $self; } -sub render { - my ( $self, $body ) = @_; +sub render +{ + my ($self, $body) = @_; my $ct = $self->content_type; my $ref = ref $body; @@ -95,30 +107,32 @@ sub render { $self->set_code(200) unless $self->code; # If the content has been determined as JSON, then encode it - if ( $ref && (!$ct || $ct =~ m{^application/json}i) ) { + if ($ref && (!$ct || $ct =~ m{^application/json}i)) { croak "No JSON encoder" unless $self->app->can('_json_internal'); $body = $self->app->_json_internal->encode($body); $self->json if !$ct; - } elsif ( !$ref ) { + } + elsif (!$ref) { $self->html if !$ct; } else { croak "Don't know how to handle non-json reference in response (forgot to serialize?)"; } - $self->body( $self->app->charset_encode( $body ) ); + $self->body($self->app->charset_encode($body)); $self->rendered(1); return $self; } -sub render_binary { - my ( $self, $body ) = @_; +sub render_binary +{ + my ($self, $body) = @_; $body //= ''; # Set code 200 if the code has not been set $self->set_code(200) unless $self->code; - if ( !$self->content_type ) { + if (!$self->content_type) { croak "Content-type must be explicitly set for binaries"; } @@ -127,17 +141,18 @@ sub render_binary { return $self; } -sub render_error { - my ( $self, $code, $error ) = @_; +sub render_error +{ + my ($self, $code, $error) = @_; - $code //= 500; + $code //= 500; $error //= status_message($code) // 'Error'; $self->set_code($code); # Look for a template and if not found, then show a generic text try { - local $SIG{__DIE__}; # Silence StackTrace + local $SIG{__DIE__}; # Silence StackTrace $self->template( "error/$code", { error => $error @@ -151,8 +166,9 @@ sub render_error { return $self; } -sub render_exception { - my ( $self, $exception ) = @_; +sub render_exception +{ + my ($self, $exception) = @_; # If the error is 500, do the same thing normal errors do: provide more # info on non-production @@ -162,23 +178,27 @@ sub render_exception { return $self->render_error($exception->code); } -sub render_401 { - $_[0]->render_error( 401 ); +sub render_401 +{ + $_[0]->render_error(401); } -sub render_403 { - $_[0]->render_error( 403 ); +sub render_403 +{ + $_[0]->render_error(403); } -sub render_404 { - $_[0]->render_error( 404 ); +sub render_404 +{ + $_[0]->render_error(404); } -sub render_500 { - my ( $self, $error ) = @_; +sub render_500 +{ + my ($self, $error) = @_; # Do not leak information on production! - if ( $self->app->is_production ) { + if ($self->app->is_production) { return $self->render_error; } @@ -192,26 +212,29 @@ sub render_500 { return $self->render_error(500, $error); } -sub redirect { +sub redirect +{ my $self = shift; $self->rendered(1); $self->SUPER::redirect(@_); } -sub redirect_to { - my ( $self, $where, $args, $code ) = @_; +sub redirect_to +{ + my ($self, $where, $args, $code) = @_; my $url = $self->app->url_for($where, %$args); - $self->redirect( $url, $code ); + $self->redirect($url, $code); } -sub template { - my ( $self, $template, $vars, @rest ) = @_; +sub template +{ + my ($self, $template, $vars, @rest) = @_; # Do we have a template module loaded? croak "No template module loaded" unless $self->app->can('template'); - my $output = $self->app->template( $template, $vars, @rest ); + my $output = $self->app->template($template, $vars, @rest); $self->render($output); } diff --git a/lib/Kelp/Routes.pm b/lib/Kelp/Routes.pm index d282db7..2b6db10 100644 --- a/lib/Kelp/Routes.pm +++ b/lib/Kelp/Routes.pm @@ -9,12 +9,12 @@ use Kelp::Routes::Location; use Try::Tiny; use Class::Inspector; -attr base => ''; # the default is set by config module -attr rebless => 0; # do not rebless app by default -attr pattern_obj => 'Kelp::Routes::Pattern'; -attr fatal => 0; -attr routes => sub { [] }; -attr names => sub { {} }; +attr base => ''; # the default is set by config module +attr rebless => 0; # do not rebless app by default +attr pattern_obj => 'Kelp::Routes::Pattern'; +attr fatal => 0; +attr routes => sub { [] }; +attr names => sub { {} }; # Cache attr cache => sub { @@ -22,41 +22,45 @@ attr cache => sub { my %cache; Plack::Util::inline_object( - get => sub { $cache{ $_[0] } }, - set => sub { $cache{ $_[0] } = $_[1] }, + get => sub { $cache{$_[0]} }, + set => sub { $cache{$_[0]} = $_[1] }, clear => sub { %cache = () } ); }; -sub add { - my ( $self, $pattern, $descr, $parent ) = @_; +sub add +{ + my ($self, $pattern, $descr, $parent) = @_; $parent = {} if !$parent || ref $parent ne 'HASH'; - my $route = $self->_parse_route( $parent, $pattern, $descr ); + my $route = $self->_parse_route($parent, $pattern, $descr); return $self->_build_location($route); } -sub clear { - my ( $self ) = @_; +sub clear +{ + my ($self) = @_; - $self->routes( [] ); + $self->routes([]); $self->cache->clear; - $self->names( {} ); + $self->names({}); } -sub url { +sub url +{ my $self = shift; my $name = shift // croak "Route name is missing"; - my %args = @_ == 1 ? %{ $_[0] } : @_; + my %args = @_ == 1 ? %{$_[0]} : @_; return $name unless exists $self->names->{$name}; - my $route = $self->routes->[ $self->names->{$name} ]; + my $route = $self->routes->[$self->names->{$name}]; return $route->build(%args); } -sub _build_location { +sub _build_location +{ # build a specific location object on which ->add can be called again - my ( $self, $route ) = @_; + my ($self, $route) = @_; return Kelp::Routes::Location->new( router => $self, @@ -64,55 +68,59 @@ sub _build_location { ); } -sub _message { - my ( $self, $type_str, @parts ) = @_; +sub _message +{ + my ($self, $type_str, @parts) = @_; my $message = "[ROUTES] $type_str: "; for my $part (@parts) { $part //= ''; - $part =~ s/ at .+? line \d+.\n//g; # way prettier errors + $part =~ s/ at .+? line \d+.\n//g; # way prettier errors } - return $message . join ' - ', @parts;; + return $message . join ' - ', @parts; } -sub _error { - my ( $self, @parts ) = @_; +sub _error +{ + my ($self, @parts) = @_; - croak $self->_message( 'ERROR', @parts ) if $self->fatal; - carp $self->_message( 'WARNING, route is skipped', @parts ); + croak $self->_message('ERROR', @parts) if $self->fatal; + carp $self->_message('WARNING, route is skipped', @parts); return; } -sub _warning { - my ( $self, @parts ) = @_; +sub _warning +{ + my ($self, @parts) = @_; - carp $self->_message( 'WARNING', @parts ); + carp $self->_message('WARNING', @parts); } -sub _parse_route { - my ( $self, $parent, $key, $val ) = @_; +sub _parse_route +{ + my ($self, $parent, $key, $val) = @_; # Scalar, e.g. 'bar#foo' # CODE, e.g. sub { ... } - if ( !ref $val || ref $val eq 'CODE' ) { - $val = { to => $val }; + if (!ref $val || ref $val eq 'CODE') { + $val = {to => $val}; } # Sanity check - if ( ref $val ne 'HASH' ) { + if (ref $val ne 'HASH') { return $self->_error('Route description must be a string, CODE or HASH'); } # Handle key in form of [METHOD => 'pattern'] - if ( ref $key eq 'ARRAY' ) { - if ( ( grep { defined } @$key ) != 2 ) { - return $self->_error( "Path as an ARRAY is expected to have two parameters" ); + if (ref $key eq 'ARRAY') { + if ((grep { defined } @$key) != 2) { + return $self->_error("Path as an ARRAY is expected to have two parameters"); } - my ( $method, $pattern ) = @$key; - if ( !grep { $method eq $_ } qw/GET POST PUT DELETE/ ) { - $self->_warning( "Using an odd method '$method'" ); + my ($method, $pattern) = @$key; + if (!grep { $method eq $_ } qw/GET POST PUT DELETE/) { + $self->_warning("Using an odd method '$method'"); } $val->{method} = $method; @@ -120,8 +128,8 @@ sub _parse_route { } # Only SCALAR and Regexp allowed - if ( ref $key && ref $key ne 'Regexp' ) { - return $self->_error( "Pattern '$key' can not be computed" ); + if (ref $key && ref $key ne 'Regexp') { + return $self->_error("Pattern '$key' can not be computed"); } $val->{pattern} = $key; @@ -129,101 +137,105 @@ sub _parse_route { # Format and load the target of 'to' my $error; try { - $val->{to} = $self->format_to( $val->{to} ); - $val->{dest} = $self->load_destination( $val->{to} ); + $val->{to} = $self->format_to($val->{to}); + $val->{dest} = $self->load_destination($val->{to}); } catch { $error = $_; }; - if ( !defined $val->{dest} || $error ) { - return $self->_error( "Invalid destination for route '$key'", $error ); + if (!defined $val->{dest} || $error) { + return $self->_error("Invalid destination for route '$key'", $error); } # store tree for later and set up bridge based on it my $tree = delete $val->{tree}; if ($tree && (ref $tree ne 'ARRAY' || @$tree % 2 != 0)) { - return $self->_error( "Tree must be an even-sized ARRAY" ); + return $self->_error("Tree must be an even-sized ARRAY"); } $val->{bridge} ||= defined $tree; # psgi + bridge is incompatible, as psgi route will only render (not return true values) - if ( $val->{psgi} && $val->{bridge} ) { - return $self->_error( "Route '$key' cannot have both 'psgi' and 'bridge'" ); + if ($val->{psgi} && $val->{bridge}) { + return $self->_error("Route '$key' cannot have both 'psgi' and 'bridge'"); } # Adjust the destination for psgi - $val->{dest} = $self->wrap_psgi( $val->{to}, $val->{dest} ) + $val->{dest} = $self->wrap_psgi($val->{to}, $val->{dest}) if $val->{psgi}; # Credit stuff from tree parent, if possible - if ( defined $parent->{pattern} ) { - if ( $val->{name} && $parent->{name} ) { + if (defined $parent->{pattern}) { + if ($val->{name} && $parent->{name}) { $val->{name} = $parent->{name} . '_' . $val->{name}; } $val->{pattern} = $parent->{pattern} . $val->{pattern}; } # Can now add the object to routes - my $route = $self->build_pattern( $val ); - push @{ $self->routes }, $route; + my $route = $self->build_pattern($val); + push @{$self->routes}, $route; # Add route index to names - if ( my $name = $val->{name} ) { - if ( exists $self->names->{$name} ) { - $self->_warning( "Multiple routes named '$name'" ); + if (my $name = $val->{name}) { + if (exists $self->names->{$name}) { + $self->_warning("Multiple routes named '$name'"); } - $self->names->{$name} = $#{ $self->routes }; + $self->names->{$name} = $#{$self->routes}; } # handle further tree levels, if any $tree //= []; while (@$tree) { - my ( $k, $v ) = splice( @$tree, 0, 2 ); - $self->_parse_route( $val, $k, $v ); + my ($k, $v) = splice(@$tree, 0, 2); + $self->_parse_route($val, $k, $v); } return $route; } # Override to change what 'to' values are valid -sub format_to { - my ( $self, $to ) = @_; +sub format_to +{ + my ($self, $to) = @_; my $ref = ref $to; - if ( !defined $to ) { + if (!defined $to) { croak 'missing'; } - elsif ( !$to || ( $ref && $ref ne 'CODE' ) ) { + elsif (!$to || ($ref && $ref ne 'CODE')) { croak 'neither a string nor a coderef'; } - $to = Kelp::Util::camelize( $to, $self->base ) + $to = Kelp::Util::camelize($to, $self->base) unless $ref; return $to; } # Override to change the way the application loads the destination from 'to' -sub load_destination { - my ( $self, $to ) = @_; +sub load_destination +{ + my ($self, $to) = @_; my $ref = ref $to; - if ( !$ref && $to ) { + if (!$ref && $to) { + # Load the class, if there is one - if ( my $class = Kelp::Util::extract_class( $to ) ) { - my $method = Kelp::Util::extract_function( $to ); + if (my $class = Kelp::Util::extract_class($to)) { + my $method = Kelp::Util::extract_function($to); - Plack::Util::load_class( $class ) - unless Class::Inspector->loaded( $class ); + Plack::Util::load_class($class) + unless Class::Inspector->loaded($class); - my $method_code = $class->can( $method ); + my $method_code = $class->can($method); croak "method '$method' does not exist in class '$class'" unless $method_code; - return [$self->rebless && $class->isa( $self->base ) ? $class : undef, $method_code]; + return [$self->rebless && $class->isa($self->base) ? $class : undef, $method_code]; } - elsif ( exists &$to ) { + elsif (exists &$to) { + # Move to reference return [undef, \&{$to}]; } @@ -231,7 +243,7 @@ sub load_destination { croak "function '$to' does not exist"; } } - elsif ( $ref ) { + elsif ($ref) { croak "don't know how to load from reftype '$ref'" unless $ref eq 'CODE'; @@ -242,8 +254,9 @@ sub load_destination { } # Override to change the way a psgi application is adapted to kelp -sub wrap_psgi { - my ( $self, $to, $destination ) = @_; +sub wrap_psgi +{ + my ($self, $to, $destination) = @_; # adjust the subroutine to load # don't adjust the controller (index 0) to still call the proper hooks if @@ -254,23 +267,26 @@ sub wrap_psgi { } # Override to use a custom pattern object -sub build_pattern { - my ( $self, $args ) = @_; +sub build_pattern +{ + my ($self, $args) = @_; my $package = $self->pattern_obj; eval qq{require $package}; - return $package->new( %$args ); + return $package->new(%$args); } -sub match { - my ( $self, $path, $method ) = @_; +sub match +{ + my ($self, $path, $method) = @_; $method //= ''; # Look for this path and method in the cache. If found, # return the array of routes that matched the previous time. # If not found, then return all routes. my $key = "$path:$method"; - my $routes = $self->cache->get( $key ); - if ( !defined $routes ) { + my $routes = $self->cache->get($key); + if (!defined $routes) { + # Look through all routes, grep the ones that match and sort them by # 'bridge' and 'pattern'. Perl sort function is stable, meaning it will # preserve the initial order of records it considers equal. This means @@ -281,36 +297,37 @@ sub match { # by string sorting by patterns. @$routes = sort { $b->bridge <=> $a->bridge || $a->pattern cmp $b->pattern } - grep { $_->match( $path, $method ) } @{ $self->routes }; + grep { $_->match($path, $method) } @{$self->routes}; - $self->cache->set( $key, $routes ); + $self->cache->set($key, $routes); } else { # matching fills the route parameters - $_->match( $path, $method ) for @$routes; + $_->match($path, $method) for @$routes; } # shallow copy to make sure nothing pollutes the cache - return [ @$routes ]; + return [@$routes]; } # dispatch does not do many sanity checks on the destination, since those are # done in format_to and load_destination. A single check is present, which # lazy-computes dest if it is not set (since some code might have overrode add). -sub dispatch { - my ( $self, $app, $route ) = @_; - $app || die "Application instance required"; +sub dispatch +{ + my ($self, $app, $route) = @_; + $app || die "Application instance required"; $route || die "No route pattern instance supplied"; my $dest = $route->dest; - $route->dest( $self->load_destination( $route->to ) ) + $route->dest($self->load_destination($route->to)) unless $dest; - my ( $to, $controller, $action ) = ( $route->to, @{ $dest } ); - $app = $app->_clone( $controller ) if $controller; + my ($to, $controller, $action) = ($route->to, @{$dest}); + $app = $app->_clone($controller) if $controller; - $app->before_dispatch( $to ); - return $action->( $app, @{ $route->param } ); + $app->before_dispatch($to); + return $action->($app, @{$route->param}); } 1; diff --git a/lib/Kelp/Routes/Location.pm b/lib/Kelp/Routes/Location.pm index 6a4f1ce..1eb9771 100644 --- a/lib/Kelp/Routes/Location.pm +++ b/lib/Kelp/Routes/Location.pm @@ -6,8 +6,9 @@ use Carp; attr 'router' => sub { croak 'router is required' }; attr 'parent' => sub { croak 'parent is required' }; -sub add { - my ( $self, $pattern, $descr, $parent_data ) = @_; +sub add +{ + my ($self, $pattern, $descr, $parent_data) = @_; my $parent = $self->parent; croak "Cannot chain 'add' calls because the parent route was not parsed correctly" @@ -21,7 +22,7 @@ sub add { # parent is a bridge now (even if the add call fails) $parent->bridge(1); - return $self->router->add( $pattern, $descr, $parent_data ); + return $self->router->add($pattern, $descr, $parent_data); } 1; diff --git a/lib/Kelp/Routes/Pattern.pm b/lib/Kelp/Routes/Pattern.pm index dac3e9c..990b6bf 100644 --- a/lib/Kelp/Routes/Pattern.pm +++ b/lib/Kelp/Routes/Pattern.pm @@ -4,39 +4,52 @@ use Carp; use Kelp::Base; -attr pattern => sub { die "pattern is required" }; -attr via => undef; -attr method => sub { $_[0]->via }; +attr pattern => sub { die "pattern is required" }; +attr via => undef; +attr method => sub { $_[0]->via }; attr has_name => undef; -attr name => sub { $_[0]->pattern }; -attr check => sub { {} }; +attr name => sub { $_[0]->pattern }; +attr check => sub { {} }; attr defaults => sub { {} }; -attr bridge => 0; -attr regex => sub { $_[0]->_build_regex }; -attr named => sub { {} }; -attr param => sub { [] }; -attr to => undef; -attr dest => undef; +attr bridge => 0; +attr regex => sub { $_[0]->_build_regex }; +attr named => sub { {} }; +attr param => sub { [] }; +attr to => undef; +attr dest => undef; # helpers for matching different types of wildcards -sub __noslash { 1 == grep { $_[0] eq $_ } ':', '?' } -sub __matchall { 1 == grep { $_[0] eq $_ } '*', '>' } -sub __optional { 1 == grep { $_[0] eq $_ } '?', '>' } +sub __noslash +{ + 1 == grep { $_[0] eq $_ } ':', '?'; +} + +sub __matchall +{ + 1 == grep { $_[0] eq $_ } '*', '>'; +} + +sub __optional +{ + 1 == grep { $_[0] eq $_ } '?', '>'; +} -sub new { +sub new +{ my $class = shift; my $self = $class->SUPER::new(@_); - $self->has_name(defined $self->{name} && length $self->{name}); # remember if pattern was named + $self->has_name(defined $self->{name} && length $self->{name}); # remember if pattern was named $self->_fix_pattern; - $self->regex; # Compile the regex + $self->regex; # Compile the regex return $self; } -sub _fix_pattern { - my ( $self ) = @_; +sub _fix_pattern +{ + my ($self) = @_; my $pattern = $self->pattern; - return if ref $pattern; # only fix non-regex patterns + return if ref $pattern; # only fix non-regex patterns # operations performed $pattern =~ s{/+}{/}g; @@ -44,8 +57,9 @@ sub _fix_pattern { $self->pattern($pattern); } -sub _rep_regex { - my ( $self, $char, $switch, $token ) = @_; +sub _rep_regex +{ + my ($self, $char, $switch, $token) = @_; my $re; my $optional = sub { @@ -55,7 +69,7 @@ sub _rep_regex { }; # no token - only valid for the wildcard * and slurpy > - if ( !defined $token ) { + if (!defined $token) { # do nothing return $char . $switch @@ -66,12 +80,12 @@ sub _rep_regex { else { push @{$self->{_tokens}}, $token; - my ( $prefix, $suffix ) = ( "(?<$token>", ')' ); - if ( __noslash($switch) ) { - $re = $char . $prefix . ( $self->check->{$token} // '[^\/]+' ) . $suffix; + my ($prefix, $suffix) = ("(?<$token>", ')'); + if (__noslash($switch)) { + $re = $char . $prefix . ($self->check->{$token} // '[^\/]+') . $suffix; } - elsif ( __matchall($switch) ) { - $re = $char . $prefix . ( $self->check->{$token} // '.+' ) . $suffix; + elsif (__matchall($switch)) { + $re = $char . $prefix . ($self->check->{$token} // '.+') . $suffix; } } @@ -79,14 +93,15 @@ sub _rep_regex { return $re; } -sub _build_regex { +sub _build_regex +{ my $self = shift; $self->{_tokens} = []; return $self->pattern if ref $self->pattern eq 'Regexp'; my $PAT = '(.?)([:*?>])(\w+)?'; - my $pattern = $self->pattern; + my $pattern = $self->pattern; # Curly braces and brackets are only used for separation. # We replace all of them with \0, then convert the pattern @@ -101,8 +116,9 @@ sub _build_regex { return qr{^$pattern}; } -sub _rep_build { - my ( $self, $switch, $token, %args ) = @_; +sub _rep_build +{ + my ($self, $switch, $token, %args) = @_; if (!defined $token) { return $switch unless __matchall($switch); @@ -110,23 +126,24 @@ sub _rep_build { } my $rep = $args{$token} // $self->defaults->{$token} // ''; - if ( !__optional($switch) && !$rep) { + if (!__optional($switch) && !$rep) { return '{?' . $token . '}'; } my $check = $self->check->{$token}; - if ( $check && $args{$token} !~ $check ) { + if ($check && $args{$token} !~ $check) { return '{!' . $token . '}'; } return $rep; } -sub build { - my ( $self, %args ) = @_; +sub build +{ + my ($self, %args) = @_; my $pattern = $self->pattern; - if ( ref $pattern eq 'Regexp' ) { + if (ref $pattern eq 'Regexp') { carp "Can't build a path for regular expressions"; return; } @@ -142,29 +159,31 @@ sub build { return $pattern; } -sub match { - my ( $self, $path, $method ) = @_; - return 0 if ( $self->method && $self->method ne ( $method // '' ) ); +sub match +{ + my ($self, $path, $method) = @_; + return 0 if ($self->method && $self->method ne ($method // '')); return 0 unless my @matched = $path =~ $self->regex; - my $has_matches = $#+; # see perlvar @+ + my $has_matches = $#+; # see perlvar @+ # Initialize the named parameters hash and its default values - my %named = ( %{ $self->defaults }, %+ ); + my %named = (%{$self->defaults}, %+); + + if (@{$self->{_tokens}}) { - if ( @{ $self->{_tokens} } ) { # values of the named placeholders in the order they appear in the # regex. - @matched = map { $named{$_} } @{ $self->{_tokens} }; + @matched = map { $named{$_} } @{$self->{_tokens}}; } - elsif ( $has_matches ) { + elsif ($has_matches) { @matched = map { length($_ // '') ? $_ : undef } @matched; } else { @matched = (); } - $self->named( \%named ); - $self->param( \@matched ); + $self->named(\%named); + $self->param(\@matched); return 1; } diff --git a/lib/Kelp/Template.pm b/lib/Kelp/Template.pm index 1c5c0ee..4647231 100644 --- a/lib/Kelp/Template.pm +++ b/lib/Kelp/Template.pm @@ -9,33 +9,35 @@ attr paths => sub { [] }; attr encoding => 'UTF-8'; attr tt => sub { Template::Tiny->new }; -sub process { - my ( $self, $template, $vars ) = @_; +sub process +{ + my ($self, $template, $vars) = @_; my $ref = ref $template; # A GLOB or an IO object will be read and returned as a SCALAR template # No reference means a file name - if ( !$ref ) { + if (!$ref) { $template = $self->_read_file($self->find_template($template)); } - elsif ( $ref =~ /^IO/ || $ref eq 'GLOB' ) { + elsif ($ref =~ /^IO/ || $ref eq 'GLOB') { $template = $self->_read_file($template); } - elsif ( $ref ne 'SCALAR' ) { + elsif ($ref ne 'SCALAR') { croak "Template reference must be SCALAR, GLOB or an IO object"; } my $output; - $self->tt->process( $template, $vars, \$output ); + $self->tt->process($template, $vars, \$output); return $output; } -sub find_template { - my ( $self, $name ) = @_; +sub find_template +{ + my ($self, $name) = @_; my $file; - for my $p ( '.', @{ $self->paths } ) { + for my $p ('.', @{$self->paths}) { $file = "$p/$name"; return $file if -e $file; } @@ -43,11 +45,12 @@ sub find_template { return undef; } -sub _read_file { - my ( $self, $file ) = @_; +sub _read_file +{ + my ($self, $file) = @_; my $text = ref $file ? <$file> : path($file)->slurp( - { binmode => ':encoding(' . $self->encoding . ')' } + {binmode => ':encoding(' . $self->encoding . ')'} ); return \$text; diff --git a/lib/Kelp/Test.pm b/lib/Kelp/Test.pm index 5ddd88f..f20d0fa 100644 --- a/lib/Kelp/Test.pm +++ b/lib/Kelp/Test.pm @@ -13,14 +13,15 @@ BEGIN { $ENV{KELP_TESTING} = 1; # Set the ENV for testing } -sub import { +sub import +{ my ($me, @args) = @_; if ($args[0] && $args[0] eq -utf8) { my $builder = Test::More->builder; - binmode $builder->output, ":encoding(utf8)"; + binmode $builder->output, ":encoding(utf8)"; binmode $builder->failure_output, ":encoding(utf8)"; - binmode $builder->todo_output, ":encoding(utf8)"; + binmode $builder->todo_output, ":encoding(utf8)"; } } @@ -29,18 +30,19 @@ attr -psgi => undef; attr -app => sub { my $self = shift; return defined $self->psgi - ? Plack::Util::load_psgi( $self->psgi ) - : die "'app' or 'psgi' parameter is required"; + ? Plack::Util::load_psgi($self->psgi) + : die "'app' or 'psgi' parameter is required"; }; -attr res => sub { die "res is not initialized" }; +attr res => sub { die "res is not initialized" }; attr cookies => sub { Kelp::Test::CookieJar->new }; -sub request { - my ( $self, $req ) = @_; +sub request +{ + my ($self, $req) = @_; croak "HTTP::Request object needed" unless ref($req) eq 'HTTP::Request'; - $self->note( $req->method . ' ' . $req->uri ); + $self->note($req->method . ' ' . $req->uri); # Most likely the request was not initialized with a URI that had a scheme, # so we add a default http to prevent unitialized regex matches further @@ -50,14 +52,14 @@ sub request { # If no host was given to the request's uri (most likely), then add # localhost. This is needed by the cookies header, which will not be # applied unless the request uri has a proper domain. - if ( $req->uri->opaque =~ qr|^/{1}| ) { - $req->uri->opaque( '//localhost' . $req->uri->opaque ); + if ($req->uri->opaque =~ qr|^/{1}|) { + $req->uri->opaque('//localhost' . $req->uri->opaque); } # Add the current cookie to the request headers $self->cookies->add_cookie_header($req); - my $res = test_psgi( $self->app->run, sub { shift->($req) } ); + my $res = test_psgi($self->app->run, sub { shift->($req) }); # Extract the cookies from the response and add them to the cookie jar $self->cookies->extract_cookies($res); @@ -66,30 +68,33 @@ sub request { return $self; } -sub request_ok { - my ( $self, $req, $test_name ) = @_; +sub request_ok +{ + my ($self, $req, $test_name) = @_; local $Test::Builder::Level = $Test::Builder::Level + 1; - $self->request($req)->code_is( 200, $test_name ); + $self->request($req)->code_is(200, $test_name); } -sub code_is { - my ( $self, $code, $test_name ) = @_; +sub code_is +{ + my ($self, $code, $test_name) = @_; local $Test::Builder::Level = $Test::Builder::Level + 1; $test_name ||= "Response code is $code"; is $self->res->code, $code, $test_name; # If we got 500 back and shouldn't have, we show the content - if ( $code != 500 && $self->res->code == 500 ) { + if ($code != 500 && $self->res->code == 500) { fail $self->res->content; } return $self; } -sub code_isnt { - my ( $self, $code, $test_name ) = @_; +sub code_isnt +{ + my ($self, $code, $test_name) = @_; local $Test::Builder::Level = $Test::Builder::Level + 1; $test_name ||= "Response code is not $code"; @@ -97,48 +102,53 @@ sub code_isnt { return $self; } -sub content_is { - my ( $self, $value, $test_name ) = @_; +sub content_is +{ + my ($self, $value, $test_name) = @_; local $Test::Builder::Level = $Test::Builder::Level + 1; $test_name ||= "Content is '$value'"; - is $self->app->charset_decode( $self->res->content ), $value, - $test_name; + is $self->app->charset_decode($self->res->content), $value, + $test_name; return $self; } -sub content_isnt { - my ( $self, $value, $test_name ) = @_; +sub content_isnt +{ + my ($self, $value, $test_name) = @_; local $Test::Builder::Level = $Test::Builder::Level + 1; $test_name ||= "Content is not '$value'"; - isnt $self->app->charset_decode( $self->res->content ), $value, - $test_name; + isnt $self->app->charset_decode($self->res->content), $value, + $test_name; return $self; } -sub content_like { - my ( $self, $regexp, $test_name ) = @_; +sub content_like +{ + my ($self, $regexp, $test_name) = @_; local $Test::Builder::Level = $Test::Builder::Level + 1; $test_name ||= "Content matches $regexp"; - like $self->app->charset_decode( $self->res->content ), $regexp, - $test_name; + like $self->app->charset_decode($self->res->content), $regexp, + $test_name; return $self; } -sub content_unlike { - my ( $self, $regexp, $test_name ) = @_; +sub content_unlike +{ + my ($self, $regexp, $test_name) = @_; local $Test::Builder::Level = $Test::Builder::Level + 1; $test_name ||= "Content does not match $regexp"; - unlike $self->app->charset_decode( $self->res->content ), $regexp, - $test_name; + unlike $self->app->charset_decode($self->res->content), $regexp, + $test_name; return $self; } -sub content_type_is { - my ( $self, $value, $test_name ) = @_; +sub content_type_is +{ + my ($self, $value, $test_name) = @_; local $Test::Builder::Level = $Test::Builder::Level + 1; $test_name ||= "Content-Type is '$value'"; @@ -146,8 +156,9 @@ sub content_type_is { return $self; } -sub content_type_isnt { - my ( $self, $value, $test_name ) = @_; +sub content_type_isnt +{ + my ($self, $value, $test_name) = @_; local $Test::Builder::Level = $Test::Builder::Level + 1; $test_name ||= "Content-Type is not '$value'"; @@ -155,52 +166,57 @@ sub content_type_isnt { return $self; } -sub header_is { - my ( $self, $header, $value, $test_name ) = @_; +sub header_is +{ + my ($self, $header, $value, $test_name) = @_; local $Test::Builder::Level = $Test::Builder::Level + 1; $test_name ||= "Header '$header' => '$value'"; is $self->res->header($header), $value, $test_name - || $self->diag_headers(); + || $self->diag_headers(); return $self; } -sub header_isnt { - my ( $self, $header, $value, $test_name ) = @_; +sub header_isnt +{ + my ($self, $header, $value, $test_name) = @_; local $Test::Builder::Level = $Test::Builder::Level + 1; $test_name ||= "Header '$header' is not '$value'"; isnt $self->res->header($header), $value, $test_name - || $self->diag_headers(); + || $self->diag_headers(); return $self; } -sub header_like { - my ( $self, $header, $regexp, $test_name ) = @_; +sub header_like +{ + my ($self, $header, $regexp, $test_name) = @_; local $Test::Builder::Level = $Test::Builder::Level + 1; $test_name ||= "Header '$header' =~ $regexp"; like $self->res->header($header), $regexp, $test_name - || $self->diag_headers(); + || $self->diag_headers(); return $self; } -sub header_unlike { - my ( $self, $header, $regexp, $test_name ) = @_; +sub header_unlike +{ + my ($self, $header, $regexp, $test_name) = @_; local $Test::Builder::Level = $Test::Builder::Level + 1; $test_name ||= "Header '$header' !~ $regexp"; unlike $self->res->header($header), $regexp, $test_name - || $self->diag_headers(); + || $self->diag_headers(); return $self; } -sub json_content { +sub json_content +{ my $self = shift; fail "No JSON decoder" unless $self->app->can('json'); my $result; try { - $result = $self->app->json->decode( $self->res->content ); + $result = $self->app->json->decode($self->res->content); } catch { fail("Poorly formatted JSON"); @@ -208,31 +224,35 @@ sub json_content { return $result; } -sub json_cmp { - my ( $self, $expected, $test_name ) = @_; +sub json_cmp +{ + my ($self, $expected, $test_name) = @_; local $Test::Builder::Level = $Test::Builder::Level + 1; $test_name ||= "JSON structure matches"; like $self->res->header('content-type'), qr/json/, 'Content-Type is JSON' - or return $self; + or return $self; my $json = $self->json_content; - cmp_deeply( $json, $expected, $test_name ) or diag explain $json; + cmp_deeply($json, $expected, $test_name) or diag explain $json; return $self; } -sub note { +sub note +{ my $self = shift; Test::More::note @_; return $self; } -sub diag_headers { +sub diag_headers +{ my $self = shift; diag $self->res->headers->as_string; return $self; } -sub diag_content { +sub diag_content +{ my $self = shift; diag $self->res->content; return $self; diff --git a/lib/Kelp/Test/CookieJar.pm b/lib/Kelp/Test/CookieJar.pm index 778fec8..86cdaae 100644 --- a/lib/Kelp/Test/CookieJar.pm +++ b/lib/Kelp/Test/CookieJar.pm @@ -7,14 +7,16 @@ use URI::Escape; attr cookies => sub { {} }; -sub set_cookie { +sub set_cookie +{ my ($self, undef, $name, $value) = @_; $self->cookies->{$name} = $value; return 1; } -sub get_cookies { +sub get_cookies +{ my ($self, undef, @names) = @_; my %ret; @@ -30,20 +32,22 @@ sub get_cookies { } } -sub clear { +sub clear +{ my ($self, undef, undef, $name) = @_; if ($name) { delete $self->cookies->{$name}; } else { - %{ $self->cookies } = (); + %{$self->cookies} = (); } return $self; } -sub add_cookie_header { +sub add_cookie_header +{ my ($self, $request) = @_; my %c = %{$self->cookies}; @@ -53,7 +57,8 @@ sub add_cookie_header { return $request; } -sub extract_cookies { +sub extract_cookies +{ my ($self, $response) = @_; my @headers = split ', ', $response->header('Set-Cookie') // ''; diff --git a/lib/Kelp/Util.pm b/lib/Kelp/Util.pm index 7e41843..f323f78 100644 --- a/lib/Kelp/Util.pm +++ b/lib/Kelp/Util.pm @@ -4,14 +4,15 @@ use Kelp::Base -strict; use Carp; use Scalar::Util qw(blessed); -sub camelize { - my ( $string, $base ) = @_; +sub camelize +{ + my ($string, $base) = @_; return $string unless $string; my $sigil = defined $string && $string =~ s/^(\+)// ? $1 : undef; $base = undef if $sigil; - my @parts = split( /\#/, $string ); + my @parts = split(/\#/, $string); my $sub = pop @parts; @parts = map { @@ -19,11 +20,12 @@ sub camelize { } @parts; unshift @parts, $base if $base; - return join( '::', @parts, $sub ); + return join('::', @parts, $sub); } -sub extract_class { - my ( $string ) = @_; +sub extract_class +{ + my ($string) = @_; return undef unless $string; if ($string =~ /^(.+)::(\w+)$/ && $1 ne 'main') { @@ -33,8 +35,9 @@ sub extract_class { return undef; } -sub extract_function { - my ( $string ) = @_; +sub extract_function +{ + my ($string) = @_; return undef unless $string; if ($string =~ /^(.+)::(\w+)$/) { @@ -44,8 +47,9 @@ sub extract_function { return $string; } -sub adapt_psgi { - my ( $app ) = @_; +sub adapt_psgi +{ + my ($app) = @_; croak 'Cannot adapt_psgi, unknown destination type - must be a coderef' unless ref $app eq 'CODE'; @@ -78,16 +82,16 @@ sub adapt_psgi { # produce a response if (ref $result eq 'ARRAY') { - my ($status, $headers, $body) = @{$result}; + my ($status, $headers, $body) = @{$result}; - my $res = $kelp->res; - $res->status($status) if $status; - $res->headers($headers) if $headers; - $res->body($body) if $body; - $res->rendered(1); + my $res = $kelp->res; + $res->status($status) if $status; + $res->headers($headers) if $headers; + $res->body($body) if $body; + $res->rendered(1); } elsif (ref $result eq 'CODE') { - return $result; + return $result; } # this should be an error unless already rendered diff --git a/t/base.t b/t/base.t index 0872959..5447e08 100644 --- a/t/base.t +++ b/t/base.t @@ -3,10 +3,10 @@ package B1; use Kelp::Base; attr bar => 1; -attr foo => sub{{ a => 1 }}; -attr baz => sub{[1,2,3,4]}; +attr foo => sub { {a => 1} }; +attr baz => sub { [1, 2, 3, 4] }; attr bat => sub { - $_[0]->bar( $_[0]->bar + 1 ); + $_[0]->bar($_[0]->bar + 1); $_[0]->bar; }; attr color => sub { $_[0]->_build_color }; @@ -39,8 +39,8 @@ my $o = B1->new; isa_ok $o, 'B1'; can_ok $o, qw/bar foo baz bat ro un/; is $o->bar, 1; -is_deeply $o->foo, { a => 1 }; -is_deeply $o->baz, [1,2,3,4]; +is_deeply $o->foo, {a => 1}; +is_deeply $o->baz, [1, 2, 3, 4]; is $o->bat, 2; is $o->bat, 2; @@ -54,11 +54,11 @@ is $o->un, undef; $o->bar(3); is $o->bar, 3; -$o->foo({ a => 2 }); -is_deeply $o->foo, { a => 2 }; +$o->foo({a => 2}); +is_deeply $o->foo, {a => 2}; -$o->baz({ b => 2 }); -is_deeply $o->baz, { b => 2 }; +$o->baz({b => 2}); +is_deeply $o->baz, {b => 2}; is $o->color, "red"; @@ -67,7 +67,7 @@ is $o->ro, 9; $o->ro(10); is $o->ro, 9; -my $oo = B1->new( ro => 6 ); +my $oo = B1->new(ro => 6); is $oo->ro, 6; $oo->ro(7); is $oo->ro, 6; @@ -77,16 +77,16 @@ isa_ok $p, 'B2'; ok $p->can($_) for qw/bar foo baz bat/; is $p->bar, 10; -is_deeply $p->foo, { a => 1 }; -is_deeply $p->baz, [1,2,3,4]; +is_deeply $p->foo, {a => 1}; +is_deeply $p->baz, [1, 2, 3, 4]; is $p->bat, 11; is $p->bat, 11; is $p->color, "green"; -my $q = B2->new( bar => 20, baz => {a => 6} ); +my $q = B2->new(bar => 20, baz => {a => 6}); is $q->bar, 20; -is_deeply $q->baz, { a => 6 }; +is_deeply $q->baz, {a => 6}; is $q->bat, 21; is $q->bat, 21; diff --git a/t/bin_tests.t b/t/bin_tests.t index b720099..87ee953 100644 --- a/t/bin_tests.t +++ b/t/bin_tests.t @@ -7,15 +7,16 @@ use FindBin '$Bin'; test_app("Foo"); -sub test_app { +sub test_app +{ my $params = shift; - my $kelp_dir = tempdir( CLEANUP => 1 ); + my $kelp_dir = tempdir(CLEANUP => 1); push @INC, "$kelp_dir/lib"; system("$Config{perlpath} $Bin/../bin/Kelp --path=$kelp_dir --noverbose $params"); - my ( $total, $failed ) = execute_tests( tests => ["$kelp_dir/t/main.t"] ); - ok( $total->{bad} == 0 && $total->{max} > 0, "Generated app tests OK" ) - or diag explain $failed; + my ($total, $failed) = execute_tests(tests => ["$kelp_dir/t/main.t"]); + ok($total->{bad} == 0 && $total->{max} > 0, "Generated app tests OK") + or diag explain $failed; } done_testing; diff --git a/t/conf/deployment_no_templates/config.pl b/t/conf/deployment_no_templates/config.pl index a7f10a2..45384cc 100644 --- a/t/conf/deployment_no_templates/config.pl +++ b/t/conf/deployment_no_templates/config.pl @@ -1,7 +1,7 @@ { modules_init => { Template => { - paths => [] # No error templates + paths => [] # No error templates } } } diff --git a/t/conf/disable/test2.pl b/t/conf/disable/test2.pl index cb3a4a7..d268b7d 100644 --- a/t/conf/disable/test2.pl +++ b/t/conf/disable/test2.pl @@ -1 +1 @@ -{ }; +{}; diff --git a/t/conf/error/test.pl b/t/conf/error/test.pl index a7f10a2..45384cc 100644 --- a/t/conf/error/test.pl +++ b/t/conf/error/test.pl @@ -1,7 +1,7 @@ { modules_init => { Template => { - paths => [] # No error templates + paths => [] # No error templates } } } diff --git a/t/conf/f/config.pl b/t/conf/f/config.pl index 8e5ed17..9c43783 100644 --- a/t/conf/f/config.pl +++ b/t/conf/f/config.pl @@ -1,4 +1,4 @@ # This one will die because it does not return a HASH -[1,2,3] +[1, 2, 3] # vim:syntax=perl diff --git a/t/conf/stack_trace_enabled/test.pl b/t/conf/stack_trace_enabled/test.pl index cf4269b..e462a5d 100644 --- a/t/conf/stack_trace_enabled/test.pl +++ b/t/conf/stack_trace_enabled/test.pl @@ -1,10 +1,10 @@ { modules_init => { Template => { - paths => [] # No error templates + paths => [] # No error templates } }, - middleware => ['StackTrace'], + middleware => ['StackTrace'], middleware_init => { StackTrace => { force => 1, diff --git a/t/custom_req_resp.t b/t/custom_req_resp.t index 30dc3f3..673025f 100644 --- a/t/custom_req_resp.t +++ b/t/custom_req_resp.t @@ -2,11 +2,13 @@ use lib 't/lib'; use MyApp; use Test::More; -ok my $app = MyApp->new( request_obj => 'MyApp::Request', - response_obj => 'MyApp::Response', - ), q{can build object}; +ok my $app = MyApp->new( + request_obj => 'MyApp::Request', + response_obj => 'MyApp::Response', + ), + q{can build object}; -isa_ok $app->build_request({}) , 'MyApp::Request' , q{custom request object}; +isa_ok $app->build_request({}), 'MyApp::Request', q{custom request object}; isa_ok $app->build_response, 'MyApp::Response', q{custom response object}; done_testing; diff --git a/t/exceptions.t b/t/exceptions.t index ab9e510..23fcaa0 100644 --- a/t/exceptions.t +++ b/t/exceptions.t @@ -9,54 +9,54 @@ use Test::More; use lib 't/lib'; use StringifyingException; -my $app = Kelp->new( mode => 'test' ); -my $t = Kelp::Test->new( app => $app ); +my $app = Kelp->new(mode => 'test'); +my $t = Kelp::Test->new(app => $app); my $ex = StringifyingException->new(data => [qw(ab cd)]); -$app->add_route( "/0", sub { die 'died' }); -$t->request( GET "/0" ) +$app->add_route("/0", sub { die 'died' }); +$t->request(GET "/0") ->code_is(500) ->content_like(qr/died/) ->content_type_is('text/html'); -$app->add_route( "/1", sub { Kelp::Exception->throw(400) }); -$app->add_route( "/2", sub { Kelp::Exception->throw(403, body => 'body text') }); -$app->add_route( "/2alt", sub { Kelp::Exception->throw(404, body => 'body text') }); -$app->add_route( "/5", sub { shift->res->json; Kelp::Exception->throw(500, body => $ex) }); -$app->add_route( "/5alt", sub { shift->res->json; Kelp::Exception->throw(501, body => $ex) }); -$app->add_route( "/6", sub { Kelp::Exception->throw(300) }); +$app->add_route("/1", sub { Kelp::Exception->throw(400) }); +$app->add_route("/2", sub { Kelp::Exception->throw(403, body => 'body text') }); +$app->add_route("/2alt", sub { Kelp::Exception->throw(404, body => 'body text') }); +$app->add_route("/5", sub { shift->res->json; Kelp::Exception->throw(500, body => $ex) }); +$app->add_route("/5alt", sub { shift->res->json; Kelp::Exception->throw(501, body => $ex) }); +$app->add_route("/6", sub { Kelp::Exception->throw(300) }); # these errors should be the same regardless of mode subtest 'testing development' => sub { $app->mode('development'); - $t->request( GET "/1" ) + $t->request(GET "/1") ->code_is(400) ->content_is('400 - Bad Request') ->content_type_is('text/plain'); - $t->request( GET "/2" ) + $t->request(GET "/2") ->code_is(403) ->content_is('403 - Forbidden') ->content_type_is('text/plain'); - $t->request( GET "/2alt" ) + $t->request(GET "/2alt") ->code_is(404) ->content_like(qr/Four Oh Four/) ->content_type_is('text/html'); - $t->request( GET "/5" ) + $t->request(GET "/5") ->code_is(500) ->content_like(qr/\Q$ex\E/) ->content_type_is('text/html'); - $t->request( GET "/5alt" ) + $t->request(GET "/5alt") ->code_is(501) ->content_like(qr/501 - Not Implemented/) ->content_type_is('text/plain'); - $t->request( GET "/6" ) + $t->request(GET "/6") ->code_is(500) ->content_like(qr/5XX/) ->content_type_is('text/html'); @@ -65,37 +65,36 @@ subtest 'testing development' => sub { subtest 'testing deployment' => sub { $app->mode('deployment'); - $t->request( GET "/1" ) + $t->request(GET "/1") ->code_is(400) ->content_is('400 - Bad Request') ->content_type_is('text/plain'); - $t->request( GET "/2" ) + $t->request(GET "/2") ->code_is(403) ->content_is('403 - Forbidden') ->content_type_is('text/plain'); - $t->request( GET "/2alt" ) + $t->request(GET "/2alt") ->code_is(404) ->content_like(qr/Four Oh Four/) ->content_type_is('text/html'); - $t->request( GET "/5" ) + $t->request(GET "/5") ->code_is(500) ->content_unlike(qr/Exception/) ->content_type_is('text/html'); - $t->request( GET "/5alt" ) + $t->request(GET "/5alt") ->code_is(501) ->content_is('501 - Not Implemented') ->content_type_is('text/plain'); - $t->request( GET "/6" ) + $t->request(GET "/6") ->code_is(500) ->content_like(qr/Five Hundred/) ->content_type_is('text/html'); }; - done_testing; diff --git a/t/json-encode-error.t b/t/json-encode-error.t index d78f06a..5f895ce 100644 --- a/t/json-encode-error.t +++ b/t/json-encode-error.t @@ -6,7 +6,7 @@ use lib 't/lib'; use JsonError; my $app = JsonError->new; -my $t = Kelp::Test->new( app => $app ); +my $t = Kelp::Test->new(app => $app); # Check if json encoding does not cause json response enconding error (json # content type + non-reference body). This happened in the past because json @@ -15,11 +15,11 @@ my $t = Kelp::Test->new( app => $app ); subtest 'testing mode development' => sub { $app->mode('development'); - $t->request( GET '/json' ) + $t->request(GET '/json') ->code_is(500) ->content_unlike(qr{Don't know how to handle non-json reference}); - $t->request( GET '/forced-json' ) + $t->request(GET '/forced-json') ->code_is(500) ->content_unlike(qr{Don't know how to handle non-json reference}); }; @@ -27,11 +27,11 @@ subtest 'testing mode development' => sub { subtest 'testing mode deployment' => sub { $app->mode('deployment'); - $t->request( GET '/json' ) + $t->request(GET '/json') ->code_is(500) ->content_like(qr{Five Hundred}); - $t->request( GET '/forced-json' ) + $t->request(GET '/forced-json') ->code_is(500) ->content_like(qr{Five Hundred}); }; diff --git a/t/less.t b/t/less.t index 43f6e97..10188ee 100644 --- a/t/less.t +++ b/t/less.t @@ -6,34 +6,34 @@ use Test::More; module 'JSON', utf8 => 1; module 'Template'; -my $t = Kelp::Test->new( app => app ); +my $t = Kelp::Test->new(app => app); # route route '/route' => sub { "A" }; -$t->request( GET '/route' )->content_is("A"); -$t->request( POST '/route' )->content_is("A"); -$t->request( PUT '/route' )->content_is("A"); +$t->request(GET '/route')->content_is("A"); +$t->request(POST '/route')->content_is("A"); +$t->request(PUT '/route')->content_is("A"); # get, post, put -get '/get' => sub { "B" }; +get '/get' => sub { "B" }; post '/post' => sub { "C" }; -put '/put' => sub { "D" }; -del '/del' => sub { "DD" }; -$t->request( GET '/get' )->content_is("B"); -$t->request( POST '/get' )->code_is(404); -$t->request( GET '/post' )->code_is(404); -$t->request( POST '/post' )->content_is("C"); -$t->request( GET '/put' )->code_is(404); -$t->request( POST '/put' )->code_is(404); -$t->request( PUT '/put' )->content_is("D"); -$t->request( DELETE '/del' )->content_is("DD"); -$t->request( GET '/del' )->code_is(404); +put '/put' => sub { "D" }; +del '/del' => sub { "DD" }; +$t->request(GET '/get')->content_is("B"); +$t->request(POST '/get')->code_is(404); +$t->request(GET '/post')->code_is(404); +$t->request(POST '/post')->content_is("C"); +$t->request(GET '/put')->code_is(404); +$t->request(POST '/put')->code_is(404); +$t->request(PUT '/put')->content_is("D"); +$t->request(DELETE '/del')->content_is("DD"); +$t->request(GET '/del')->code_is(404); # param -route '/param' => sub { [ sort(param()) ] }; -$t->request( GET '/param?a=bar&b=foo' )->json_cmp(['a','b']); +route '/param' => sub { [sort(param())] }; +$t->request(GET '/param?a=bar&b=foo')->json_cmp(['a', 'b']); route '/param2' => sub { param 'a' }; -$t->request( GET '/param2?a=bar&b=foo' )->content_is("bar"); +$t->request(GET '/param2?a=bar&b=foo')->content_is("bar"); # session route '/session' => sub { @@ -43,37 +43,37 @@ route '/session' => sub { # stash route '/stash' => sub { stash->{a} = "E"; stash 'a' }; -$t->request( GET '/stash' )->content_is("E"); +$t->request(GET '/stash')->content_is("E"); # named route '/named/:a' => sub { named 'a' }; -$t->request( GET '/named/F' )->content_is("F"); +$t->request(GET '/named/F')->content_is("F"); # req route '/req' => sub { ref(req) eq 'Kelp::Request' ? "G" : "FAIL" }; -$t->request( POST '/req' )->content_is("G"); +$t->request(POST '/req')->content_is("G"); # res route '/res' => sub { ref(res) eq 'Kelp::Response' ? "H" : "FAIL" }; -$t->request( POST '/res' )->content_is("H"); +$t->request(POST '/res')->content_is("H"); # template -route '/template' => sub { template \"[% letter %]", { letter => 'I' } }; -$t->request( GET '/template' )->content_is("I"); +route '/template' => sub { template \"[% letter %]", {letter => 'I'} }; +$t->request(GET '/template')->content_is("I"); # attr attr active => "J"; attr lazy => sub { app->active }; route '/attr' => sub { app->lazy }; -$t->request( GET '/attr' )->content_is("J"); +$t->request(GET '/attr')->content_is("J"); # sub route '/sub' => 'func'; sub func { "K" } -$t->request( GET '/sub' )->content_is("K"); +$t->request(GET '/sub')->content_is("K"); # config route '/config' => sub { config('charset') }; -$t->request( GET '/config')->content_is('UTF-8'); +$t->request(GET '/config')->content_is('UTF-8'); done_testing; diff --git a/t/lib/JsonError.pm b/t/lib/JsonError.pm index 0453e16..4bd199a 100644 --- a/t/lib/JsonError.pm +++ b/t/lib/JsonError.pm @@ -1,24 +1,31 @@ -package JsonError;; +package JsonError; use Kelp::Base 'Kelp'; -sub build { +sub build +{ my $self = shift; - my $r = $self->routes; + my $r = $self->routes; - $r->add( "/json", sub { - return { - key => sub {} - }; - }); + $r->add( + "/json", + sub { + return { + key => sub { } + }; + } + ); - $r->add( "/forced-json", sub { - my $self = shift; + $r->add( + "/forced-json", + sub { + my $self = shift; - $self->res->json; - return { - key => sub {} - }; - }); + $self->res->json; + return { + key => sub { } + }; + } + ); } 1; diff --git a/t/lib/MyApp.pm b/t/lib/MyApp.pm index b4e8a93..e13e819 100644 --- a/t/lib/MyApp.pm +++ b/t/lib/MyApp.pm @@ -3,34 +3,39 @@ use Kelp::Base 'Kelp'; use MyApp::Response; use UtilPackage; -sub before_dispatch { +sub before_dispatch +{ my $self = shift; - $self->res->header( 'X-Before-Dispatch', 'MyApp' ); + $self->res->header('X-Before-Dispatch', 'MyApp'); } -sub before_finalize { +sub before_finalize +{ my $self = shift; - $self->res->header( 'X-Test', 'MyApp' ); + $self->res->header('X-Test', 'MyApp'); } -sub build_response { +sub build_response +{ my $self = shift; - MyApp::Response->new( app => $self ); + MyApp::Response->new(app => $self); } -sub build { +sub build +{ my $self = shift; - my $r = $self->routes; - $r->add( "/test", sub { "OK" } ); - $r->add( "/greet/:name", "routes#greet"); - $r->add( "/bye/:name", "Routes2::goodbye"); + my $r = $self->routes; + $r->add("/test", sub { "OK" }); + $r->add("/greet/:name", "routes#greet"); + $r->add("/bye/:name", "Routes2::goodbye"); # Controller routes $r->add("/blessed", "blessed"); } -sub blessed { - my ( $self ) = @_; +sub blessed +{ + my ($self) = @_; $self->template('home'); } diff --git a/t/lib/MyApp/Module/Null.pm b/t/lib/MyApp/Module/Null.pm index b3bdde8..19e990a 100644 --- a/t/lib/MyApp/Module/Null.pm +++ b/t/lib/MyApp/Module/Null.pm @@ -1,9 +1,10 @@ package MyApp::Module::Null; use Kelp::Base 'Kelp::Module'; -sub build { - my ( $self, %args ) = @_; - $self->register( plus => sub { $_[1] + $args{number} } ); +sub build +{ + my ($self, %args) = @_; + $self->register(plus => sub { $_[1] + $args{number} }); } 1; diff --git a/t/lib/MyApp/Response.pm b/t/lib/MyApp/Response.pm index c3ad097..b50feab 100644 --- a/t/lib/MyApp/Response.pm +++ b/t/lib/MyApp/Response.pm @@ -1,10 +1,10 @@ package MyApp::Response; use Kelp::Base 'Kelp::Response'; -sub render_404 { +sub render_404 +{ my $self = shift; $self->set_code(404)->text->render("NO"); } - 1; diff --git a/t/lib/MyApp/Routes.pm b/t/lib/MyApp/Routes.pm index 2499c37..d43dddb 100644 --- a/t/lib/MyApp/Routes.pm +++ b/t/lib/MyApp/Routes.pm @@ -1,7 +1,8 @@ package MyApp::Routes; -sub greet { - my ( $self, $name ) = @_; +sub greet +{ + my ($self, $name) = @_; return "OK $name"; } diff --git a/t/lib/MyApp/Routes2.pm b/t/lib/MyApp/Routes2.pm index 7018fae..d0cf743 100644 --- a/t/lib/MyApp/Routes2.pm +++ b/t/lib/MyApp/Routes2.pm @@ -1,7 +1,8 @@ package MyApp::Routes2; -sub goodbye { - my ( $self, $name ) = @_; +sub goodbye +{ + my ($self, $name) = @_; return "BYE $name"; } diff --git a/t/lib/MyApp2.pm b/t/lib/MyApp2.pm index 1011794..5d69cd2 100644 --- a/t/lib/MyApp2.pm +++ b/t/lib/MyApp2.pm @@ -1,15 +1,16 @@ package MyApp2; use Kelp::Base 'Kelp'; -sub build { +sub build +{ my $self = shift; - my $r = $self->routes; - $r->add( "/blessed", "blessed" ); - $r->add( "/blessed_bar", "Bar::blessed" ); - $r->add( "/blessed_bar2", "bar#blessed" ); - $r->add( "/test_inherit", "bar#test_inherit" ); - $r->add( "/test_module", "bar#test_module" ); - $r->add( "/test_template", "bar#test_template" ); + my $r = $self->routes; + $r->add("/blessed", "blessed"); + $r->add("/blessed_bar", "Bar::blessed"); + $r->add("/blessed_bar2", "bar#blessed"); + $r->add("/test_inherit", "bar#test_inherit"); + $r->add("/test_module", "bar#test_module"); + $r->add("/test_template", "bar#test_template"); } 1; diff --git a/t/lib/MyApp2/Controller/Bar.pm b/t/lib/MyApp2/Controller/Bar.pm index 9a10b7a..5120c7e 100644 --- a/t/lib/MyApp2/Controller/Bar.pm +++ b/t/lib/MyApp2/Controller/Bar.pm @@ -5,7 +5,8 @@ sub naughty_secret { "I control the Bar" } sub test_inherit { "OK" } -sub test_template { +sub test_template +{ return $_[0]->template('0'); } diff --git a/t/lib/StringifyingException.pm b/t/lib/StringifyingException.pm index 1e25d22..813a0d0 100644 --- a/t/lib/StringifyingException.pm +++ b/t/lib/StringifyingException.pm @@ -6,9 +6,10 @@ attr data => undef; use overload q{""} => 'stringify', fallback => 1, -; + ; -sub stringify { +sub stringify +{ return 'Exception with data: [' . (join ',', @{$_[0]->data}) . ']'; } diff --git a/t/middleware.t b/t/middleware.t index 3f5ed2d..ab63fb4 100644 --- a/t/middleware.t +++ b/t/middleware.t @@ -5,22 +5,22 @@ use Kelp::Test; use HTTP::Request::Common; use Test::More; -my $app = Kelp->new( mode => 'test', __config => 1 ); +my $app = Kelp->new(mode => 'test', __config => 1); $app->routes->base("main"); # Need only one route -$app->add_route( '/mw', sub { "OK" } ); +$app->add_route('/mw', sub { "OK" }); -my $t = Kelp::Test->new( app => $app ); +my $t = Kelp::Test->new(app => $app); # No middleware -$t->request( GET '/mw' ) - ->header_is( "X-Framework", "Perl Kelp" ); +$t->request(GET '/mw') + ->header_is("X-Framework", "Perl Kelp"); # Add middleware $app->_cfg->merge( { - middleware => [ 'XFramework', 'ContentLength' ], + middleware => ['XFramework', 'ContentLength'], middleware_init => { XFramework => { framework => 'Changed' @@ -29,8 +29,8 @@ $app->_cfg->merge( } ); -$t->request( GET '/mw' ) - ->header_is( "X-Framework", "Changed" ) - ->header_is( "Content-Length", 2 ); +$t->request(GET '/mw') + ->header_is("X-Framework", "Changed") + ->header_is("Content-Length", 2); done_testing; diff --git a/t/module.t b/t/module.t index 033de73..b5c82a9 100644 --- a/t/module.t +++ b/t/module.t @@ -10,23 +10,23 @@ use Plack::Util; dies_ok { Kelp::Module->new() } "Dies when no app"; my %types = ( - hash => { bar => 'foo' }, - array => [ 9, 8, 7 ], - object => Plack::Util::inline_object( something => sub {1} ), + hash => {bar => 'foo'}, + array => [9, 8, 7], + object => Plack::Util::inline_object(something => sub { 1 }), code => sub { "Moo!" } ); -my $app = Kelp->new( mode => 'test' ); -my $m = Kelp::Module->new( app => $app ); +my $app = Kelp->new(mode => 'test'); +my $m = Kelp::Module->new(app => $app); isa_ok $m, 'Kelp::Module'; # Register -for my $name ( keys %types ) { +for my $name (keys %types) { my $type = $types{$name}; - $m->register( $name => $type ); + $m->register($name => $type); can_ok $app, $name; - if ( ref $type eq 'CODE' ) { + if (ref $type eq 'CODE') { is $app->$name, $type->(), "CODE checks out"; } else { @@ -35,20 +35,20 @@ for my $name ( keys %types ) { } # Redefine -for my $name ( keys %types ) { +for my $name (keys %types) { my $type = $types{$name}; # Redefine 'em all one by one. - for my $t ( values %types ) { - dies_ok { $m->register( $name => $t ) } - "Dies when redefining " . ref $t; + for my $t (values %types) { + dies_ok { $m->register($name => $t) } + "Dies when redefining " . ref $t; } # Now allow redefining and do it again $ENV{KELP_REDEFINE} = 1; for my $t (values %types) { - $m->register( $name => $t ); - if ( ref $t eq 'CODE' ) { + $m->register($name => $t); + if (ref $t eq 'CODE') { is $app->$name, $t->(), "Redefines CODE"; } else { diff --git a/t/module_config.t b/t/module_config.t index 3b76bc1..e5ee2e9 100644 --- a/t/module_config.t +++ b/t/module_config.t @@ -15,40 +15,40 @@ use Test::Exception; my $app = Plack::Util::inline_object( mode => sub { "test" } ); -my $c = Kelp::Module::Config->new( app => $app ); +my $c = Kelp::Module::Config->new(app => $app); isa_ok $c, 'Kelp::Module::Config'; # No file -$c->data({ C => 'baz' }); +$c->data({C => 'baz'}); $c->path("$Bin/conf/missing"); $c->build(); -is_deeply( $c->data, { C => 'baz' } ); +is_deeply($c->data, {C => 'baz'}); # Single file -$c->data({ C => 'baz' }); +$c->data({C => 'baz'}); $c->path("$Bin/conf/a"); $c->build(); -is_deeply( $c->data, { A => 'bar', B => 'foo', C => 'baz' } ); +is_deeply($c->data, {A => 'bar', B => 'foo', C => 'baz'}); # Main + Mode file -$c->data({ C => 'baz' }); +$c->data({C => 'baz'}); $c->path("$Bin/conf/b"); $c->build(); -is_deeply( $c->data, { A => 'bar', B => 'new', C => 'baz' } ); +is_deeply($c->data, {A => 'bar', B => 'new', C => 'baz'}); # Mode file only -$c->data({ C => 'baz' }); +$c->data({C => 'baz'}); $c->path("$Bin/conf/c"); $c->build(); -is_deeply( $c->data, { B => 'new', C => 'baz' } ); +is_deeply($c->data, {B => 'new', C => 'baz'}); # Syntax error -$c->data({ C => 'baz' }); +$c->data({C => 'baz'}); $c->path("$Bin/conf/e"); dies_ok { $c->build() }; # Does not return a hash -$c->data({ C => 'baz' }); +$c->data({C => 'baz'}); $c->path("$Bin/conf/f"); dies_ok { $c->build() }; @@ -56,6 +56,6 @@ dies_ok { $c->build() }; $c->data({}); $c->path("$Bin/conf/g"); $c->build(); -is_deeply( $c->data, { mode => 'test' } ); +is_deeply($c->data, {mode => 'test'}); done_testing; diff --git a/t/module_config_get.t b/t/module_config_get.t index 0b70b4b..7f4a58b 100644 --- a/t/module_config_get.t +++ b/t/module_config_get.t @@ -13,23 +13,23 @@ my $app = Plack::Util::inline_object( mode => sub { "test" }, path => sub { $ENV{KELP_CONFIG_DIR} } ); -my $c = Kelp::Module::Config->new( app => $app ); +my $c = Kelp::Module::Config->new(app => $app); # Inject some test data into the config so we can test $c->data->{test} = { a => 1, b => 2, c => 'bin', - d => { e => 3 }, - f => { g => { h => { i => 4 } } } + d => {e => 3}, + f => {g => {h => {i => 4}}} }; is $c->get('charset'), 'UTF-8'; is $c->get('modules_init.JSON.utf8'), 1; -is $c->get('test.a'), 1; -is $c->get('test.d.e'), 3; +is $c->get('test.a'), 1; +is $c->get('test.d.e'), 3; is $c->get('test.f.g.h.i'), 4; -is_deeply $c->get('test.f.g.h'), { i => 4 }; +is_deeply $c->get('test.f.g.h'), {i => 4}; is $c->get(''), undef; is $c->get(), undef; diff --git a/t/module_config_merge.t b/t/module_config_merge.t index 6eda672..b1639fa 100644 --- a/t/module_config_merge.t +++ b/t/module_config_merge.t @@ -8,118 +8,118 @@ use Kelp::Module::Config; my $H = {}; my $A = []; my @arr = ( - [ 1, 2, 2 ], - [ 1, undef, undef ], - [ 1, $H, $H ], - [ 1, $A, $A ], - [ undef, 1, 1 ], - [ undef, undef, undef ], - [ $H, $A, $A ], - [ $A, $H, $H ] + [1, 2, 2], + [1, undef, undef], + [1, $H, $H], + [1, $A, $A], + [undef, 1, 1], + [undef, undef, undef], + [$H, $A, $A], + [$A, $H, $H] ); - _try( @arr ); + _try(@arr); } # Overwrite { my @arr = ( [ - { a => 1 }, - { a => 2 }, - { a => 2 } + {a => 1}, + {a => 2}, + {a => 2} ], [ - { a => 1, b => 2 }, - { b => 3 }, - { a => 1, b => 3 } + {a => 1, b => 2}, + {b => 3}, + {a => 1, b => 3} ], [ {}, - { a => 1 }, - { a => 1 } + {a => 1}, + {a => 1} ], [ - { a => 1 }, + {a => 1}, {}, - { a => 1 } + {a => 1} ], [ - { a => [1,2,3] }, - { a => [4,5] }, - { a => [4,5] }, + {a => [1, 2, 3]}, + {a => [4, 5]}, + {a => [4, 5]}, ], [ - { a => "bar", b => [1,2] }, - { a => [1,2] }, - { a => [1,2], b => [1,2] } + {a => "bar", b => [1, 2]}, + {a => [1, 2]}, + {a => [1, 2], b => [1, 2]} ], [ - { a => { b => 'bar' } }, - { a => { c => 'foo' } }, - { a => { b => 'bar', c => 'foo' } }, + {a => {b => 'bar'}}, + {a => {c => 'foo'}}, + {a => {b => 'bar', c => 'foo'}}, ], [ - { a => { b => 'bar' } }, - { a => { b => [1,2] } }, - { a => { b => [1,2] } }, + {a => {b => 'bar'}}, + {a => {b => [1, 2]}}, + {a => {b => [1, 2]}}, ], ); - _try( @arr ); + _try(@arr); } # Add to adday { my @arr = ( [ - { a => { b => [ 1, 2 ] } }, - { a => { "+b" => [ 3, 4 ] } }, - { a => { b => [ 1, 2, 3, 4 ] } } + {a => {b => [1, 2]}}, + {a => {"+b" => [3, 4]}}, + {a => {b => [1, 2, 3, 4]}} ], [ - { a => { b => [ 1, 2 ] } }, - { a => { "+b" => [ 1, 2, 4 ] } }, - { a => { b => [ 1, 2, 4 ] } } + {a => {b => [1, 2]}}, + {a => {"+b" => [1, 2, 4]}}, + {a => {b => [1, 2, 4]}} ], [ - { a => { b => [ 1, 2 ] } }, - { a => { "+b" => [ 1, 2 ] } }, - { a => { b => [ 1, 2 ] } } + {a => {b => [1, 2]}}, + {a => {"+b" => [1, 2]}}, + {a => {b => [1, 2]}} ], [ - { a => { b => [ 1, 'bar' ] } }, - { a => { "+b" => [ 2, 'foo' ] } }, - { a => { b => [ 1, 'bar', 2, 'foo' ] } } + {a => {b => [1, 'bar']}}, + {a => {"+b" => [2, 'foo']}}, + {a => {b => [1, 'bar', 2, 'foo']}} ], [ - { a => { b => [ 1, { bar => 'foo' } ] } }, - { a => { "+b" => [ 2, { bar => 'foo' } ] } }, - { a => { b => [ 1, { bar => 'foo' }, 2 ] } } + {a => {b => [1, {bar => 'foo'}]}}, + {a => {"+b" => [2, {bar => 'foo'}]}}, + {a => {b => [1, {bar => 'foo'}, 2]}} ], # Merging only applies to arrays - [ { a => "bar" }, { "+a" => "foo" }, { a => "bar", "+a" => "foo" } ], + [{a => "bar"}, {"+a" => "foo"}, {a => "bar", "+a" => "foo"}], # A real modules initialization test [ { - modules => ["+MyApp::Fully::Qualified"], + modules => ["+MyApp::Fully::Qualified"], modules_init => { - "+MyApp::Fully::Qualified" => { bar => 1, foo => 'baz' } + "+MyApp::Fully::Qualified" => {bar => 1, foo => 'baz'} } }, { modules_init => { - "+MyApp::Fully::Qualified" => { coo => 'bah' } + "+MyApp::Fully::Qualified" => {coo => 'bah'} } }, { - modules => ["+MyApp::Fully::Qualified"], + modules => ["+MyApp::Fully::Qualified"], modules_init => { - "+MyApp::Fully::Qualified" => { bar => 1, foo => 'baz', coo => 'bah' } + "+MyApp::Fully::Qualified" => {bar => 1, foo => 'baz', coo => 'bah'} } } ] @@ -132,33 +132,34 @@ use Kelp::Module::Config; { my @arr = ( [ - { a => { b => [ 1, 2 ] } }, - { a => { "-b" => [ 2 ] } }, - { a => { b => [ 1 ] } } + {a => {b => [1, 2]}}, + {a => {"-b" => [2]}}, + {a => {b => [1]}} ], [ - { a => { b => [ 1, 2 ] } }, - { a => { "-b" => [ 2, 3, 4 ] } }, - { a => { b => [ 1 ] } } + {a => {b => [1, 2]}}, + {a => {"-b" => [2, 3, 4]}}, + {a => {b => [1]}} ], [ - { a => { b => [ 1, 2, "bar" ] } }, - { a => { "-b" => [ "bar", 3, 2] } }, - { a => { b => [ 1 ] } } + {a => {b => [1, 2, "bar"]}}, + {a => {"-b" => ["bar", 3, 2]}}, + {a => {b => [1]}} ], [ - { a => { b => [ 1, 2, { bar => 'foo' } ] } }, - { a => { "-b" => [ { bar => 'foo' }, 1 ] } }, - { a => { b => [ 2 ] } } + {a => {b => [1, 2, {bar => 'foo'}]}}, + {a => {"-b" => [{bar => 'foo'}, 1]}}, + {a => {b => [2]}} ], ); _try(@arr); } -sub _try { +sub _try +{ for (@_) { - my ( $a, $b, $c ) = @$_; - my $m = Kelp::Module::Config::_merge( $a, $b ); + my ($a, $b, $c) = @$_; + my $m = Kelp::Module::Config::_merge($a, $b); is_deeply($m, $c) or diag explain $m; } } diff --git a/t/module_config_null.t b/t/module_config_null.t index 048c5af..1005205 100644 --- a/t/module_config_null.t +++ b/t/module_config_null.t @@ -10,7 +10,7 @@ use Kelp::Base -strict; use Test::More; # Basic -my $app = Kelp->new( config_module => 'Config::Null' ); +my $app = Kelp->new(config_module => 'Config::Null'); is $app->config("injected"), 1; is $app->config("shoulda"), undef; diff --git a/t/module_config_process_mode.t b/t/module_config_process_mode.t index 274e7fe..342af34 100644 --- a/t/module_config_process_mode.t +++ b/t/module_config_process_mode.t @@ -10,15 +10,15 @@ BEGIN { } my $app = Kelp->new; -my $c = Kelp::Module::Config->new( app => $app, data => { foo => 1 } ); +my $c = Kelp::Module::Config->new(app => $app, data => {foo => 1}); $c->process_mode('missing'); -is_deeply $c->data, { foo => 1 }; +is_deeply $c->data, {foo => 1}; $c->process_mode('a'); -is_deeply $c->data, { foo => 1, bar => 1 }; +is_deeply $c->data, {foo => 1, bar => 1}; $c->process_mode('b'); -is_deeply $c->data, { foo => 1, bar => 1, baz => 1 }; +is_deeply $c->data, {foo => 1, bar => 1, baz => 1}; done_testing; diff --git a/t/module_json.t b/t/module_json.t index 5046461..fb20839 100644 --- a/t/module_json.t +++ b/t/module_json.t @@ -5,7 +5,7 @@ use Test::More; # Basic { - my $app = Kelp->new( __config => { modules => [] } ); + my $app = Kelp->new(__config => {modules => []}); my $m = $app->load_module('JSON'); isa_ok $m, "Kelp::Module::JSON"; can_ok $app, $_ for qw/json/; diff --git a/t/module_load.t b/t/module_load.t index 5cfe22c..bdc9ae5 100644 --- a/t/module_load.t +++ b/t/module_load.t @@ -14,7 +14,7 @@ dies_ok { }; # Direct -$app->load_module( 'Null', number => 2 ); +$app->load_module('Null', number => 2); is $app->plus(5), 7; # Via config @@ -22,7 +22,7 @@ my $bpp = Kelp->new; $bpp->config_hash->{modules_init}->{Null} = { number => 3 }; -$bpp->load_module( 'Null' ); +$bpp->load_module('Null'); is $bpp->plus(5), 8; # Direct overrides @@ -30,19 +30,16 @@ my $cpp = Kelp->new; $cpp->config_hash->{modules_init}->{Null} = { number => 3 }; -$cpp->load_module( 'Null', number => 5 ); +$cpp->load_module('Null', number => 5); is $cpp->plus(5), 10; # Fully qualified module name my $dpp = Kelp->new; $dpp->config_hash->{modules_init}->{'MyApp::Module::Null'} = { - number => 4 + number => 4 }; -$dpp->load_module( '+MyApp::Module::Null' ); +$dpp->load_module('+MyApp::Module::Null'); is $dpp->plus(5), 9; - done_testing; - - diff --git a/t/module_logger.t b/t/module_logger.t index b16b309..c8c4df9 100644 --- a/t/module_logger.t +++ b/t/module_logger.t @@ -12,20 +12,23 @@ use HTTP::Request::Common; # Levels { - my $app = Kelp->new( mode => 'nomod' ); + my $app = Kelp->new(mode => 'nomod'); my $m = $app->load_module('Logger'); isa_ok $m, "Kelp::Module::Logger"; can_ok $app, $_ for qw/error debug/; my $t = Kelp::Test->new(app => $app); - $app->add_route('/log', sub { - my $self = shift; - $self->debug("Debug message"); - $self->error("Error message"); - $self->logger('critical', "Critical message"); - "ok"; - }); + $app->add_route( + '/log', + sub { + my $self = shift; + $self->debug("Debug message"); + $self->error("Error message"); + $self->logger('critical', "Critical message"); + "ok"; + } + ); $t->request(GET '/log')->code_is(200); } diff --git a/t/module_template.t b/t/module_template.t index cbeef57..d793f80 100644 --- a/t/module_template.t +++ b/t/module_template.t @@ -5,12 +5,11 @@ use Test::More; use utf8; # Basic -my $app = Kelp->new( __config => { modules => [] }); +my $app = Kelp->new(__config => {modules => []}); my $m = $app->load_module('Template'); isa_ok $m, 'Kelp::Module::Template'; can_ok $app, $_ for qw/template/; -is $app->template( \"[% a %] ☃", { a => 4 } ), '4 ☃', "Process"; - +is $app->template(\"[% a %] ☃", {a => 4}), '4 ☃', "Process"; # Test automatic appending of default extension to template names my $ext = 'foo'; @@ -22,6 +21,5 @@ $m->ext(''); is $m->_rename('home'), 'home', 'if no default defined, no change'; $m->ext('tt'); - done_testing; diff --git a/t/module_template_null.t b/t/module_template_null.t index 99b41c7..aa02c6b 100644 --- a/t/module_template_null.t +++ b/t/module_template_null.t @@ -4,8 +4,8 @@ use Kelp::Base -strict; use Test::More; # Basic -my $app = Kelp->new( __config => { modules => ['Template::Null'] } ); +my $app = Kelp->new(__config => {modules => ['Template::Null']}); is $app->template(), "All the ducks"; -is $app->template("something", { bar => 'foo' }), "All the ducks"; +is $app->template("something", {bar => 'foo'}), "All the ducks"; done_testing; diff --git a/t/new_anonymous.t b/t/new_anonymous.t index 14c2fe1..b57c4c9 100644 --- a/t/new_anonymous.t +++ b/t/new_anonymous.t @@ -2,7 +2,7 @@ package TestApp; use Kelp::Base 'Kelp'; -sub hello {} +sub hello { } 1; @@ -18,9 +18,10 @@ use Scalar::Util qw(blessed refaddr); my ($app1, $app2); lives_ok sub { - $app1 = TestApp->new_anon( mode => 'test' ); - $app2 = TestApp->new_anon( mode => 'test' ); -}, 'construction ok'; + $app1 = TestApp->new_anon(mode => 'test'); + $app2 = TestApp->new_anon(mode => 'test'); + }, + 'construction ok'; ok $app1, 'first anonymous app ok'; ok $app2, 'second anonymous app ok'; @@ -45,18 +46,24 @@ is $app1->routes->routes->[0]->to, 'TestApp::hello', 'route destination ok'; # Check for possible string eval problems throws_ok sub { - Kelp::new_anon(qq[';#\ndie 'not what was expected']); # <- try hack the class name -}, qr/invalid class for new_anon/i, 'eval checks ok'; + Kelp::new_anon(qq[';#\ndie 'not what was expected']); # <- try hack the class name + }, + qr/invalid class for new_anon/i, + 'eval checks ok'; throws_ok sub { - Kelp::new_anon(undef); # <- silly but possible usage -}, qr/invalid class for new_anon/i, 'eval checks ok'; + Kelp::new_anon(undef); # <- silly but possible usage + }, + qr/invalid class for new_anon/i, + 'eval checks ok'; # The limitation is that we can't mix ->new and ->new_anon throws_ok sub { - $app1 = Kelp->new( mode => 'test' ); - $app2 = Kelp->new_anon( mode => 'test' ); -}, qr/redefining of .+ not allowed/i, 'limitations ok'; + $app1 = Kelp->new(mode => 'test'); + $app2 = Kelp->new_anon(mode => 'test'); + }, + qr/redefining of .+ not allowed/i, + 'limitations ok'; done_testing; diff --git a/t/params.t b/t/params.t index 56855ee..2396d73 100644 --- a/t/params.t +++ b/t/params.t @@ -8,49 +8,57 @@ use Encode; use URI::Escape; use utf8; -my $app = Kelp->new( mode => 'test' ); -my $t = Kelp::Test->new( app => $app ); +my $app = Kelp->new(mode => 'test'); +my $t = Kelp::Test->new(app => $app); -$app->add_route( [ POST => '/dump_params/:field' ] => sub { - my ( $self, $field ) = @_; - my $req = $self->req; +$app->add_route( + [POST => '/dump_params/:field'] => sub { + my ($self, $field) = @_; + my $req = $self->req; - return { - param => $req->param( $field ), - query_param => $req->query_param( $field ), - body_param => $req->body_param( $field ), - json_param => $req->json_param( $field ), - }; -} ); + return { + param => $req->param($field), + query_param => $req->query_param($field), + body_param => $req->body_param($field), + json_param => $req->json_param($field), + }; + } +); my $target = '/dump_params/fld?fld=query'; subtest 'testing normal request' => sub { - $t->request( POST $target, + $t->request( + POST $target, 'Content-Type' => 'application/x-www-form-urlencoded', 'Content' => 'fld=body', )->code_is(200); - $t->json_cmp({ - param => 'body', - query_param => 'query', - body_param => 'body', - json_param => undef, - }); + $t->json_cmp( + { + param => 'body', + query_param => 'query', + body_param => 'body', + json_param => undef, + } + ); }; subtest 'testing json request' => sub { - $t->request( POST $target, + $t->request( + POST $target, 'Content-Type' => 'application/json', 'Content' => '{"fld": "json"}', )->code_is(200); - $t->json_cmp({ - param => 'json', - query_param => 'query', - body_param => undef, - json_param => 'json', - }); + $t->json_cmp( + { + param => 'json', + query_param => 'query', + body_param => undef, + json_param => 'json', + } + ); }; done_testing; diff --git a/t/pattern_build.t b/t/pattern_build.t index 082ce51..f7bce9e 100644 --- a/t/pattern_build.t +++ b/t/pattern_build.t @@ -12,124 +12,124 @@ use Test::More; use Kelp::Routes::Pattern; { - my $p = Kelp::Routes::Pattern->new( pattern => '/:a/:b' ); - is $p->build( a => 1, b => 2 ), '/1/2'; - is $p->build( a => 'bar', b => 'foo' ), '/bar/foo'; - is $p->build( a => 'bar' ), undef; - is $p->build( b => 'bar' ), undef; + my $p = Kelp::Routes::Pattern->new(pattern => '/:a/:b'); + is $p->build(a => 1, b => 2), '/1/2'; + is $p->build(a => 'bar', b => 'foo'), '/bar/foo'; + is $p->build(a => 'bar'), undef; + is $p->build(b => 'bar'), undef; is $p->build(), undef; } { - my $p = Kelp::Routes::Pattern->new( pattern => '/:a/?b' ); - is $p->build( a => 1, b => 2 ), '/1/2'; - is $p->build( a => 'bar', b => 'foo' ), '/bar/foo'; - is $p->build( a => 'bar' ), '/bar/'; - is $p->build( b => 'bar' ), undef; + my $p = Kelp::Routes::Pattern->new(pattern => '/:a/?b'); + is $p->build(a => 1, b => 2), '/1/2'; + is $p->build(a => 'bar', b => 'foo'), '/bar/foo'; + is $p->build(a => 'bar'), '/bar/'; + is $p->build(b => 'bar'), undef; } # Checks { my $p = Kelp::Routes::Pattern->new( pattern => '/:a/:b', - check => { a => '\d+', b => '[a-z]+' } + check => {a => '\d+', b => '[a-z]+'} ); - is $p->build( a => 1, b => 'a' ), '/1/a'; - is $p->build( a => 1, b => 2 ), undef; - is $p->build( a => 'a', b => 'b' ), undef; + is $p->build(a => 1, b => 'a'), '/1/a'; + is $p->build(a => 1, b => 2), undef; + is $p->build(a => 'a', b => 'b'), undef; } # Defaults { my $p = Kelp::Routes::Pattern->new( - pattern => '/:a/?b', - defaults => { b => 'foo' } + pattern => '/:a/?b', + defaults => {b => 'foo'} ); - is $p->build( a => 'bar', b => 'baz' ), '/bar/baz'; - is $p->build( a => 'bar' ), '/bar/foo'; - is $p->build( b => 'bar' ), undef; + is $p->build(a => 'bar', b => 'baz'), '/bar/baz'; + is $p->build(a => 'bar'), '/bar/foo'; + is $p->build(b => 'bar'), undef; } { my $p = Kelp::Routes::Pattern->new( - pattern => '/?a/:b', - defaults => { a => 'bar' } + pattern => '/?a/:b', + defaults => {a => 'bar'} ); - is $p->build( a => 'foo', b => 'baz' ), '/foo/baz'; - is $p->build( b => 'bar' ), '/bar/bar'; - is $p->build( a => 'foo' ), undef; + is $p->build(a => 'foo', b => 'baz'), '/foo/baz'; + is $p->build(b => 'bar'), '/bar/bar'; + is $p->build(a => 'foo'), undef; } { my $p = Kelp::Routes::Pattern->new( - pattern => '/:a/>b', - defaults => { b => 'bar/baz' } + pattern => '/:a/>b', + defaults => {b => 'bar/baz'} ); - is $p->build( a => 'bar', b => 'baz' ), '/bar/baz'; - is $p->build( a => 'foo' ), '/foo/bar/baz'; - is $p->build( b => 'bar' ), undef; + is $p->build(a => 'bar', b => 'baz'), '/bar/baz'; + is $p->build(a => 'foo'), '/foo/bar/baz'; + is $p->build(b => 'bar'), undef; } # Captures { - my $p = Kelp::Routes::Pattern->new( pattern => '/{:a}ing/{:b}ing' ); - is $p->build( a => 'go', b => 'walk' ), '/going/walking'; - is $p->build( a => 'go' ), undef; + my $p = Kelp::Routes::Pattern->new(pattern => '/{:a}ing/{:b}ing'); + is $p->build(a => 'go', b => 'walk'), '/going/walking'; + is $p->build(a => 'go'), undef; } # Conditional captures { my $p = Kelp::Routes::Pattern->new( - pattern => '/{:a}ing/{?b}ing', - defaults => { b => 'fart' } + pattern => '/{:a}ing/{?b}ing', + defaults => {b => 'fart'} ); - is $p->build( a => 'sleep' ), '/sleeping/farting'; - is $p->build( b => 'talk' ), undef; + is $p->build(a => 'sleep'), '/sleeping/farting'; + is $p->build(b => 'talk'), undef; } { - my $p = Kelp::Routes::Pattern->new( pattern => '/{:a}ing/{?b}ing' ); - is $p->build( a => 'sleep' ), '/sleeping/ing'; - is $p->build( b => 'talk' ), undef; + my $p = Kelp::Routes::Pattern->new(pattern => '/{:a}ing/{?b}ing'); + is $p->build(a => 'sleep'), '/sleeping/ing'; + is $p->build(b => 'talk'), undef; } # Globs { - my $p = Kelp::Routes::Pattern->new( pattern => '/*a/:b' ); - is $p->build( a => 'bar', b => 'foo' ), '/bar/foo'; - is $p->build( a => 'bar/bat', b => 'foo' ), '/bar/bat/foo'; - is $p->build( b => 'foo' ), undef; - is $p->build( a => 'foo' ), undef; + my $p = Kelp::Routes::Pattern->new(pattern => '/*a/:b'); + is $p->build(a => 'bar', b => 'foo'), '/bar/foo'; + is $p->build(a => 'bar/bat', b => 'foo'), '/bar/bat/foo'; + is $p->build(b => 'foo'), undef; + is $p->build(a => 'foo'), undef; } { - my $p = Kelp::Routes::Pattern->new( pattern => '/a/*/*b' ); - is $p->build( '*' => 'hello', b => 5 ), '/a/hello/5'; - is $p->build( '*' => 'b/c', b => 'd' ), '/a/b/c/d'; - is $p->build( b => '??' ), undef; - is $p->build( '*' => 'foo' ), undef; + my $p = Kelp::Routes::Pattern->new(pattern => '/a/*/*b'); + is $p->build('*' => 'hello', b => 5), '/a/hello/5'; + is $p->build('*' => 'b/c', b => 'd'), '/a/b/c/d'; + is $p->build(b => '??'), undef; + is $p->build('*' => 'foo'), undef; } # Slurpy { - my $p = Kelp::Routes::Pattern->new( pattern => '/:a/>b' ); - is $p->build( a => 'bar', b => 'foo' ), '/bar/foo'; - is $p->build( a => 'bar', b => 'bat/foo' ), '/bar/bat/foo'; - is $p->build( b => 'foo' ), undef; - is $p->build( a => 'foo' ), '/foo/'; + my $p = Kelp::Routes::Pattern->new(pattern => '/:a/>b'); + is $p->build(a => 'bar', b => 'foo'), '/bar/foo'; + is $p->build(a => 'bar', b => 'bat/foo'), '/bar/bat/foo'; + is $p->build(b => 'foo'), undef; + is $p->build(a => 'foo'), '/foo/'; } { - my $p = Kelp::Routes::Pattern->new( pattern => '/a/>' ); - is $p->build( '>' => 'hello' ), '/a/hello'; - is $p->build( '>' => 'b/c' ), '/a/b/c'; + my $p = Kelp::Routes::Pattern->new(pattern => '/a/>'); + is $p->build('>' => 'hello'), '/a/hello'; + is $p->build('>' => 'b/c'), '/a/b/c'; is $p->build(), '/a/'; } # Two unnamed items { - my $p = Kelp::Routes::Pattern->new( pattern => '/hello/*/>' ); - is $p->build( '*' => 'kelp', '>' => 'world' ), '/hello/kelp/world'; + my $p = Kelp::Routes::Pattern->new(pattern => '/hello/*/>'); + is $p->build('*' => 'kelp', '>' => 'world'), '/hello/kelp/world'; } done_testing; diff --git a/t/pattern_cache.t b/t/pattern_cache.t index 38dacc4..8a2270d 100644 --- a/t/pattern_cache.t +++ b/t/pattern_cache.t @@ -9,71 +9,78 @@ use Kelp::Routes::Pattern; use Kelp::Test; use HTTP::Request::Common; -my $app = Kelp->new( mode => 'test', modules => ['JSON'] ); -my $t = Kelp::Test->new( app => $app ); +my $app = Kelp->new(mode => 'test', modules => ['JSON']); +my $t = Kelp::Test->new(app => $app); # param $app->add_route( '/test/:a/:b', sub { - my ( $self, $a, $b ) = @_; - sprintf( '%s-%s-%s-%s', $a, $b, $self->named('a'), $self->named('b') ); + my ($self, $a, $b) = @_; + sprintf('%s-%s-%s-%s', $a, $b, $self->named('a'), $self->named('b')); } ); srand; -for (1..10) { +for (1 .. 10) { my $a = int(rand(500)); my $b = int(rand(500)); - $t->request( POST "/test/$a/$b" )->content_is("$a-$b-$a-$b"); + $t->request(POST "/test/$a/$b")->content_is("$a-$b-$a-$b"); } +$app->add_route( + '/test2/:i', + sub { + $_[0]->param('b') . $_[1]; + } +); -$app->add_route( '/test2/:i', sub { - $_[0]->param('b') . $_[1]; -}); - -for ( 1 .. 10 ) { - my $b = int( rand(500) ); - $t->request( POST "/test2/1", +for (1 .. 10) { + my $b = int(rand(500)); + $t->request( + POST "/test2/1", 'Content-Type' => 'application/json', 'Content' => sprintf('{"b":%i}', $b) )->content_is("${b}1"); - $t->request( POST "/test2/1", [ b => $b ] )->content_is("${b}1"); + $t->request(POST "/test2/1", [b => $b])->content_is("${b}1"); } # param -$app->add_route('/test3/:n', sub { - my ( $self, $n ) = @_; - if ($n == 1) { - [ sort($self->param) ]; - } - elsif ($n == 2) { - my %h = map { $_ => $self->param($_) } $self->param; - return \%h; +$app->add_route( + '/test3/:n', + sub { + my ($self, $n) = @_; + if ($n == 1) { + [sort($self->param)]; + } + elsif ($n == 2) { + my %h = map { $_ => $self->param($_) } $self->param; + return \%h; + } } -}); -$t->request( POST '/test3/1', +); +$t->request( + POST '/test3/1', 'Content-Type' => 'application/json', 'Content' => '{"a":"bar","b":"foo"}' ) - ->code_is(200) - ->json_cmp(['a', 'b'], "Get JSON list of params"); + ->code_is(200) + ->json_cmp(['a', 'b'], "Get JSON list of params"); -$t->request( POST '/test3/2', +$t->request( + POST '/test3/2', 'Content-Type' => 'application/json', 'Content' => '{"a":"bar","b":"foo"}' ) - ->code_is(200) - ->json_cmp({a => "bar", b => "foo"}, "Get JSON struct of params"); - -$t->request( POST '/test3/1', [a => "bar", b => "foo"]) - ->code_is(200) - ->json_cmp(['a', 'b'], "Get POST list of params"); + ->code_is(200) + ->json_cmp({a => "bar", b => "foo"}, "Get JSON struct of params"); -$t->request( POST '/test3/2', [a => "bar", b => "foo"]) - ->code_is(200) - ->json_cmp({a => "bar", b => "foo"}, "Get POST struct of params"); +$t->request(POST '/test3/1', [a => "bar", b => "foo"]) + ->code_is(200) + ->json_cmp(['a', 'b'], "Get POST list of params"); +$t->request(POST '/test3/2', [a => "bar", b => "foo"]) + ->code_is(200) + ->json_cmp({a => "bar", b => "foo"}, "Get POST struct of params"); done_testing; diff --git a/t/pattern_match.t b/t/pattern_match.t index 3ebbddf..5172e70 100644 --- a/t/pattern_match.t +++ b/t/pattern_match.t @@ -12,49 +12,48 @@ use utf8; _match( '/bar', yes => { - '/bar' => {}, + '/bar' => {}, '/bar/' => {}, }, par => { - '/bar' => [], + '/bar' => [], '/bar/' => [], }, ); - _match( '/:a/?b', yes => { - '/bar/foo' => { a => 'bar', b => 'foo' }, - '/1/2' => { a => '1', b => '2' }, - '/bar/' => { a => 'bar' }, - '/bar' => { a => 'bar' }, + '/bar/foo' => {a => 'bar', b => 'foo'}, + '/1/2' => {a => '1', b => '2'}, + '/bar/' => {a => 'bar'}, + '/bar' => {a => 'bar'}, }, par => { '/bar/foo' => [qw/bar foo/], - '/bar' => ['bar', undef] + '/bar' => ['bar', undef] }, - no => ['/bar/foo/baz'] + no => ['/bar/foo/baz'] ); # Partials _match( '/:a/{?b}ing', yes => { - '/bar/ing' => { a => 'bar' }, - '/bar/hopping' => { a => 'bar', b => 'hopp' } + '/bar/ing' => {a => 'bar'}, + '/bar/hopping' => {a => 'bar', b => 'hopp'} }, par => { - '/bar/ing' => ['bar', undef], + '/bar/ing' => ['bar', undef], '/bar/hopping' => ['bar', 'hopp'] }, - no => [ '/a/b', '/a', '/a/min' ] + no => ['/a/b', '/a', '/a/min'] ); _match( '/:a/{*b}ing/:c', yes => { - '/bar/hop/ping/foo' => { a => 'bar', b => 'hop/p', c => 'foo' }, + '/bar/hop/ping/foo' => {a => 'bar', b => 'hop/p', c => 'foo'}, }, par => { '/bar/hop/ping/foo' => [qw{bar hop/p foo}] @@ -63,82 +62,88 @@ _match( _match( '/:a/:b/:c', - yes => [qw{ - /a/b/c - /a-a/b-b/c-c - /12/23/34 - /бар/фу/баз - /référence/Français/d'œuf - /რეგიონების/მიხედვით/არსებობს - }] + yes => [ + qw{ + /a/b/c + /a-a/b-b/c-c + /12/23/34 + /бар/фу/баз + /référence/Français/d'œuf + /რეგიონების/მიხედვით/არსებობს + } + ] ); _match( '/:a/:b', yes => { - '/bar/foo' => { a => 'bar', b => 'foo' }, - '/1/2' => { a => '1', b => '2' }, - '/bar/foo/'=> { a => 'bar', b => 'foo' }, + '/bar/foo' => {a => 'bar', b => 'foo'}, + '/1/2' => {a => '1', b => '2'}, + '/bar/foo/' => {a => 'bar', b => 'foo'}, }, par => { '/bar/foo' => [qw/bar foo/] }, - no => ['/bar', '/foo', '/bar/foo/baz'] + no => ['/bar', '/foo', '/bar/foo/baz'] ); _match( '/{:a}b/{:c}d', yes => { - '/barb/food' => { a => 'bar', c => 'foo' }, - '/bazb/fizd' => { a => 'baz', c => 'fiz' }, - '/1b/4d' => { a => '1', c => '4' } + '/barb/food' => {a => 'bar', c => 'foo'}, + '/bazb/fizd' => {a => 'baz', c => 'fiz'}, + '/1b/4d' => {a => '1', c => '4'} }, par => { '/barb/food' => [qw/bar foo/], '/bazb/fizd' => [qw/baz fiz/], - '/1b/4d' => [qw/1 4/] + '/1b/4d' => [qw/1 4/] }, - no => [qw{/barba/food /baz/mood /bab/mac /b/ad /ab/d /b/d}] + no => [qw{/barba/food /baz/mood /bab/mac /b/ad /ab/d /b/d}] ); _match( '/:a/*b/:c', yes => { - '/bar/foo/baz/bat' => { a => 'bar', b => 'foo/baz', c => 'bat' }, - '/12/56/ab/blah' => { a => '12', b => '56/ab', c => 'blah' } + '/bar/foo/baz/bat' => {a => 'bar', b => 'foo/baz', c => 'bat'}, + '/12/56/ab/blah' => {a => '12', b => '56/ab', c => 'blah'} }, par => { '/bar/foo/baz/bat' => [qw{bar foo/baz bat}], '/12/56/ab/blah' => [qw{12 56/ab blah}] }, - no => [qw{ - /bar/bat - }] + no => [ + qw{ + /bar/bat + } + ] ); _match( '/:a/?b/:c', yes => { - '/a/b/c' => { a => 'a', b => 'b', c => 'c' }, - '/a/c' => { a => 'a', c => 'c' }, - '/a/c/' => { a => 'a', c => 'c' } + '/a/b/c' => {a => 'a', b => 'b', c => 'c'}, + '/a/c' => {a => 'a', c => 'c'}, + '/a/c/' => {a => 'a', c => 'c'} }, par => { '/a/b/c' => [qw/a b c/], - '/a/c' => ['a', undef, 'c'] + '/a/c' => ['a', undef, 'c'] }, - no => [qw{ - /a - /a/b/c/d - }] + no => [ + qw{ + /a + /a/b/c/d + } + ] ); _match( '/aa/?b', yes => { - '/aa' => {}, - '/aa/' => {}, - '/aa/b' => { b => 'b' }, + '/aa' => {}, + '/aa/' => {}, + '/aa/b' => {b => 'b'}, }, no => [ '/aaa' @@ -150,54 +155,60 @@ _match( _match( '/r/*', yes => { - '/r/a' => {}, - '/r/a/b' => {}, - '/r/a/b/' => {}, + '/r/a' => {}, + '/r/a/b' => {}, + '/r/a/b/' => {}, }, par => { - '/r/a' => [qw(a)], + '/r/a' => [qw(a)], '/r/a/b' => [qw(a/b)], }, - no => [qw{ - / - /r - /r/ - /r1 - /ar1 - }] + no => [ + qw{ + / + /r + /r/ + /r1 + /ar1 + } + ] ); _match( '/r*', yes => { - '/r/' => {}, - '/r/a' => {}, - '/r/a/b/' => {}, - '/r1' => {}, + '/r/' => {}, + '/r/a' => {}, + '/r/a/b/' => {}, + '/r1' => {}, }, par => { - '/r/' => [qw(/)], - '/r1' => [qw(1)], - }, - no => [qw{ - / - /r - /ar1 - }] + '/r/' => [qw(/)], + '/r1' => [qw(1)], + }, + no => [ + qw{ + / + /r + /ar1 + } + ] ); _match( '/r/*/:a', yes => { - '/r/aa/b' => { a => 'b' }, - '/r/aa/bb/c' => { a => 'c' }, + '/r/aa/b' => {a => 'b'}, + '/r/aa/bb/c' => {a => 'c'}, }, par => { '/r/aa/bb/c' => [qw(c)], }, - no => [qw{ - /r/tt/ - }] + no => [ + qw{ + /r/tt/ + } + ] ); # Slurpy @@ -205,38 +216,42 @@ _match( _match( '/test/>a', yes => { - '/test' => {}, - '/test/' => {}, - '/test/a' => { a => 'a' }, - '/test/a/b' => { a => 'a/b' }, - '/test/a/b/' => { a => 'a/b/' }, + '/test' => {}, + '/test/' => {}, + '/test/a' => {a => 'a'}, + '/test/a/b' => {a => 'a/b'}, + '/test/a/b/' => {a => 'a/b/'}, }, par => { - '/test/a' => [ 'a' ], - '/test/a/b' => [ 'a/b' ], - '/test/a/b/' => [ 'a/b/' ], - }, - no => [qw( - /tes - /testa - /tes/t - )], + '/test/a' => ['a'], + '/test/a/b' => ['a/b'], + '/test/a/b/' => ['a/b/'], + }, + no => [ + qw( + /tes + /testa + /tes/t + ) + ], ); _match( '/test/a>b', yes => { - '/test/a' => {}, - '/test/a/' => { b => '/' }, - '/test/ab' => { b => 'b' }, - '/test/a/b' => { b => '/b' }, - '/test/a/b/' => { b => '/b/' }, - }, - no => [qw( - /test/b - /test/ - /a/test/a - )], + '/test/a' => {}, + '/test/a/' => {b => '/'}, + '/test/ab' => {b => 'b'}, + '/test/a/b' => {b => '/b'}, + '/test/a/b/' => {b => '/b/'}, + }, + no => [ + qw( + /test/b + /test/ + /a/test/a + ) + ], ); # Defaults @@ -244,35 +259,39 @@ _match( _match( '/:a/?b', yes => { - '/bar' => { a => 'bar', b => 'boo' }, - '/bar/foo' => { a => 'bar', b => 'foo' } + '/bar' => {a => 'bar', b => 'boo'}, + '/bar/foo' => {a => 'bar', b => 'foo'} }, par => { '/bar' => [qw/bar boo/], '/bar/foo' => [qw/bar foo/] }, - no => [qw{ - /a/b/c - }], + no => [ + qw{ + /a/b/c + } + ], - defaults => { b => 'boo' } + defaults => {b => 'boo'} ); _match( '/:a/?b/:c', yes => { - '/bar/foo' => { a => 'bar', b => 'boo', c => 'foo' }, - '/bar/moo/foo' => { a => 'bar', b => 'moo', c => 'foo' } + '/bar/foo' => {a => 'bar', b => 'boo', c => 'foo'}, + '/bar/moo/foo' => {a => 'bar', b => 'moo', c => 'foo'} }, par => { '/bar/foo' => [qw/bar boo foo/], '/bar/moo/foo' => [qw/bar moo foo/] }, - no => [qw{ - /a/b/c/d - /a - }], - defaults => { b => 'boo' } + no => [ + qw{ + /a/b/c/d + /a + } + ], + defaults => {b => 'boo'} ); # Check @@ -280,63 +299,67 @@ _match( _match( '/:a/:b', yes => { - '/123/012012' => { a => '123', b => '012012' }, + '/123/012012' => {a => '123', b => '012012'}, }, par => { '/123/012012' => [qw/123 012012/], }, - no => [qw{ - /12/1a - /1a/12 - }], - check => { a => '\d+', b => '[0-2]+' } + no => [ + qw{ + /12/1a + /1a/12 + } + ], + check => {a => '\d+', b => '[0-2]+'} ); _match( '/:a/?b', yes => { - '/123/012012' => { a => '123', b => '012012' }, - '/123/' => { a => '123' }, - '/123' => { a => '123' } + '/123/012012' => {a => '123', b => '012012'}, + '/123/' => {a => '123'}, + '/123' => {a => '123'} }, par => { '/123/012012' => [qw/123 012012/], - '/123' => ['123', undef] + '/123' => ['123', undef] }, - no => [qw{ - /12/1a - /1a/12 - }], - check => { a => '\d+', b => '[0-2]+' } + no => [ + qw{ + /12/1a + /1a/12 + } + ], + check => {a => '\d+', b => '[0-2]+'} ); _match( '/:a', - check => { a => '\d{1,3}' }, - yes => [qw{/1 /12 /123}], - no => [qw{/a /ab /abc /1234 /a12}] + check => {a => '\d{1,3}'}, + yes => [qw{/1 /12 /123}], + no => [qw{/a /ab /abc /1234 /a12}] ); # Checks and partials _match( '/:a/{?b}ing', - check => { a => qr/\w{3}/, b => qr/\d{1,3}/ }, - yes => { - '/bar/ing' => { a => 'bar' }, - '/bar/123ing' => { a => 'bar', b => '123' } + check => {a => qr/\w{3}/, b => qr/\d{1,3}/}, + yes => { + '/bar/ing' => {a => 'bar'}, + '/bar/123ing' => {a => 'bar', b => '123'} }, par => { - '/bar/ing' => [ 'bar', undef ], - '/bar/123ing' => [ 'bar', '123' ] + '/bar/ing' => ['bar', undef], + '/bar/123ing' => ['bar', '123'] }, - no => [ '/a/b', '/a', '/a/min', '/a/1234ing' ] + no => ['/a/b', '/a', '/a/min', '/a/1234ing'] ); _match( '/:a/*c', - check => { a => qr/[^0-9]+/, c => qr/\d{1,2}/ }, + check => {a => qr/[^0-9]+/, c => qr/\d{1,2}/}, yes => { - '/abc/69' => { a => 'abc', c => '69' } + '/abc/69' => {a => 'abc', c => '69'} }, par => { '/abc/69' => [qw/abc 69/] @@ -352,39 +375,39 @@ _match( # Regexp instead of pattern _match( qr{/([a-z]+)/([a-z]+)$}, - no => [qw{/12/12 /123/abc /abc/123}], + no => [qw{/12/12 /123/abc /abc/123}], yes => [qw{/abc/a /a/b /a/abc}], par => { '/abc/a' => [qw{abc a}], - '/a/b' => [qw{a b}], + '/a/b' => [qw{a b}], '/a/abc' => [qw{a abc}], } ); _match( qr{/([a-z]+)/?([a-z]*)$}, - no => [qw{/123 /abc/123}], + no => [qw{/123 /abc/123}], yes => [qw{/abc/def /abc}], par => { '/abc/def' => [qw/abc def/], - '/abc' => [ 'abc', undef ], + '/abc' => ['abc', undef], } ); _match( qr{/(\d{1,3})$}, - no => [ '/abc', '/ab2', '/1234', '/123a' ], + no => ['/abc', '/ab2', '/1234', '/123a'], yes => [qw{/1 /12 /123}], par => { - '/1' => ['1'], - '/12' => ['12'], + '/1' => ['1'], + '/12' => ['12'], '/123' => ['123'] } ); # Method { - my $p = Kelp::Routes::Pattern->new( pattern => '/a', method => 'POST' ); + my $p = Kelp::Routes::Pattern->new(pattern => '/a', method => 'POST'); ok $p->match('/a', 'POST'); ok !$p->match('/a', 'GET'); ok !$p->match('/a'); @@ -392,7 +415,7 @@ _match( # no method { - my $p = Kelp::Routes::Pattern->new( pattern => '/a' ); + my $p = Kelp::Routes::Pattern->new(pattern => '/a'); ok $p->match('/a', 'POST'); ok $p->match('/a', 'GET'); ok $p->match('/a'); @@ -400,27 +423,28 @@ _match( done_testing; -sub _match { - my ( $pattern, %args ) = @_; +sub _match +{ + my ($pattern, %args) = @_; my $yes = delete $args{yes}; my $par = delete $args{par}; - my $no = delete $args{no}; + my $no = delete $args{no}; - my $p = Kelp::Routes::Pattern->new( pattern => $pattern, %args ); + my $p = Kelp::Routes::Pattern->new(pattern => $pattern, %args); note "Trying: " . $p->pattern . " -> " . $p->regex; if ($yes) { my @arr = ref $yes eq 'HASH' ? keys %$yes : @$yes; for my $path (@arr) { ok $p->match($path), "match: $path"; - if ( ref $yes eq 'HASH' ) { + if (ref $yes eq 'HASH') { is_deeply $p->named, $yes->{$path}, "$path placeholders ok" - or diag explain $p->named; + or diag explain $p->named; } - if ( $par && $par->{$path} ) { + if ($par && $par->{$path}) { is_deeply $p->param, $par->{$path}, "$path param ok" - or diag caller; + or diag caller; delete $par->{$path}; } } diff --git a/t/psgi.t b/t/psgi.t index d2d6454..27ac046 100644 --- a/t/psgi.t +++ b/t/psgi.t @@ -25,106 +25,116 @@ my $psgi_dumper = sub { ]; }; -my $app = Kelp->new( mode => 'test' ); +my $app = Kelp->new(mode => 'test'); $app->routes->fatal(1); -$app->add_route('/app1' => { - to => $psgi_dumper, - psgi => 1, -}); - -$app->add_route('/app2/>path' => { - to => $psgi_dumper, - psgi => 1, -}); +$app->add_route( + '/app1' => { + to => $psgi_dumper, + psgi => 1, + } +); -$app->add_route('/app3/:part' => { - to => $psgi_dumper, - psgi => 1, -}); +$app->add_route( + '/app2/>path' => { + to => $psgi_dumper, + psgi => 1, + } +); -throws_ok { - $app->add_route('/invalid' => { +$app->add_route( + '/app3/:part' => { to => $psgi_dumper, psgi => 1, - bridge => 1, - }); + } +); + +throws_ok { + $app->add_route( + '/invalid' => { + to => $psgi_dumper, + psgi => 1, + bridge => 1, + } + ); } qr{'psgi'.+'bridge'}; -my $t = Kelp::Test->new( app => $app ); +my $t = Kelp::Test->new(app => $app); -$t->request( GET "/app1" ) - ->code_is(200) - ->content_like(qr{^script: /app1$}m) - ->content_like(qr{^path: $}m); +$t->request(GET "/app1") + ->code_is(200) + ->content_like(qr{^script: /app1$}m) + ->content_like(qr{^path: $}m); -$t->request( GET "/app1/" ) - ->code_is(200) - ->content_like(qr{^script: /app1$}m) - ->content_like(qr{^path: /$}m); +$t->request(GET "/app1/") + ->code_is(200) + ->content_like(qr{^script: /app1$}m) + ->content_like(qr{^path: /$}m); -$t->request( GET "/app1/x" ) - ->code_is(404); +$t->request(GET "/app1/x") + ->code_is(404); -$t->request( GET "/app2" ) - ->code_is(200) - ->content_like(qr{^script: /app2$}m) - ->content_like(qr{^path: $}m); +$t->request(GET "/app2") + ->code_is(200) + ->content_like(qr{^script: /app2$}m) + ->content_like(qr{^path: $}m); -$t->request( GET "/app2/" ) - ->code_is(200) - ->content_like(qr{^script: /app2$}m) - ->content_like(qr{^path: /$}m); +$t->request(GET "/app2/") + ->code_is(200) + ->content_like(qr{^script: /app2$}m) + ->content_like(qr{^path: /$}m); -$t->request( GET "/app2/x" ) - ->code_is(200) - ->content_like(qr{^script: /app2$}m) - ->content_like(qr{^path: /x$}m); +$t->request(GET "/app2/x") + ->code_is(200) + ->content_like(qr{^script: /app2$}m) + ->content_like(qr{^path: /x$}m); -$t->request( GET "/app2/x/" ) - ->code_is(200) - ->content_like(qr{^script: /app2$}m) - ->content_like(qr{^path: /x/$}m); +$t->request(GET "/app2/x/") + ->code_is(200) + ->content_like(qr{^script: /app2$}m) + ->content_like(qr{^path: /x/$}m); -$t->request( GET "/app2/x/y" ) - ->code_is(200) - ->content_like(qr{^script: /app2$}m) - ->content_like(qr{^path: /x/y$}m); +$t->request(GET "/app2/x/y") + ->code_is(200) + ->content_like(qr{^script: /app2$}m) + ->content_like(qr{^path: /x/y$}m); -$t->request( GET "/app3" ) - ->code_is(404); +$t->request(GET "/app3") + ->code_is(404); -$t->request( GET "/app3/" ) - ->code_is(404); +$t->request(GET "/app3/") + ->code_is(404); -$t->request( GET "/app3/x" ) - ->code_is(200) - ->content_like(qr{^script: /app3$}m) - ->content_like(qr{^path: /x$}m); +$t->request(GET "/app3/x") + ->code_is(200) + ->content_like(qr{^script: /app3$}m) + ->content_like(qr{^path: /x$}m); -$t->request( GET "/app3/x/" ) - ->code_is(200) - ->content_like(qr{^script: /app3$}m) - ->content_like(qr{^path: /x/$}m); +$t->request(GET "/app3/x/") + ->code_is(200) + ->content_like(qr{^script: /app3$}m) + ->content_like(qr{^path: /x/$}m); -$t->request( GET "/app3/x/y" ) - ->code_is(404); +$t->request(GET "/app3/x/y") + ->code_is(404); # application unicode support should be distinct from Kelp. Kelp will just have # to pass everything to the app through psgi env undecoded. App result should # not be encoded either, it should do its own encoding and decoding. subtest 'testing unicode' => sub { - $app->add_route('/zażółć/>part' => { - to => $psgi_dumper, - psgi => 1, - }); + $app->add_route( + '/zażółć/>part' => { + to => $psgi_dumper, + psgi => 1, + } + ); my $script = uri_escape encode('UTF-8', 'zażółć'); my @path = map { uri_escape encode('UTF-8', $_) } 'gęślą', 'jaźń'; - $t->request( GET '/' . (join '/', $script, @path) ) - ->code_is(200) - ->content_like(qr{^script: /zażółć$}m) - ->content_like(qr{^path: /gęślą/jaźń$}m); + $t->request(GET '/' . (join '/', $script, @path)) + ->code_is(200) + ->content_like(qr{^script: /zażółć$}m) + ->content_like(qr{^path: /gęślą/jaźń$}m); }; done_testing; diff --git a/t/redefine_attrs.t b/t/redefine_attrs.t index 9f2a0ce..f456d07 100644 --- a/t/redefine_attrs.t +++ b/t/redefine_attrs.t @@ -6,11 +6,11 @@ use Kelp::Test; use HTTP::Request::Common qw( GET ); my $app = MyApp->new; -my $t = Kelp::Test->new( app => $app ); +my $t = Kelp::Test->new(app => $app); -is $t->request( GET '/blessed' )->res->code, 200, - '"path" attr not redefined by import.'; +is $t->request(GET '/blessed')->res->code, 200, + '"path" attr not redefined by import.'; is $app->check_util_fun, "OK", - '"path" util function still work inside package.'; + '"path" util function still work inside package.'; done_testing; diff --git a/t/request.t b/t/request.t index 1621727..76eb95b 100644 --- a/t/request.t +++ b/t/request.t @@ -6,106 +6,120 @@ use HTTP::Request::Common; use Test::More; use utf8; -my $app = Kelp->new( mode => 'test' ); -my $t = Kelp::Test->new( app => $app ); +my $app = Kelp->new(mode => 'test'); +my $t = Kelp::Test->new(app => $app); # is_json -$app->add_route('/json', sub { - return $_[0]->req->is_json ? "ok" : "fail"; -}); +$app->add_route( + '/json', + sub { + return $_[0]->req->is_json ? "ok" : "fail"; + } +); for my $ct ( 'application/json', 'application/json; charset=UTF-8', 'APPLICATION/json; charset=UTF-8', 'APPLICATION/JSON; somethin=blah' -) { - $t->request( GET '/json', Content_Type => $ct ) - ->code_is(200) - ->content_is('ok'); + ) +{ + $t->request(GET '/json', Content_Type => $ct) + ->code_is(200) + ->content_is('ok'); } # is_ajax -$app->add_route('/ajax', sub { - return $_[0]->req->is_ajax ? "ok" : "fail"; -}); -$t->request( GET '/ajax', 'X-Requested-With' => 'XMLHttpRequest' ) - ->code_is(200) - ->content_is('ok'); +$app->add_route( + '/ajax', + sub { + return $_[0]->req->is_ajax ? "ok" : "fail"; + } +); +$t->request(GET '/ajax', 'X-Requested-With' => 'XMLHttpRequest') + ->code_is(200) + ->content_is('ok'); # param -$app->add_route('/param/:n', sub { - my ( $self, $n ) = @_; - if ($n == 1) { - [ sort($self->param) ]; - } - elsif ($n == 2) { - my %h = map { $_ => $self->param($_) } $self->param; - return \%h; - } - elsif ($n == 3) { - return scalar($self->param); +$app->add_route( + '/param/:n', + sub { + my ($self, $n) = @_; + if ($n == 1) { + [sort($self->param)]; + } + elsif ($n == 2) { + my %h = map { $_ => $self->param($_) } $self->param; + return \%h; + } + elsif ($n == 3) { + return scalar($self->param); + } } -}); -$t->request( POST '/param/1', +); +$t->request( + POST '/param/1', 'Content-Type' => 'application/json', 'Content' => '{"a":"bar","b":"foo"}' ) - ->code_is(200) - ->json_cmp(['a', 'b'], "Get JSON list of params"); + ->code_is(200) + ->json_cmp(['a', 'b'], "Get JSON list of params"); -$t->request( POST '/param/2', +$t->request( + POST '/param/2', 'Content-Type' => 'application/json', 'Content' => '{"a":"bar","b":"foo"}' ) - ->code_is(200) - ->json_cmp({a => "bar", b => "foo"}, "JSON array context"); + ->code_is(200) + ->json_cmp({a => "bar", b => "foo"}, "JSON array context"); -$t->request( POST '/param/3', +$t->request( + POST '/param/3', 'Content-Type' => 'application/json', 'Content' => '{"a":"bar","b":"foo"}' ) - ->code_is(200) - ->json_cmp({a => "bar", b => "foo"}, "JSON scalar context"); + ->code_is(200) + ->json_cmp({a => "bar", b => "foo"}, "JSON scalar context"); # No JSON content -$t->request( POST '/param/3', 'Content-Type' => 'application/json') - ->code_is(200) - ->json_cmp({}, "No JSON content"); +$t->request(POST '/param/3', 'Content-Type' => 'application/json') + ->code_is(200) + ->json_cmp({}, "No JSON content"); # JSON content is not a hash -$t->request( POST '/param/3', +$t->request( + POST '/param/3', 'Content-Type' => 'application/json', 'Content' => '[1,2,3]' ) - ->code_is(200) - ->json_cmp({ARRAY => [1,2,3]}, "JSON content is not a hash"); + ->code_is(200) + ->json_cmp({ARRAY => [1, 2, 3]}, "JSON content is not a hash"); -$t->request( POST '/param/1', [a => "bar", b => "foo"]) - ->code_is(200) - ->json_cmp(['a', 'b'], "Get POST list of params"); +$t->request(POST '/param/1', [a => "bar", b => "foo"]) + ->code_is(200) + ->json_cmp(['a', 'b'], "Get POST list of params"); -$t->request( POST '/param/2', [a => "bar", b => "foo"]) - ->code_is(200) - ->json_cmp({a => "bar", b => "foo"}, "POST array context"); +$t->request(POST '/param/2', [a => "bar", b => "foo"]) + ->code_is(200) + ->json_cmp({a => "bar", b => "foo"}, "POST array context"); # UTF8 my $utf_hash = { english => 'Well done', russian => 'Молодец' }; -$app->add_route( '/json/utf', sub { $utf_hash } ); -$t->request( GET '/json/utf' )->json_cmp( $utf_hash ); +$app->add_route('/json/utf', sub { $utf_hash }); +$t->request(GET '/json/utf')->json_cmp($utf_hash); # Make sure legacy 'via' attribute works for backwards # compatibiliry $app->add_route( '/via_legacy', { via => 'POST', - to => sub { "OK" } + to => sub { "OK" } } ); -$t->request( POST 'via_legacy' ) - ->code_is(200) - ->content_is("OK"); +$t->request(POST 'via_legacy') + ->code_is(200) + ->content_is("OK"); done_testing; diff --git a/t/request_session.t b/t/request_session.t index 87644c5..3d99ccd 100644 --- a/t/request_session.t +++ b/t/request_session.t @@ -13,45 +13,48 @@ plan skip_all => 'These tests require Plack::Middleware::Session' unless $has_session; my $app = Kelp->new( - mode => 'test', - __config => { middleware => ['Session'] } + mode => 'test', + __config => {middleware => ['Session']} ); -my $t = Kelp::Test->new( app => $app ); +my $t = Kelp::Test->new(app => $app); #ok $app->can('session'); -$app->add_route( '/session', sub { - my $r = $_[0]->req; - my $s = $r->env->{'psgix.session'}; - is_deeply $r->session( bar => 'foo' ), { bar => 'foo' }; - is $r->session('bar'), 'foo'; - is $s->{'bar'}, 'foo'; - - delete $r->session->{bar}; - is $r->session('bar'), undef; - - $r->session( bar => 'foo', baz => 'goo' ); - is $r->session('bar'), 'foo'; - is $r->session('baz'), 'goo'; - - is $s->{'bar'}, 'foo'; - is $s->{'baz'}, 'goo'; - - $r->session( faa => 'taa' ); - is_deeply $s, { - bar => 'foo', - baz => 'goo', - faa => 'taa' - }; - - $r->session({}); - is_deeply $r->session, {}; - is_deeply $r->env->{'psgix.session'}, {}; - - return 'All OK'; -}); +$app->add_route( + '/session', + sub { + my $r = $_[0]->req; + my $s = $r->env->{'psgix.session'}; + is_deeply $r->session(bar => 'foo'), {bar => 'foo'}; + is $r->session('bar'), 'foo'; + is $s->{'bar'}, 'foo'; + + delete $r->session->{bar}; + is $r->session('bar'), undef; + + $r->session(bar => 'foo', baz => 'goo'); + is $r->session('bar'), 'foo'; + is $r->session('baz'), 'goo'; + + is $s->{'bar'}, 'foo'; + is $s->{'baz'}, 'goo'; + + $r->session(faa => 'taa'); + is_deeply $s, { + bar => 'foo', + baz => 'goo', + faa => 'taa' + }; + + $r->session({}); + is_deeply $r->session, {}; + is_deeply $r->env->{'psgix.session'}, {}; + + return 'All OK'; + } +); -$t->request( GET '/session' ) +$t->request(GET '/session') ->code_is(200) ->content_is('All OK'); diff --git a/t/response.t b/t/response.t index 88194d9..a1a9aa6 100644 --- a/t/response.t +++ b/t/response.t @@ -5,101 +5,101 @@ use Kelp::Test; use HTTP::Request::Common; use Test::More; -my $app = Kelp->new( mode => 'test' ); -my $t = Kelp::Test->new( app => $app ); +my $app = Kelp->new(mode => 'test'); +my $t = Kelp::Test->new(app => $app); # Bare render -$app->add_route( "/1", sub { $_[0]->res->render }); -$t->request( GET "/1" ) +$app->add_route("/1", sub { $_[0]->res->render }); +$t->request(GET "/1") ->code_is(200) ->content_is('') ->content_type_is('text/html'); # Set code -$app->add_route( "/2", sub { $_[0]->res->set_code(401)->render }); -$t->request( GET "/2" )->code_is(401); +$app->add_route("/2", sub { $_[0]->res->set_code(401)->render }); +$t->request(GET "/2")->code_is(401); # Set content type -$app->add_route( "/3", sub { $_[0]->res->html->render }); -$t->request( GET "/3" )->content_type_is('text/html'); +$app->add_route("/3", sub { $_[0]->res->html->render }); +$t->request(GET "/3")->content_type_is('text/html'); -$app->add_route( "/4", sub { $_[0]->res->text->render }); -$t->request( GET "/4" )->content_type_is('text/plain'); +$app->add_route("/4", sub { $_[0]->res->text->render }); +$t->request(GET "/4")->content_type_is('text/plain'); -$app->add_route( "/5", sub { $_[0]->res->json->render({}) }); -$t->request( GET "/5" )->content_type_is('application/json'); +$app->add_route("/5", sub { $_[0]->res->json->render({}) }); +$t->request(GET "/5")->content_type_is('application/json'); -$app->add_route( "/51", sub { $_[0]->res->json->render("aaa") }); -$t->request( GET "/51" )->code_is(200)->content_type_is('application/json'); +$app->add_route("/51", sub { $_[0]->res->json->render("aaa") }); +$t->request(GET "/51")->code_is(200)->content_type_is('application/json'); -$app->add_route( "/52", sub { $_[0]->res->json->render(\"aaa") }); -$t->request( GET "/52" )->code_is(500); +$app->add_route("/52", sub { $_[0]->res->json->render(\"aaa") }); +$t->request(GET "/52")->code_is(500); -$app->add_route( "/53", sub { $_[0]->res->json->render([]) }); -$t->request( GET "/53" )->code_is(200)->content_type_is('application/json'); +$app->add_route("/53", sub { $_[0]->res->json->render([]) }); +$t->request(GET "/53")->code_is(200)->content_type_is('application/json'); -$app->add_route( "/6", sub { $_[0]->res->xml->render }); -$t->request( GET "/6" )->content_type_is('application/xml'); +$app->add_route("/6", sub { $_[0]->res->xml->render }); +$t->request(GET "/6")->content_type_is('application/xml'); -$app->add_route( "/7", sub { $_[0]->res->set_content_type('image/png')->render }); -$t->request( GET "/7" )->content_type_is('image/png'); +$app->add_route("/7", sub { $_[0]->res->set_content_type('image/png')->render }); +$t->request(GET "/7")->content_type_is('image/png'); # Set header -$app->add_route( "/8", sub { $_[0]->res->set_header('x-something', 'foo')->render }); -$t->request( GET "/8" )->header_is('x-something', 'foo'); +$app->add_route("/8", sub { $_[0]->res->set_header('x-something', 'foo')->render }); +$t->request(GET "/8")->header_is('x-something', 'foo'); # 404 -$app->add_route( "/404", sub { $_[0]->res->render_404 }); -$t->request( GET "/404" )->code_is(404); +$app->add_route("/404", sub { $_[0]->res->render_404 }); +$t->request(GET "/404")->code_is(404); # 500 -$app->add_route( "/500", sub { $_[0]->res->render_500 }); -$t->request( GET "/500" )->code_is(500); +$app->add_route("/500", sub { $_[0]->res->render_500 }); +$t->request(GET "/500")->code_is(500); # Redirect -$app->add_route( "/redi1", sub { $_[0]->res->redirect_to('/') }); -$t->request( GET "/redi1" )->code_is(302); -$app->add_route( "/redi2", sub { $_[0]->res->redirect_to('/', {}, 301) }); -$t->request( GET "/redi2" )->code_is(301); +$app->add_route("/redi1", sub { $_[0]->res->redirect_to('/') }); +$t->request(GET "/redi1")->code_is(302); +$app->add_route("/redi2", sub { $_[0]->res->redirect_to('/', {}, 301) }); +$t->request(GET "/redi2")->code_is(301); # Die -$app->add_route( "/die", sub { die "You all suck." }); -$t->request( GET "/die" )->code_is(500); +$app->add_route("/die", sub { die "You all suck." }); +$t->request(GET "/die")->code_is(500); # Render -$app->add_route( "/r1", sub { return "Ahoi" }); -$t->request( GET "/r1" ) +$app->add_route("/r1", sub { return "Ahoi" }); +$t->request(GET "/r1") ->code_is(200) ->content_type_is('text/html') ->content_is("Ahoi"); -$app->add_route( "/r2", sub { return { a => 'foo' } }); -$t->request( GET "/r2" ) +$app->add_route("/r2", sub { return {a => 'foo'} }); +$t->request(GET "/r2") ->code_is(200) ->content_type_is('application/json') - ->json_cmp({ a => 'foo' }); + ->json_cmp({a => 'foo'}); # json_content will return a hash -is ref($t->request( GET "/r2" )->json_content), 'HASH'; +is ref($t->request(GET "/r2")->json_content), 'HASH'; # Template -$app->add_route( "/t1", sub { $_[0]->res->text->template( \"[% word %]", { word => 'duck' } ) } ); -$t->request( GET "/t1" ) +$app->add_route("/t1", sub { $_[0]->res->text->template(\"[% word %]", {word => 'duck'}) }); +$t->request(GET "/t1") ->code_is(200) ->content_type_is('text/plain') ->content_is("duck"); -$app->add_route( "/t2", sub { $_[0]->res->html->template( \"[% word %]", { word => 'swan' } ) } ); -$t->request( GET "/t2" ) +$app->add_route("/t2", sub { $_[0]->res->html->template(\"[% word %]", {word => 'swan'}) }); +$t->request(GET "/t2") ->code_is(200) ->content_type_is('text/html') ->content_is("swan"); -$app->add_route( "/bin1", sub { $_[0]->res->render_binary( "123" ) } ); -$t->request( GET "/bin1" )->code_is(500); +$app->add_route("/bin1", sub { $_[0]->res->render_binary("123") }); +$t->request(GET "/bin1")->code_is(500); -$app->add_route( "/bin2", sub { $_[0]->res->set_content_type("image/png")->render_binary( "123" ) } ); -$t->request( GET "/bin2" )->code_is(200); +$app->add_route("/bin2", sub { $_[0]->res->set_content_type("image/png")->render_binary("123") }); +$t->request(GET "/bin2")->code_is(200); done_testing; diff --git a/t/response_error.t b/t/response_error.t index b68f4a3..2266526 100644 --- a/t/response_error.t +++ b/t/response_error.t @@ -17,38 +17,38 @@ my $ex = StringifyingException->new(data => [3, 2, 1]); # Error templates present { - my $app = Kelp->new( mode => 'test' ); + my $app = Kelp->new(mode => 'test'); my $r = $app->routes; - my $t = Kelp::Test->new( app => $app ); + my $t = Kelp::Test->new(app => $app); $r->add("/404", sub { $_[0]->res->render_404 }); - $t->request( GET "/404" ) - ->code_is(404) - ->content_like(qr/Four Oh Four/, "Custom 404 template engaged"); + $t->request(GET "/404") + ->code_is(404) + ->content_like(qr/Four Oh Four/, "Custom 404 template engaged"); - $r->add("/700", sub { $_[0]->res->render_error( 700, "Custom" ) }); - $t->request( GET '/700' ) - ->code_is(700) - ->content_like(qr/Seven Hundred/, "Custom 700 template engaged") - ->content_unlike(qr/700/); + $r->add("/700", sub { $_[0]->res->render_error(700, "Custom") }); + $t->request(GET '/700') + ->code_is(700) + ->content_like(qr/Seven Hundred/, "Custom 700 template engaged") + ->content_unlike(qr/700/); $r->add("/500", sub { $_[0]->res->render_500 }); - $t->request( GET '/500' ) - ->code_is(500) - ->content_like(qr/Five Hundred/, "Custom 500 template engaged"); + $t->request(GET '/500') + ->code_is(500) + ->content_like(qr/Five Hundred/, "Custom 500 template engaged"); $r->add("/exception_text", sub { die "Text exception"; }); - $t->request( GET '/exception_text' ) - ->code_is(500) - ->content_like(qr/Text exception/); + $t->request(GET '/exception_text') + ->code_is(500) + ->content_like(qr/Text exception/); $r->add("/exception_obj", sub { die bless {}, 'Exception'; }); - $t->request( GET '/exception_obj' ) - ->code_is(500) - ->content_like(qr/Exception=HASH/); + $t->request(GET '/exception_obj') + ->code_is(500) + ->content_like(qr/Exception=HASH/); $r->add("/exception_stringify", sub { die $ex }); - $t->request( GET '/exception_stringify' ) + $t->request(GET '/exception_stringify') ->code_is(500) ->content_type_is('text/html') ->content_like(qr/\Q$ex\E/); @@ -57,73 +57,73 @@ my $ex = StringifyingException->new(data => [3, 2, 1]); # No error templates { $ENV{KELP_CONFIG_DIR} = "$Bin/conf/error"; - my $app = Kelp->new( mode => 'test' ); + my $app = Kelp->new(mode => 'test'); my $r = $app->routes; - my $t = Kelp::Test->new( app => $app ); + my $t = Kelp::Test->new(app => $app); $r->add("/404", sub { $_[0]->res->render_404 }); - $t->request( GET "/404" ) - ->code_is(404) - ->content_type_is('text/plain') - ->content_unlike(qr/Four Oh Four/, "Default 404 message engaged"); - - $r->add("/700", sub { $_[0]->res->render_error( 700, "Custom" ) }); - $t->request( GET '/700' ) - ->code_is(700) - ->content_type_is('text/plain') - ->content_unlike(qr/Seven Hundred/) - ->content_like(qr/Custom/, "Default 700 message engaged"); + $t->request(GET "/404") + ->code_is(404) + ->content_type_is('text/plain') + ->content_unlike(qr/Four Oh Four/, "Default 404 message engaged"); + + $r->add("/700", sub { $_[0]->res->render_error(700, "Custom") }); + $t->request(GET '/700') + ->code_is(700) + ->content_type_is('text/plain') + ->content_unlike(qr/Seven Hundred/) + ->content_like(qr/Custom/, "Default 700 message engaged"); $r->add("/500", sub { $_[0]->res->render_500 }); - $t->request( GET '/500' ) - ->code_is(500) - ->content_type_is('text/plain') - ->content_unlike(qr/Five Hundred/, "Default 500 template engaged"); + $t->request(GET '/500') + ->code_is(500) + ->content_type_is('text/plain') + ->content_unlike(qr/Five Hundred/, "Default 500 template engaged"); $r->add("/exception_text", sub { die "Text exception"; }); - $t->request( GET '/exception_text' ) - ->code_is(500) - ->content_type_is('text/plain') - ->content_like(qr/Text exception/); + $t->request(GET '/exception_text') + ->code_is(500) + ->content_type_is('text/plain') + ->content_like(qr/Text exception/); $r->add("/exception_obj", sub { die bless {}, 'Exception'; }); - $t->request( GET '/exception_obj' ) - ->code_is(500) - ->content_type_is('text/plain') - ->content_like(qr/Exception=HASH/); + $t->request(GET '/exception_obj') + ->code_is(500) + ->content_type_is('text/plain') + ->content_like(qr/Exception=HASH/); } # Deployment { - my $app = Kelp->new( mode => 'deployment' ); + my $app = Kelp->new(mode => 'deployment'); my $r = $app->routes; - my $t = Kelp::Test->new( app => $app ); - - $r->add("/500", sub { $_[0]->res->render_500( $_[0]->req->param('m') ) }); - $t->request( GET '/500' ) - ->code_is(500) - ->content_type_is('text/html') - ->content_like(qr/Five Hundred/, "Custom 500 template engaged"); - $t->request( GET '/500?m=Foo' ) - ->code_is(500) - ->content_type_is('text/html') - ->content_like(qr/Five Hundred/, "Custom 500 template engaged") - ->content_unlike(qr/Foo/); + my $t = Kelp::Test->new(app => $app); + + $r->add("/500", sub { $_[0]->res->render_500($_[0]->req->param('m')) }); + $t->request(GET '/500') + ->code_is(500) + ->content_type_is('text/html') + ->content_like(qr/Five Hundred/, "Custom 500 template engaged"); + $t->request(GET '/500?m=Foo') + ->code_is(500) + ->content_type_is('text/html') + ->content_like(qr/Five Hundred/, "Custom 500 template engaged") + ->content_unlike(qr/Foo/); $r->add("/exception_text", sub { die bless {}, 'Exception'; }); - $t->request( GET '/exception_text' ) - ->code_is(500) - ->content_type_is('text/html') - ->content_like(qr/Five Hundred/); + $t->request(GET '/exception_text') + ->code_is(500) + ->content_type_is('text/html') + ->content_like(qr/Five Hundred/); $r->add("/exception_obj", sub { die "Text exception"; }); - $t->request( GET '/exception_obj' ) - ->code_is(500) - ->content_type_is('text/html') - ->content_like(qr/Five Hundred/); + $t->request(GET '/exception_obj') + ->code_is(500) + ->content_type_is('text/html') + ->content_like(qr/Five Hundred/); $r->add("/500_exception", sub { die $ex }); - $t->request( GET '/500_exception' ) + $t->request(GET '/500_exception') ->code_is(500) ->content_type_is('text/html') ->content_like(qr/Five Hundred/); @@ -133,31 +133,31 @@ my $ex = StringifyingException->new(data => [3, 2, 1]); # StackTrace enabled { $ENV{KELP_CONFIG_DIR} = "$Bin/conf/stack_trace_enabled"; - my $app = Kelp->new( mode => 'test' ); - my $r = $app->routes; - my $t = Kelp::Test->new( app => $app ); + my $app = Kelp->new(mode => 'test'); + my $r = $app->routes; + my $t = Kelp::Test->new(app => $app); # we must not catch template not found error when try to # render_500 $r->add("/render_500", sub { $_[0]->res->render_500 }); - $t->request( GET '/render_500' ) - ->code_is(500) - ->content_like(qr/500 - No error, something is wrong/); + $t->request(GET '/render_500') + ->code_is(500) + ->content_like(qr/500 - No error, something is wrong/); # and render_error too $r->add("/render_error", sub { $_[0]->res->render_error }); - $t->request( GET '/render_error' ) - ->code_is(500) - ->content_like(qr/500 - Internal Server Error/); + $t->request(GET '/render_error') + ->code_is(500) + ->content_like(qr/500 - Internal Server Error/); # FIXME: would be nice if stacktrace stringified the JSON - $r->add("/500_json", sub { die { json => 'error' }; }); - $t->request( GET '/500_json' ) + $r->add("/500_json", sub { die {json => 'error'}; }); + $t->request(GET '/500_json') ->code_is(500) ->content_like(qr/^HASH/, 'json is not stringified'); $r->add("/500_exception", sub { die $ex }); - $t->request( GET '/500_exception' ) + $t->request(GET '/500_exception') ->code_is(500) ->content_like(qr/\Q$ex\E/); } @@ -167,36 +167,36 @@ my $ex = StringifyingException->new(data => [3, 2, 1]); # must show stock "Internal Server Error" message { $ENV{KELP_CONFIG_DIR} = "$Bin/conf/deployment_no_templates"; - my $app = Kelp->new( mode => 'deployment' ); + my $app = Kelp->new(mode => 'deployment'); - my $r = $app->routes; - my $t = Kelp::Test->new( app => $app ); + my $r = $app->routes; + my $t = Kelp::Test->new(app => $app); $r->add("/500", sub { $_[0]->res->render_500($_[0]->req->param('m')) }); - $t->request( GET '/500' ) - ->code_is(500) - ->content_like(qr/500 - Internal Server Error/); - $t->request( GET '/500?m=Foo' ) - ->code_is(500) - ->content_like(qr/500 - Internal Server Error/); - - $r->add("/500_json", sub { $_[0]->res->render_500({ json => 'error' }) }); - $t->request( GET '/500_json' ) - ->code_is(500) - ->content_like(qr/500 - Internal Server Error/); + $t->request(GET '/500') + ->code_is(500) + ->content_like(qr/500 - Internal Server Error/); + $t->request(GET '/500?m=Foo') + ->code_is(500) + ->content_like(qr/500 - Internal Server Error/); + + $r->add("/500_json", sub { $_[0]->res->render_500({json => 'error'}) }); + $t->request(GET '/500_json') + ->code_is(500) + ->content_like(qr/500 - Internal Server Error/); $r->add("/render_error", sub { $_[0]->res->render_error }); - $t->request( GET '/render_error' ) - ->code_is(500) - ->content_like(qr/500 - Internal Server Error/); + $t->request(GET '/render_error') + ->code_is(500) + ->content_like(qr/500 - Internal Server Error/); $r->add("/exception", sub { die bless {}, 'Exception'; }); - $t->request( GET '/exception' ) - ->code_is(500) - ->content_like(qr/500 - Internal Server Error/); + $t->request(GET '/exception') + ->code_is(500) + ->content_like(qr/500 - Internal Server Error/); $r->add("/500_exception", sub { die $ex }); - $t->request( GET '/500_exception' ) + $t->request(GET '/500_exception') ->code_is(500) ->content_unlike(qr/\Q$ex\E/); } diff --git a/t/response_finalize.t b/t/response_finalize.t index d452c71..ed33e45 100644 --- a/t/response_finalize.t +++ b/t/response_finalize.t @@ -4,8 +4,8 @@ use Kelp; use Kelp::Response; use Test::More; -my $app = Kelp->new( mode => 'test' ); -my $r = Kelp::Response->new( app => $app ); +my $app = Kelp->new(mode => 'test'); +my $r = Kelp::Response->new(app => $app); $r->text; $r->set_code(200); diff --git a/t/response_redirect.t b/t/response_redirect.t index 1added6..02a95b9 100644 --- a/t/response_redirect.t +++ b/t/response_redirect.t @@ -5,27 +5,27 @@ use Kelp::Test; use HTTP::Request::Common; use Test::More tests => 8; -my $app = Kelp->new( mode => 'test' ); -my $t = Kelp::Test->new( app => $app ); +my $app = Kelp->new(mode => 'test'); +my $t = Kelp::Test->new(app => $app); -$app->add_route( '/test' => sub { shift->res->redirect_to('/example') }); -$t->request( GET '/test' ) +$app->add_route('/test' => sub { shift->res->redirect_to('/example') }); +$t->request(GET '/test') ->header_is('Location', '/example') ->code_is(302); -$app->add_route( '/catalogue/:id' => { to => sub { '?' }, name => 'catalogue', defaults => { id => 'all' }}); -$app->add_route( '/test2' => sub { shift->res->redirect_to('catalogue') }); -$t->request( GET '/test2' ) +$app->add_route('/catalogue/:id' => {to => sub { '?' }, name => 'catalogue', defaults => {id => 'all'}}); +$app->add_route('/test2' => sub { shift->res->redirect_to('catalogue') }); +$t->request(GET '/test2') ->header_is('Location', '/catalogue/all') ->code_is(302); -$app->add_route( '/test3' => sub { shift->res->redirect_to('catalogue', {id => 243}) }); -$t->request( GET '/test3' ) +$app->add_route('/test3' => sub { shift->res->redirect_to('catalogue', {id => 243}) }); +$t->request(GET '/test3') ->header_is('Location', '/catalogue/243') ->code_is(302); -$app->add_route( '/test4' => sub { shift->res->redirect_to('catalogue', {}, 403) }); -$t->request( GET '/test4' ) +$app->add_route('/test4' => sub { shift->res->redirect_to('catalogue', {}, 403) }); +$t->request(GET '/test4') ->header_is('Location', '/catalogue/all') ->code_is(403); diff --git a/t/routes_add.t b/t/routes_add.t index 80b6bb0..ec2032b 100644 --- a/t/routes_add.t +++ b/t/routes_add.t @@ -34,56 +34,56 @@ my $r = Kelp::Routes->new; # Basic # { - $r->add( '/a' => 'a#b' ); - is_deeply _d( $r, qw/pattern to/ ), [ + $r->add('/a' => 'a#b'); + is_deeply _d($r, qw/pattern to/), [ { pattern => '/a', - to => 'A::b' + to => 'A::b' } - ]; + ]; } # Via method # { $r->clear; - $r->add( [ POST => '/a' ] => 'a#b' ); - is_deeply _d( $r, qw/method pattern to/ ), [ + $r->add([POST => '/a'] => 'a#b'); + is_deeply _d($r, qw/method pattern to/), [ { - method => 'POST', + method => 'POST', pattern => '/a', - to => 'A::b' + to => 'A::b' } - ]; + ]; } # Odd method # { $r->clear; - $r->add( [ MOST => '/a' ] => 'a#b' ); - is_deeply _d( $r, qw/method pattern to/ ), [ + $r->add([MOST => '/a'] => 'a#b'); + is_deeply _d($r, qw/method pattern to/), [ { - method => 'MOST', + method => 'MOST', pattern => '/a', - to => 'A::b' + to => 'A::b' } - ]; + ]; } # Sub # { $r->clear; - $r->add( '/a' => sub { } ); - is ref( $r->routes->[0]->to ), 'CODE'; + $r->add('/a' => sub { }); + is ref($r->routes->[0]->to), 'CODE'; } # Not hash # { $r->clear; - $r->add( '/a' => [] ); + $r->add('/a' => []); is_deeply $r->routes, []; } @@ -91,10 +91,10 @@ my $r = Kelp::Routes->new; # { $r->clear; - $r->add( { a => 1 }, 'a#b' ); + $r->add({a => 1}, 'a#b'); is_deeply $r->routes, []; - $r->add( [ POST => { a => 1 } ], 'a#b' ); + $r->add([POST => {a => 1}], 'a#b'); is_deeply $r->routes, []; } @@ -102,15 +102,15 @@ my $r = Kelp::Routes->new; # { $r->clear; - $r->add( '/a' => { name => 'a' } ); + $r->add('/a' => {name => 'a'}); is_deeply $r->routes, []; } # Key trumps method in the value { $r->clear; - $r->add( [ POST => '/a' ] => { to => 'a#b', method => 'PUT' } ); - is_deeply _d( $r, qw/method/ ), [ { method => 'POST' } ]; + $r->add([POST => '/a'] => {to => 'a#b', method => 'PUT'}); + is_deeply _d($r, qw/method/), [{method => 'POST'}]; } # Regex @@ -118,12 +118,12 @@ my $r = Kelp::Routes->new; { $r->clear; my $re = qr{^/a/(\w+)$}; - $r->add( $re, 'bar#foo' ); - is_deeply _d( $r, qw/pattern/ ), [ + $r->add($re, 'bar#foo'); + is_deeply _d($r, qw/pattern/), [ { pattern => $re } - ]; + ]; } # Hash @@ -131,18 +131,18 @@ my $r = Kelp::Routes->new; { $r->clear; my $hash = { - name => 'james', - check => { a => '\d' }, - to => 'bar#foo' + name => 'james', + check => {a => '\d'}, + to => 'bar#foo' }; - $r->add( '/:a' => $hash ); - is_deeply _d( $r, qw/name check to/ ), [ + $r->add('/:a' => $hash); + is_deeply _d($r, qw/name check to/), [ { - name => 'james', - check => { a => '\d' }, - to => 'Bar::foo' + name => 'james', + check => {a => '\d'}, + to => 'Bar::foo' } - ]; + ]; } # Base @@ -150,12 +150,12 @@ my $r = Kelp::Routes->new; { $r->clear; $r->base('Bar'); - $r->add( '/a' => 'foo#baz' ); - is_deeply _d( $r, qw/to/ ), [ + $r->add('/a' => 'foo#baz'); + is_deeply _d($r, qw/to/), [ { to => 'Bar::Foo::baz' } - ]; + ]; $r->base(''); } @@ -163,20 +163,20 @@ my $r = Kelp::Routes->new; { $r->clear; $r->base('Bar'); - $r->add( '/a' => '+Plack::Util::load_class' ); - is_deeply _d( $r, qw/to/ ), [ + $r->add('/a' => '+Plack::Util::load_class'); + is_deeply _d($r, qw/to/), [ { to => 'Plack::Util::load_class' } - ]; + ]; $r->clear; - $r->add( '/a' => '+plack#util#load_class'); - is_deeply _d( $r, qw/to/ ), [ + $r->add('/a' => '+plack#util#load_class'); + is_deeply _d($r, qw/to/), [ { to => 'Plack::Util::load_class' } - ]; + ]; $r->base(''); } @@ -189,7 +189,7 @@ my $r = Kelp::Routes->new; $r->clear; $r->add( '/user' => { - tree => { a => 1, b => 2 } + tree => {a => 1, b => 2} } ); is_deeply $r->routes, []; @@ -198,71 +198,71 @@ my $r = Kelp::Routes->new; $r->clear; $r->add( '/a' => { - to => 'a#b', + to => 'a#b', tree => [ - '/b' => { name => 'b', to => 'a#b' }, + '/b' => {name => 'b', to => 'a#b'}, '/c' => 'a#c' ] } ); - is_deeply _d( $r, 'name' ), [ {}, { name => 'b' }, {} ]; + is_deeply _d($r, 'name'), [{}, {name => 'b'}, {}]; # Good tree $r->clear; $r->add( '/user' => { name => 'user', - to => 'bar#user', + to => 'bar#user', tree => [ - '/id' => { to => 'bar#id', name => 'id' }, - '/edit' => { to => 'bar#edit', name => 'edit' }, - [ DELETE => '/id' ] => { to => 'bar#del' => name => 'delete' }, + '/id' => {to => 'bar#id', name => 'id'}, + '/edit' => {to => 'bar#edit', name => 'edit'}, + [DELETE => '/id'] => {to => 'bar#del' => name => 'delete'}, '/change' => { - to => 'bar#change', + to => 'bar#change', name => 'change', tree => [ - '/name' => { to => 'bar#change_name', name => 'name' }, - [ PUT => '/email' ] => - { to => 'bar#change_email', name => 'email' } + '/name' => {to => 'bar#change_name', name => 'name'}, + [PUT => '/email'] => + {to => 'bar#change_email', name => 'email'} ] } ] } ); - is_deeply _d( $r, qw/pattern name to method/ ), [ + is_deeply _d($r, qw/pattern name to method/), [ { pattern => '/user', - name => 'user', - to => 'Bar::user', + name => 'user', + to => 'Bar::user', }, { pattern => '/user/id', - name => 'user_id', - to => 'Bar::id', + name => 'user_id', + to => 'Bar::id', }, { pattern => '/user/edit', - name => 'user_edit', - to => 'Bar::edit', + name => 'user_edit', + to => 'Bar::edit', }, { pattern => '/user/id', - name => 'user_delete', - to => 'Bar::del', - method => 'DELETE' + name => 'user_delete', + to => 'Bar::del', + method => 'DELETE' }, { pattern => '/user/change', - name => 'user_change', - to => 'Bar::change' + name => 'user_change', + to => 'Bar::change' }, { pattern => '/user/change/name', - name => 'user_change_name', - to => 'Bar::change_name' + name => 'user_change_name', + to => 'Bar::change_name' }, { pattern => '/user/change/email', - name => 'user_change_email', - to => 'Bar::change_email', - method => 'PUT' + name => 'user_change_email', + to => 'Bar::change_email', + method => 'PUT' } - ]; + ]; } # Returned locations @@ -270,65 +270,66 @@ my $r = Kelp::Routes->new; # same tree as above $r->clear; - my $user = $r->add( '/user' => { name => 'user', to => 'bar#user', } ); - $user->add( '/id' => { to => 'bar#id', name => 'id' } ); - $user->add( '/edit' => { to => 'bar#edit', name => 'edit' } ); - $user->add( [ DELETE => '/id' ] => { to => 'bar#del' => name => 'delete' } ); + my $user = $r->add('/user' => {name => 'user', to => 'bar#user',}); + $user->add('/id' => {to => 'bar#id', name => 'id'}); + $user->add('/edit' => {to => 'bar#edit', name => 'edit'}); + $user->add([DELETE => '/id'] => {to => 'bar#del' => name => 'delete'}); - my $change = $user->add( '/change' => { to => 'bar#change', name => 'change' } ); - $change->add( '/name' => { to => 'bar#change_name', name => 'name' } ); - $change->add( [ PUT => '/email' ] => { to => 'bar#change_email', name => 'email' } ); + my $change = $user->add('/change' => {to => 'bar#change', name => 'change'}); + $change->add('/name' => {to => 'bar#change_name', name => 'name'}); + $change->add([PUT => '/email'] => {to => 'bar#change_email', name => 'email'}); - is_deeply _d( $r, qw/pattern name to method bridge/ ), [ + is_deeply _d($r, qw/pattern name to method bridge/), [ { pattern => '/user', - name => 'user', - to => 'Bar::user', - bridge => !!1, + name => 'user', + to => 'Bar::user', + bridge => !!1, }, { pattern => '/user/id', - name => 'user_id', - to => 'Bar::id', - bridge => !!0, + name => 'user_id', + to => 'Bar::id', + bridge => !!0, }, { pattern => '/user/edit', - name => 'user_edit', - to => 'Bar::edit', - bridge => !!0, + name => 'user_edit', + to => 'Bar::edit', + bridge => !!0, }, { pattern => '/user/id', - name => 'user_delete', - to => 'Bar::del', - method => 'DELETE', - bridge => !!0, + name => 'user_delete', + to => 'Bar::del', + method => 'DELETE', + bridge => !!0, }, { pattern => '/user/change', - name => 'user_change', - to => 'Bar::change', - bridge => !!1, + name => 'user_change', + to => 'Bar::change', + bridge => !!1, }, { pattern => '/user/change/name', - name => 'user_change_name', - to => 'Bar::change_name', - bridge => !!0, + name => 'user_change_name', + to => 'Bar::change_name', + bridge => !!0, }, { pattern => '/user/change/email', - name => 'user_change_email', - to => 'Bar::change_email', - method => 'PUT', - bridge => !!0, + name => 'user_change_email', + to => 'Bar::change_email', + method => 'PUT', + bridge => !!0, } - ]; + ]; } -sub _d { - my ( $r, @fields ) = @_; +sub _d +{ + my ($r, @fields) = @_; my @o = (); - for my $route ( @{ $r->routes } ) { + for my $route (@{$r->routes}) { my @a = scalar(@fields) ? @fields : keys %{$route}; my %h = (); for my $k (@a) { - $h{$k} = $route->{$k} if ( defined $route->{$k} ); + $h{$k} = $route->{$k} if (defined $route->{$k}); } push @o, \%h; } diff --git a/t/routes_controller.t b/t/routes_controller.t index 10e2bcf..d21f2d7 100644 --- a/t/routes_controller.t +++ b/t/routes_controller.t @@ -11,37 +11,37 @@ my $app = MyApp2->new( modules_init => { Routes => { rebless => 1, - base => 'MyApp2::Controller', + base => 'MyApp2::Controller', } } } ); -$app->routes->add('/inline', sub {"OK"}); +$app->routes->add('/inline', sub { "OK" }); # Test object -my $t = Kelp::Test->new( app => $app ); +my $t = Kelp::Test->new(app => $app); -$t->request_ok( GET '/inline') - ->content_is("OK"); +$t->request_ok(GET '/inline') + ->content_is("OK"); -$t->request_ok( GET '/blessed' ) - ->content_is('MyApp2::Controller'); +$t->request_ok(GET '/blessed') + ->content_is('MyApp2::Controller'); -$t->request_ok( GET '/blessed_bar' ) - ->content_is('MyApp2::Controller::Bar'); +$t->request_ok(GET '/blessed_bar') + ->content_is('MyApp2::Controller::Bar'); -$t->request_ok( GET '/blessed_bar2' ) - ->content_is('MyApp2::Controller::Bar'); +$t->request_ok(GET '/blessed_bar2') + ->content_is('MyApp2::Controller::Bar'); -$t->request_ok( GET '/test_inherit' ) - ->content_is('OK'); +$t->request_ok(GET '/test_inherit') + ->content_is('OK'); -$t->request_ok( GET '/test_module' ) - ->content_is('UTF-8'); +$t->request_ok(GET '/test_module') + ->content_is('UTF-8'); -$t->request_ok( GET '/test_template' ) - ->content_like( qr/confession: I control the Bar/ ); +$t->request_ok(GET '/test_template') + ->content_like(qr/confession: I control the Bar/); done_testing; diff --git a/t/routes_invalid.t b/t/routes_invalid.t index d089327..fb750ae 100644 --- a/t/routes_invalid.t +++ b/t/routes_invalid.t @@ -15,21 +15,21 @@ use Kelp::Routes; use Data::Dumper; my @cases = ( - [qr/neither a string nor a coderef/, '/wrong_to1', { to => [] }], - [qr/neither a string nor a coderef/, '/wrong_to2', { to => {} }], - [qr/missing/, '/wrong_to3', { to => undef }], + [qr/neither a string nor a coderef/, '/wrong_to1', {to => []}], + [qr/neither a string nor a coderef/, '/wrong_to2', {to => {}}], + [qr/missing/, '/wrong_to3', {to => undef}], [qr/function 'missing' does not exist/, '/wrong_to4', 'missing'], - [qr/function 'missing' does not exist/, '/wrong_to5', { to => 'missing' }], - [qr/function '1' does not exist/, '/wrong_to6', { to => 1 }], - [qr/Can't locate Bar\/_Foo.pm /, '/wrong_to6', { to => 'Bar::_Foo::x' }], - [qr/method 'x' does not exist in class 'Test'/, '/wrong_to7', { to => 'Test::x' }], + [qr/function 'missing' does not exist/, '/wrong_to5', {to => 'missing'}], + [qr/function '1' does not exist/, '/wrong_to6', {to => 1}], + [qr/Can't locate Bar\/_Foo.pm /, '/wrong_to6', {to => 'Bar::_Foo::x'}], + [qr/method 'x' does not exist in class 'Test'/, '/wrong_to7', {to => 'Test::x'}], ); subtest 'testing with default fatal' => sub { my $r = Kelp::Routes->new; for my $case (@cases) { - $r->add(@{$case} [ 1 .. $#$case ]); + $r->add(@{$case}[1 .. $#$case]); } my $routes_count = @{$r->routes}; @@ -44,7 +44,7 @@ subtest 'testing with fatal=1' => sub { my $r = Kelp::Routes->new(fatal => 1); for my $case (@cases) { - throws_ok { $r->add(@{$case} [ 1 .. $#$case ]) } $case->[0]; + throws_ok { $r->add(@{$case}[1 .. $#$case]) } $case->[0]; } my $routes_count = @{$r->routes}; diff --git a/t/routes_match.t b/t/routes_match.t index 90b5380..777d485 100644 --- a/t/routes_match.t +++ b/t/routes_match.t @@ -16,69 +16,69 @@ my $r = Kelp::Routes->new; # Simple { - $r->add( '/:a/:b' => 'a#b' ); + $r->add('/:a/:b' => 'a#b'); is_deeply $r->match($_), [] for ('/a', '', '/a/b/c', 'a'); - is_deeply _d($r->match('/a/b'), 'to'), [ { to => 'A::b' } ]; - is_deeply _d($r->match('/a/b', 'GET'), 'to'), [ { to => 'A::b' } ]; - is_deeply _d($r->match('/a/b', 'PUT'), 'to'), [ { to => 'A::b' } ]; - is_deeply _d($r->match('/a/b', 'POST'), 'to'), [ { to => 'A::b' } ]; - is_deeply _d($r->match('/a/b', 'DELETE'), 'to'), [ { to => 'A::b' } ]; + is_deeply _d($r->match('/a/b'), 'to'), [{to => 'A::b'}]; + is_deeply _d($r->match('/a/b', 'GET'), 'to'), [{to => 'A::b'}]; + is_deeply _d($r->match('/a/b', 'PUT'), 'to'), [{to => 'A::b'}]; + is_deeply _d($r->match('/a/b', 'POST'), 'to'), [{to => 'A::b'}]; + is_deeply _d($r->match('/a/b', 'DELETE'), 'to'), [{to => 'A::b'}]; } # With method { $r->clear; - $r->add( [ POST => '/:a'] => 'a#b' ); + $r->add([POST => '/:a'] => 'a#b'); is_deeply $r->match($_), [] for ('/a', '', '/a/b', 'a'); - is_deeply _d($r->match('/a', 'POST'), 'to'), [ { to => 'A::b' } ]; + is_deeply _d($r->match('/a', 'POST'), 'to'), [{to => 'A::b'}]; is_deeply _d($r->match('/a', 'GET'), 'to'), []; } # Another method { $r->clear; - $r->add( [ GET => '/:a'] => 'a#c' ); + $r->add([GET => '/:a'] => 'a#c'); is_deeply $r->match($_), [] for ('/a', '', '/a/b', 'a'); - is_deeply _d($r->match('/a', 'POST'), 'to'), [ ]; - is_deeply _d($r->match('/a', 'GET'), 'to'), [{ to => 'A::c' }]; + is_deeply _d($r->match('/a', 'POST'), 'to'), []; + is_deeply _d($r->match('/a', 'GET'), 'to'), [{to => 'A::c'}]; } # Similar routes with checks { $r->clear; - $r->add( '/:a/:b' => 'a#b' ); - $r->add( '/:a/:b' => { to => 'a#c', check => { b => '\d+' } } ); - $r->add( '/:a/:b' => { to => 'a#d', check => { a => '\d+' } } ); - is_deeply _d($r->match('/aa/bb'), 'to'), [{ to => 'A::b' }]; - is_deeply _d($r->match('/aa/22'), 'to'), [{ to => 'A::b' }, { to => 'A::c' }]; - is_deeply _d($r->match('/11/bb'), 'to'), [{ to => 'A::b' }, { to => 'A::d' }]; - is_deeply _d($r->match('/11/22'), 'to'), [{ to => 'A::b' }, { to => 'A::c' }, { to => 'A::d' }]; + $r->add('/:a/:b' => 'a#b'); + $r->add('/:a/:b' => {to => 'a#c', check => {b => '\d+'}}); + $r->add('/:a/:b' => {to => 'a#d', check => {a => '\d+'}}); + is_deeply _d($r->match('/aa/bb'), 'to'), [{to => 'A::b'}]; + is_deeply _d($r->match('/aa/22'), 'to'), [{to => 'A::b'}, {to => 'A::c'}]; + is_deeply _d($r->match('/11/bb'), 'to'), [{to => 'A::b'}, {to => 'A::d'}]; + is_deeply _d($r->match('/11/22'), 'to'), [{to => 'A::b'}, {to => 'A::c'}, {to => 'A::d'}]; } # Different routes (same beginning) { $r->clear; - $r->add( '/:a' => 'a#b' ); - $r->add( '/:a/:b' => { to => 'a#c', check => { b => '\d' } } ); - $r->add( '/:a/:b/:c' => 'a#d' ); + $r->add('/:a' => 'a#b'); + $r->add('/:a/:b' => {to => 'a#c', check => {b => '\d'}}); + $r->add('/:a/:b/:c' => 'a#d'); - is_deeply _d($r->match('/a'), 'to'), [{ to => 'A::b' }]; - is_deeply _d($r->match('/a/2'), 'to'), [{ to => 'A::c' }]; + is_deeply _d($r->match('/a'), 'to'), [{to => 'A::b'}]; + is_deeply _d($r->match('/a/2'), 'to'), [{to => 'A::c'}]; is_deeply _d($r->match('/a/b'), 'to'), []; - is_deeply _d($r->match('/a/b/c'), 'to'), [{ to => 'A::d' }]; + is_deeply _d($r->match('/a/b/c'), 'to'), [{to => 'A::d'}]; } # Bridges { $r->clear; - $r->add( '/:a' => { to => 'a#b', bridge => 1 } ); - $r->add( '/:a/:b' => { to => 'a#c', check => { b => '\d' } } ); - $r->add( '/:a/:b/:c' => 'a#d' ); + $r->add('/:a' => {to => 'a#b', bridge => 1}); + $r->add('/:a/:b' => {to => 'a#c', check => {b => '\d'}}); + $r->add('/:a/:b/:c' => 'a#d'); - is_deeply _d($r->match('/a'), 'to'), [{ to => 'A::b' }]; - is_deeply _d($r->match('/a/2'), 'to'), [{to => 'A::b'}, { to => 'A::c' }]; + is_deeply _d($r->match('/a'), 'to'), [{to => 'A::b'}]; + is_deeply _d($r->match('/a/2'), 'to'), [{to => 'A::b'}, {to => 'A::c'}]; is_deeply _d($r->match('/a/b'), 'to'), [{to => 'A::b'}]; - is_deeply _d($r->match('/a/b/c'), 'to'), [{to => 'A::b'}, { to => 'A::d' }]; + is_deeply _d($r->match('/a/b/c'), 'to'), [{to => 'A::b'}, {to => 'A::d'}]; } # Cache @@ -91,7 +91,7 @@ my $r = Kelp::Routes->new; $m = $r->match('/a', 'POST'); is_deeply $m, $r->cache->get('/a:POST'); - $r->add('/a/b', { to => 'a#c', bridge => 1 }); + $r->add('/a/b', {to => 'a#c', bridge => 1}); $m = $r->match('/a/b'); is_deeply $m, $r->cache->get('/a/b:'); $r->add('/a/b/c', 'a#d'); @@ -101,14 +101,15 @@ my $r = Kelp::Routes->new; done_testing; -sub _d { - my ( $m, @fields ) = @_; +sub _d +{ + my ($m, @fields) = @_; my @o = (); - for my $route ( @$m ) { + for my $route (@$m) { my @a = scalar(@fields) ? @fields : keys %{$route}; my %h = (); - for my $k ( @a ) { - $h{$k} = $route->{$k} if ( defined $route->{$k} ); + for my $k (@a) { + $h{$k} = $route->{$k} if (defined $route->{$k}); } push @o, \%h; } diff --git a/t/routes_url.t b/t/routes_url.t index 513256b..02f73be 100644 --- a/t/routes_url.t +++ b/t/routes_url.t @@ -1,5 +1,10 @@ -package A; sub b{} 1; -package Ab; sub c{} 1; +package A; +sub b { } +1; + +package Ab; +sub c { } +1; package main; use strict; @@ -10,10 +15,10 @@ use Kelp::Routes; my $r = Kelp::Routes->new; -$r->add( '/a' => { to => 'a#b', name => 'a' } ); -$r->add( '/b' => { to => 'ab#c', name => 'b' } ); -$r->add( '/a/b' => { to => 'a#b', name => 'ab' } ); -$r->add( '/a/b/c' => 'ab#c'); +$r->add('/a' => {to => 'a#b', name => 'a'}); +$r->add('/b' => {to => 'ab#c', name => 'b'}); +$r->add('/a/b' => {to => 'a#b', name => 'ab'}); +$r->add('/a/b/c' => 'ab#c'); is $r->url('noname'), 'noname'; is $r->url('a'), '/a'; @@ -21,8 +26,8 @@ is $r->url('b'), '/b'; is $r->url('ab'), '/a/b'; $r->clear; -$r->add('/:a/:b', { to => 'a#b', name => 'a' }); -$r->add('/:a/?b', { to => 'ab#c', name => 'b', defaults => { b => 'foo' } }); +$r->add('/:a/:b', {to => 'a#b', name => 'a'}); +$r->add('/:a/?b', {to => 'ab#c', name => 'b', defaults => {b => 'foo'}}); is $r->url(qw/a a bar b foo/), '/bar/foo'; is $r->url(qw/b a bar b moo/), '/bar/moo'; diff --git a/t/run.t b/t/run.t index f907e50..12fad58 100644 --- a/t/run.t +++ b/t/run.t @@ -7,28 +7,31 @@ use Test::More; use URI::Escape; use utf8; -my $app = Kelp->new( mode => 'test' ); +my $app = Kelp->new(mode => 'test'); $app->routes->base("main"); -my $t = Kelp::Test->new( app => $app ); +my $t = Kelp::Test->new(app => $app); # Nothing rendered -$app->add_route("/nothing", sub {}); -$t->request( GET '/nothing' )->code_is(500); +$app->add_route("/nothing", sub { }); +$t->request(GET '/nothing')->code_is(500); # 404 -$app->add_route("/not_found", sub {}); -$t->request( GET '/not_found' )->code_is(500); +$app->add_route("/not_found", sub { }); +$t->request(GET '/not_found')->code_is(500); # Named placeholders -$app->add_route("/named/:a", sub { - my $self = shift; - return "Got: " . $self->req->named->{a}; -}); +$app->add_route( + "/named/:a", + sub { + my $self = shift; + return "Got: " . $self->req->named->{a}; + } +); for my $a (qw{boo дума 123}) { my $encoded = uri_escape $app->charset_encode($a); - $t->request( GET "/named/$encoded" ) - ->code_is(200) - ->content_is("Got: $a"); + $t->request(GET "/named/$encoded") + ->code_is(200) + ->content_is("Got: $a"); } # Route name @@ -37,129 +40,145 @@ my $route_name_sub = sub { return "Got: " . $self->req->route_name; }; -$app->add_route("/bridge", { - name => 'named_bridge', - to => sub { 1 }, - bridge => 1, -}); +$app->add_route( + "/bridge", { + name => 'named_bridge', + to => sub { 1 }, + bridge => 1, + } +); -$app->add_route("/bridge/name", { - name => 'named_route', - to => $route_name_sub, -}); +$app->add_route( + "/bridge/name", { + name => 'named_route', + to => $route_name_sub, + } +); $app->add_route("/unnamed", $route_name_sub); -$t->request( GET "/bridge/name" ) - ->code_is(200) - ->content_is("Got: named_route"); +$t->request(GET "/bridge/name") + ->code_is(200) + ->content_is("Got: named_route"); -$t->request( GET "/unnamed" ) - ->code_is(200) - ->content_is("Got: /unnamed"); +$t->request(GET "/unnamed") + ->code_is(200) + ->content_is("Got: /unnamed"); # Route name - tree -$app->add_route("/tree", { - name => 'tree_bridge', - to => sub { 1 }, - tree => [ - "/name" => { - name => 'tree_route', - to => $route_name_sub, - }, - ], -}); - -$t->request( GET "/tree/name" ) - ->code_is(200) - ->content_is("Got: tree_bridge_tree_route"); +$app->add_route( + "/tree", { + name => 'tree_bridge', + to => sub { 1 }, + tree => [ + "/name" => { + name => 'tree_route', + to => $route_name_sub, + }, + ], + } +); + +$t->request(GET "/tree/name") + ->code_is(200) + ->content_is("Got: tree_bridge_tree_route"); # Array of placeholders -$app->add_route("/array/:a/:b", sub { - my ($self, $a, $b) = @_; - return "Got: $a and $b"; -}); +$app->add_route( + "/array/:a/:b", + sub { + my ($self, $a, $b) = @_; + return "Got: $a and $b"; + } +); for my $a (qw{boo дума 123}) { my $encoded = uri_escape $app->charset_encode($a); - $t->request( GET "/array/one/$encoded" ) - ->code_is(200) - ->content_is("Got: one and $a"); + $t->request(GET "/array/one/$encoded") + ->code_is(200) + ->content_is("Got: one and $a"); } # Param -$app->add_route("/param", sub { - my $self = shift; - return "We have " . $self->param('word'); -}); +$app->add_route( + "/param", + sub { + my $self = shift; + return "We have " . $self->param('word'); + } +); for my $word ('word', 'дума', 'كلمة', 'բառ', 'sözcük') { my $encoded = uri_escape $app->charset_encode($word); - $t->request( GET "/param?word=$encoded" ) - ->code_is(200) - ->content_like(qr{$word}); + $t->request(GET "/param?word=$encoded") + ->code_is(200) + ->content_like(qr{$word}); } # Template $app->add_route("/view", "view"); -$t->request( GET '/view' ) - ->code_is(200) - ->content_is("We are all living in America"); +$t->request(GET '/view') + ->code_is(200) + ->content_is("We are all living in America"); # Delayed $app->add_route("/delayed", "not_really_delayed"); $app->add_route("/delayed", "delayed"); -$t->request( GET '/delayed?yes' ) - ->code_is(200) - ->content_is("Better late than never."); +$t->request(GET '/delayed?yes') + ->code_is(200) + ->content_is("Better late than never."); -$t->request( GET '/delayed' ) - ->code_is(200) - ->content_is("Why wait?"); +$t->request(GET '/delayed') + ->code_is(200) + ->content_is("Why wait?"); # Stash -$app->add_route("/auth" => { - to => "auth", - tree => [ "/work" => "work" ] -}); -$t->request( GET '/auth/work' ) - ->code_is(200) - ->content_is('foo'); +$app->add_route( + "/auth" => { + to => "auth", + tree => ["/work" => "work"] + } +); +$t->request(GET '/auth/work') + ->code_is(200) + ->content_is('foo'); # Methods -$app->add_route( [ POST => "/meth1" ] => sub { "OK" } ); -$t->request( POST "/meth1" )->content_is("OK"); -$app->add_route( [ GET => "/meth2" ] => sub { "OK" } ); -$t->request( GET "/meth2" )->content_is("OK"); -$app->add_route( [ PUT => "/meth3" ] => sub { "OK" } ); -$t->request( PUT "/meth3" )->content_is("OK"); +$app->add_route([POST => "/meth1"] => sub { "OK" }); +$t->request(POST "/meth1")->content_is("OK"); +$app->add_route([GET => "/meth2"] => sub { "OK" }); +$t->request(GET "/meth2")->content_is("OK"); +$app->add_route([PUT => "/meth3"] => sub { "OK" }); +$t->request(PUT "/meth3")->content_is("OK"); # Before render -$t->request( GET "/meth2" )->header_is('X-Framework', 'Perl Kelp'); +$t->request(GET "/meth2")->header_is('X-Framework', 'Perl Kelp'); # Manual render $app->add_route( "/manual" => sub { my $self = shift; - $self->res->render( { bar => 'foo' } ); - return { this => 'will not render' }; + $self->res->render({bar => 'foo'}); + return {this => 'will not render'}; } ); -$t->request( GET "/manual" )->json_cmp( { bar => 'foo' } ); +$t->request(GET "/manual")->json_cmp({bar => 'foo'}); done_testing; -sub view { +sub view +{ my $self = shift; $self->res->template( \"[% who %] are all living in [% where %]", { - who => 'We', + who => 'We', where => 'America' } ); } -sub not_really_delayed { +sub not_really_delayed +{ my $self = shift; # render something unless the route wants delayed @@ -171,7 +190,8 @@ sub not_really_delayed { return undef; } -sub delayed { +sub delayed +{ my $self = shift; return sub { my $responder = shift; @@ -181,13 +201,15 @@ sub delayed { }; } -sub auth { +sub auth +{ my $self = shift; $self->req->stash->{bar} = 'foo'; return 1; } -sub work { +sub work +{ my $self = shift; return $self->req->stash->{bar}; } diff --git a/t/run_bridge.t b/t/run_bridge.t index bcb88ad..206f154 100644 --- a/t/run_bridge.t +++ b/t/run_bridge.t @@ -5,34 +5,34 @@ use Kelp::Test; use HTTP::Request::Common; use Test::More; -my $app = Kelp->new( mode => 'test' ); +my $app = Kelp->new(mode => 'test'); $app->routes->base("main"); -my $t = Kelp::Test->new( app => $app ); +my $t = Kelp::Test->new(app => $app); # Bridge $app->add_route( "/bridge" => { - to => "bridge", + to => "bridge", tree => [ "/route" => "bridge_route", "/render_route" => "bridge_route_render", ] } ); -$t->request( GET '/bridge' )->code_is(403); -$t->request( GET '/bridge/route' )->code_is(403); -$t->request( GET '/bridge/route?code=404' )->code_is(404); -$t->request( GET '/bridge/not_existing_route?ok=1' )->code_is(404); +$t->request(GET '/bridge')->code_is(403); +$t->request(GET '/bridge/route')->code_is(403); +$t->request(GET '/bridge/route?code=404')->code_is(404); +$t->request(GET '/bridge/not_existing_route?ok=1')->code_is(404); -$t->request( GET '/bridge/route?ok=1' ) - ->code_is(200) - ->content_is("We like milk."); +$t->request(GET '/bridge/route?ok=1') + ->code_is(200) + ->content_is("We like milk."); # if a bridge renders a response, no other handlers should be executed even # if the return value is true -$t->request( GET '/bridge/render_route?code=403&ok=1' ) - ->code_is(403) - ->content_is("ok"); +$t->request(GET '/bridge/render_route?code=403&ok=1') + ->code_is(403) + ->content_is("ok"); # render inside bridge $app->add_route( @@ -44,12 +44,12 @@ $app->add_route( } ); -$t->request( GET '/render' ) - ->code_is(700) - ->content_is('auth'); +$t->request(GET '/render') + ->code_is(700) + ->content_is('auth'); # Redirect inside bridge -$app->add_route( '/auth' => sub { 'auth' } ); +$app->add_route('/auth' => sub { 'auth' }); $app->add_route( '/redirect' => { to => sub { $_[0]->res->redirect_to('/auth'); 0 }, @@ -59,27 +59,30 @@ $app->add_route( } ); -$t->request( GET '/redirect/dead' ) - ->code_is(302) - ->header_like(location => qr{/auth$}); +$t->request(GET '/redirect/dead') + ->code_is(302) + ->header_like(location => qr{/auth$}); done_testing; -sub bridge { +sub bridge +{ my $self = shift; $self->req->stash->{info} = "We like milk."; - if ( my $code = $self->param('code') ) { + if (my $code = $self->param('code')) { $self->res->set_code($code)->render("ok"); } return $self->param('ok'); } -sub bridge_route { +sub bridge_route +{ my $self = shift; return $self->req->stash->{info}; } -sub bridge_route_render { +sub bridge_route_render +{ my $self = shift; $self->res->render($self->req->stash->{info}); } diff --git a/t/safe_param.t b/t/safe_param.t index 8cca7c3..f7c5be1 100644 --- a/t/safe_param.t +++ b/t/safe_param.t @@ -5,14 +5,14 @@ use Kelp::Test; use HTTP::Request::Common; use Test::More; -my $app = Kelp->new_anon( mode => 'test' ); +my $app = Kelp->new_anon(mode => 'test'); $app->routes->base('main'); my $t = Kelp::Test->new(app => $app); $app->add_route( "/safe/:val" => { method => 'GET', - to => "check_safe", + to => "check_safe", } ); @@ -23,7 +23,8 @@ $t->request(GET '/safe/tval?test=sth&test=sth_else') done_testing; -sub check_safe { +sub check_safe +{ my ($kelp, $val) = @_; # list context + parameter to param used to return all parameters with that diff --git a/t/subclassed.t b/t/subclassed.t index db88177..38bf016 100644 --- a/t/subclassed.t +++ b/t/subclassed.t @@ -6,10 +6,10 @@ use HTTP::Request::Common; use Test::More; use Test::Exception; -my $app = MyApp->new( mode => 'test' ); -my $t = Kelp::Test->new( app => $app ); +my $app = MyApp->new(mode => 'test'); +my $t = Kelp::Test->new(app => $app); -$t->request( GET '/test' ) +$t->request(GET '/test') ->code_isnt(500) ->content_is("OK") ->content_isnt("FAIL") @@ -17,17 +17,17 @@ $t->request( GET '/test' ) ->header_is("X-Test", "MyApp") ->header_isnt("X-Framework", "Perl Kelp"); -$t->request( GET '/missing' ) - ->code_is(404) - ->content_is("NO"); +$t->request(GET '/missing') + ->code_is(404) + ->content_is("NO"); -$t->request( GET '/greet/jack' ) - ->code_is(200) - ->content_is("OK jack"); +$t->request(GET '/greet/jack') + ->code_is(200) + ->content_is("OK jack"); -$t->request( GET '/bye/jack' ) - ->code_is(200) - ->content_is("BYE jack"); +$t->request(GET '/bye/jack') + ->code_is(200) + ->content_is("BYE jack"); done_testing; diff --git a/t/template.t b/t/template.t index 10864df..b27aa24 100644 --- a/t/template.t +++ b/t/template.t @@ -7,10 +7,10 @@ use utf8; my $text = "Hello, world! ☃\n"; -my $t = Kelp::Template->new( paths => ['views', 't/views']); -is $t->process( \$text ), $text, "Render SCALAR"; +my $t = Kelp::Template->new(paths => ['views', 't/views']); +is $t->process(\$text), $text, "Render SCALAR"; is $t->process('home.tt'), $text, "Render file"; -is $t->process(\*DATA ), $text, "Render GLOB"; +is $t->process(\*DATA), $text, "Render GLOB"; my $f = IO::File->new("t/views/home.tt", "<:encoding(utf8)") or die $!; is $t->process($f), $text, "Render IO object"; diff --git a/t/test_psgi.t b/t/test_psgi.t index 55b29e3..07e776d 100644 --- a/t/test_psgi.t +++ b/t/test_psgi.t @@ -2,7 +2,7 @@ use Kelp::Test; use HTTP::Request::Common qw/GET PUT POST DELETE/; use Test::More; -my $t = Kelp::Test->new( psgi => 't/test.psgi' ); -$t->request( GET '/say' )->content_is("OK"); +my $t = Kelp::Test->new(psgi => 't/test.psgi'); +$t->request(GET '/say')->content_is("OK"); done_testing; diff --git a/t/test_request.t b/t/test_request.t index 566878d..ae50cc5 100644 --- a/t/test_request.t +++ b/t/test_request.t @@ -7,17 +7,16 @@ use Test::Deep; use HTTP::Request::Common; use URI::Escape; -my $app = Kelp->new( mode => 'test' ); -my $t = Kelp::Test->new( app => $app ); +my $app = Kelp->new(mode => 'test'); +my $t = Kelp::Test->new(app => $app); # Request { - $app->add_route( '/a' => sub { 1 } ); - $t->request_ok( GET '/a' ); - $t->request( GET '//a' )->code_isnt(200); + $app->add_route('/a' => sub { 1 }); + $t->request_ok(GET '/a'); + $t->request(GET '//a')->code_isnt(200); } - # Cookies { my $cookie_val = 'kelper'; @@ -42,9 +41,9 @@ my $t = Kelp::Test->new( app => $app ); ); $t->cookies->set_cookie(undef, $user_cookie_name, $user_cookie_val); - $t->request_ok( GET '/auth' ); - $t->request_ok( GET '/user/foo' )->content_is($cookie_val); - $t->request_ok( GET '/user/' . uri_escape($user_cookie_name) )->content_is($user_cookie_val); + $t->request_ok(GET '/auth'); + $t->request_ok(GET '/user/foo')->content_is($cookie_val); + $t->request_ok(GET '/user/' . uri_escape($user_cookie_name))->content_is($user_cookie_val); # check if tester itself handles cookies is_deeply diff --git a/t/unicode.t b/t/unicode.t index e63b96b..9d9ebe3 100644 --- a/t/unicode.t +++ b/t/unicode.t @@ -8,14 +8,14 @@ use Encode; use URI::Escape; use utf8; -my $app = Kelp->new( mode => 'test' ); -my $t = Kelp::Test->new( app => $app ); +my $app = Kelp->new(mode => 'test'); +my $t = Kelp::Test->new(app => $app); my $test_string = 'zażółć gęslą jaźń ZAŻÓŁĆ GĘŚLĄ JAŹŃ'; -$app->add_route( [ POST => '/path_echo/:echo' ] => sub { return $_[1]; } ); -$app->add_route( [ POST => '/body_echo' ] => sub { return $_[0]->param('śś'); } ); -$app->add_route( [ POST => '/json_echo' ] => sub { return { 'śś' => $_[0]->param('śś') }; } ); +$app->add_route([POST => '/path_echo/:echo'] => sub { return $_[1]; }); +$app->add_route([POST => '/body_echo'] => sub { return $_[0]->param('śś'); }); +$app->add_route([POST => '/json_echo'] => sub { return {'śś' => $_[0]->param('śś')}; }); subtest 'path encoding no charset ok' => sub { my $string = uri_escape $app->charset_encode($test_string); @@ -26,7 +26,10 @@ subtest 'path encoding no charset ok' => sub { subtest 'path encoding cp1250 ok' => sub { my $string = uri_escape encode 'cp1250', $test_string; - _t("/path_echo/$string", 'application/x-www-form-urlencoded; charset=cp1250', '', 200, encode($app->charset, $test_string)); + _t( + "/path_echo/$string", 'application/x-www-form-urlencoded; charset=cp1250', + '', 200, encode($app->charset, $test_string) + ); }; subtest 'plaintext encoding no charset ok' => sub { @@ -38,25 +41,37 @@ subtest 'plaintext encoding no charset ok' => sub { subtest 'plaintext encoding utf8 ok' => sub { my $string = join '=', map { uri_escape encode 'utf-8', $_ } 'śś', $test_string; - _t('/body_echo', 'application/x-www-form-urlencoded; charset=utf-8', $string, 200, encode($app->charset, $test_string)); + _t( + '/body_echo', 'application/x-www-form-urlencoded; charset=utf-8', + $string, 200, encode($app->charset, $test_string) + ); }; subtest 'plaintext encoding cp1250 ok' => sub { my $string = join '=', map { uri_escape encode 'cp1250', $_ } 'śś', $test_string; - _t('/body_echo', 'application/x-www-form-urlencoded; charset=cp1250', $string, 200, encode($app->charset, $test_string)); + _t( + '/body_echo', 'application/x-www-form-urlencoded; charset=cp1250', + $string, 200, encode($app->charset, $test_string) + ); }; subtest 'plaintext encoding CP1250 ok' => sub { my $string = join '=', map { uri_escape encode 'cp1250', $_ } 'śś', $test_string; - _t('/body_echo', 'application/x-www-form-urlencoded; CHARSET=CP1250', $string, 200, encode($app->charset, $test_string)); + _t( + '/body_echo', 'application/x-www-form-urlencoded; CHARSET=CP1250', + $string, 200, encode($app->charset, $test_string) + ); }; subtest 'plaintext encoding unknown is utf8 ok' => sub { my $string = join '=', map { uri_escape encode 'utf-8', $_ } 'śś', $test_string; - _t('/body_echo', 'application/x-www-form-urlencoded; charset=xxnotanencoding', $string, 200, encode($app->charset, $test_string)); + _t( + '/body_echo', 'application/x-www-form-urlencoded; charset=xxnotanencoding', + $string, 200, encode($app->charset, $test_string) + ); }; subtest 'plaintext encoding unknown is not utf8 error ok' => sub { @@ -71,17 +86,19 @@ subtest 'json encoding ok' => sub { _t('/json_echo', 'application/json', $string, 200, $string); }; -sub _t { - my ( $target, $ct, $content, $code, $expected, %headers) = @_; +sub _t +{ + my ($target, $ct, $content, $code, $expected, %headers) = @_; - $t->request( POST $target, + $t->request( + POST $target, 'Content-Type' => $ct, %headers, 'Content' => $content, )->code_is($code); if ($expected) { - is $t->res->content, $expected, "expected string to $target ($ct) ok" + is $t->res->content, $expected, "expected string to $target ($ct) ok"; } } diff --git a/t/util.t b/t/util.t index 96764ed..939a35b 100644 --- a/t/util.t +++ b/t/util.t @@ -7,46 +7,46 @@ use Kelp::Util; subtest 'testing camelize' => sub { my %h = ( - 'a#b' => 'A::b', - 'bar#foo' => 'Bar::foo', - 'bar_foo#baz' => 'BarFoo::baz', - 'bar_foo#baz_bat' => 'BarFoo::baz_bat', - 'BarFoo#baz' => 'Barfoo::baz', - 'barfoo#BAZ' => 'Barfoo::BAZ', + 'a#b' => 'A::b', + 'bar#foo' => 'Bar::foo', + 'bar_foo#baz' => 'BarFoo::baz', + 'bar_foo#baz_bat' => 'BarFoo::baz_bat', + 'BarFoo#baz' => 'Barfoo::baz', + 'barfoo#BAZ' => 'Barfoo::BAZ', 'bar_foo_baz_bat#moo' => 'BarFooBazBat::moo', - 'a' => 'a', - 'M::D::f' => 'M::D::f', - 'R_E_S_T#asured' => 'REST::asured', - 'REST::Assured::ok' => 'REST::Assured::ok', - 'REST' => 'REST', + 'a' => 'a', + 'M::D::f' => 'M::D::f', + 'R_E_S_T#asured' => 'REST::asured', + 'REST::Assured::ok' => 'REST::Assured::ok', + 'REST' => 'REST', ); - for my $k ( keys %h ) { - is( Kelp::Util::camelize($k), $h{$k}, "base $k" ); - is( Kelp::Util::camelize($k, 'Boo'), 'Boo::' . $h{$k}, "$k with namespace" ); - is( Kelp::Util::camelize($k, ''), $h{$k}, "$k with empty namespace" ); + for my $k (keys %h) { + is(Kelp::Util::camelize($k), $h{$k}, "base $k"); + is(Kelp::Util::camelize($k, 'Boo'), 'Boo::' . $h{$k}, "$k with namespace"); + is(Kelp::Util::camelize($k, ''), $h{$k}, "$k with empty namespace"); } - is( Kelp::Util::camelize(''), '', 'empty ok' ); - is( Kelp::Util::camelize('', 'Boo'), '', 'empty with class ok' ); + is(Kelp::Util::camelize(''), '', 'empty ok'); + is(Kelp::Util::camelize('', 'Boo'), '', 'empty with class ok'); }; subtest 'testing extract_class' => sub { my %h = ( - 'A::b' => 'A', - 'Bar::foo' => 'Bar', - 'BarFoo::baz' => 'BarFoo', - 'BarFooBazBat::moo' => 'BarFooBazBat', - 'a' => undef, - 'M::D::f' => 'M::D', - 'REST::Assured::ok' => 'REST::Assured', - 'main::ok' => undef, - '' => undef, + 'A::b' => 'A', + 'Bar::foo' => 'Bar', + 'BarFoo::baz' => 'BarFoo', + 'BarFooBazBat::moo' => 'BarFooBazBat', + 'a' => undef, + 'M::D::f' => 'M::D', + 'REST::Assured::ok' => 'REST::Assured', + 'main::ok' => undef, + '' => undef, ); - for my $k ( keys %h ) { + for my $k (keys %h) { if (defined $h{$k}) { - is( Kelp::Util::extract_class($k), $h{$k}, $k ); + is(Kelp::Util::extract_class($k), $h{$k}, $k); } else { ok !defined Kelp::Util::extract_class($k), $k; @@ -57,16 +57,16 @@ subtest 'testing extract_class' => sub { subtest 'testing extract_function' => sub { my %h = ( - 'A::b' => 'b', - 'BarFoo::baz' => 'baz', - 'a' => 'a', - 'M::D::f' => 'f', - '' => undef, + 'A::b' => 'b', + 'BarFoo::baz' => 'baz', + 'a' => 'a', + 'M::D::f' => 'f', + '' => undef, ); - for my $k ( keys %h ) { + for my $k (keys %h) { if (defined $h{$k}) { - is( Kelp::Util::extract_function($k), $h{$k}, $k ); + is(Kelp::Util::extract_function($k), $h{$k}, $k); } else { ok !defined Kelp::Util::extract_function($k), $k;