From 0635e9e124b23afc459e838225d0b250079f61c5 Mon Sep 17 00:00:00 2001 From: Masahiro Chiba Date: Tue, 6 Sep 2011 05:02:17 +0900 Subject: [PATCH] initial import --- .gitignore | 27 +++++ .shipit | 6 ++ Changes | 5 + MANIFEST | 26 +++++ MANIFEST.SKIP | 70 +++++++++++++ Makefile.PL | 76 ++++++++++++++ README | 39 +++++++ author/requires.cpanm | 20 ++++ lib/Plack/Handler/Nginx.pm | 204 +++++++++++++++++++++++++++++++++++++ src/Plack-Handler-Nginx.xs | 130 +++++++++++++++++++++++ t/000_load.t | 10 ++ t/001_basic.t | 90 ++++++++++++++++ xshelper.h | 101 ++++++++++++++++++ xt/perlcritic.t | 20 ++++ xt/pod.t | 8 ++ xt/podcoverage.t | 9 ++ xt/podspell.t | 115 +++++++++++++++++++++ 17 files changed, 956 insertions(+) create mode 100644 .gitignore create mode 100644 .shipit create mode 100644 Changes create mode 100644 MANIFEST create mode 100644 MANIFEST.SKIP create mode 100644 Makefile.PL create mode 100644 README create mode 100644 author/requires.cpanm create mode 100644 lib/Plack/Handler/Nginx.pm create mode 100644 src/Plack-Handler-Nginx.xs create mode 100644 t/000_load.t create mode 100644 t/001_basic.t create mode 100644 xshelper.h create mode 100644 xt/perlcritic.t create mode 100644 xt/pod.t create mode 100644 xt/podcoverage.t create mode 100644 xt/podspell.t diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e0ab7af --- /dev/null +++ b/.gitignore @@ -0,0 +1,27 @@ +Plack-Handler-Nginx-* +.* +!.gitignore +!.shipit +!.dim.pl +*.o +*.obj +*.bs +*.def +Makefile* +!Makefile.PL +*blib +META.* +MYMETA.* +*.out +*.bak +*.old +*~ +*.swp +ppport.h +nytprof* +cover_db* +*.gcda +*.gcno +*.gcov +*.stackdump +src/*.c diff --git a/.shipit b/.shipit new file mode 100644 index 0000000..687cd76 --- /dev/null +++ b/.shipit @@ -0,0 +1,6 @@ +steps = FindVersion, ChangeAllVersions, CheckChangeLog, DistTest, Commit, Tag, MakeDist, UploadCPAN + +git.tagpattern = %v +git.push_to = origin + +CheckChangeLog.files = Changes diff --git a/Changes b/Changes new file mode 100644 index 0000000..a130799 --- /dev/null +++ b/Changes @@ -0,0 +1,5 @@ +Revision history for Perl extension Plack::Handler::Nginx + +NEXT <> + - original version; created by dim + at Tue Sep 6 00:10:45 2011. diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 0000000..6997ad1 --- /dev/null +++ b/MANIFEST @@ -0,0 +1,26 @@ +.shipit +Changes +inc/Module/Install.pm +inc/Module/Install/AuthorTests.pm +inc/Module/Install/Base.pm +inc/Module/Install/Can.pm +inc/Module/Install/Makefile.pm +inc/Module/Install/Metadata.pm +inc/Module/Install/Repository.pm +inc/Module/Install/WriteAll.pm +inc/Module/Install/XSUtil.pm +lib/Plack/Handler/Nginx.pm +Makefile.PL +MANIFEST This list of files +MANIFEST.SKIP +META.yml +ppport.h +README +src/Plack-Handler-Nginx.xs +t/000_load.t +t/001_basic.t +xshelper.h +xt/perlcritic.t +xt/pod.t +xt/podcoverage.t +xt/podspell.t diff --git a/MANIFEST.SKIP b/MANIFEST.SKIP new file mode 100644 index 0000000..2fb64af --- /dev/null +++ b/MANIFEST.SKIP @@ -0,0 +1,70 @@ + +#!start included /home/chiba/perl5/perlbrew/perls/perl-5.14.1/lib/site_perl/5.14.1/ExtUtils/MANIFEST.SKIP +# Avoid version control files. +\bRCS\b +\bCVS\b +\bSCCS\b +,v$ +\B\.svn\b +\B\.git\b +\B\.gitignore\b +\b_darcs\b +\B\.cvsignore$ + +# Avoid VMS specific MakeMaker generated files +\bDescrip.MMS$ +\bDESCRIP.MMS$ +\bdescrip.mms$ + +# Avoid Makemaker generated and utility files. +\bMANIFEST\.bak +\bMakefile$ +\bblib/ +\bMakeMaker-\d +\bpm_to_blib\.ts$ +\bpm_to_blib$ +\bblibdirs\.ts$ # 6.18 through 6.25 generated this + +# Avoid Module::Build generated and utility files. +\bBuild$ +\b_build/ +\bBuild.bat$ +\bBuild.COM$ +\bBUILD.COM$ +\bbuild.com$ + +# Avoid temp and backup files. +~$ +\.old$ +\#$ +\b\.# +\.bak$ +\.tmp$ +\.# +\.rej$ +\.swp$ + +# Avoid OS-specific files/dirs +# Mac OSX metadata +\B\.DS_Store +# Mac OSX SMB mount metadata files +\B\._ + +# Avoid Devel::Cover and Devel::CoverX::Covered files. +\bcover_db\b +\bcovered\b + +# Avoid MYMETA files +^MYMETA\. +#!end included /home/chiba/perl5/perlbrew/perls/perl-5.14.1/lib/site_perl/5.14.1/ExtUtils/MANIFEST.SKIP + + +# skip author's files +\bauthor\b + +\.bs$ +\.o(?:|bj|ld|ut)$ +nytprof +MYMETA\.yml$ + +src/.*\.c$ diff --git a/Makefile.PL b/Makefile.PL new file mode 100644 index 0000000..332c502 --- /dev/null +++ b/Makefile.PL @@ -0,0 +1,76 @@ +#!perl +use strict; +use warnings; +BEGIN { + unshift @INC, 'inc'; + + # author requires, or bundled modules + my @devmods = qw( + inc::Module::Install 1.00 + Module::Install::AuthorTests 0.002 + Module::Install::Repository 0.06 + Test::Requires 0.06 + Module::Install::XSUtil 0.32 + ); + my @not_available; + while(my($mod, $ver) = splice @devmods, 0, 2) { + eval qq{use $mod $ver (); 1} or push @not_available, $mod; + } + if(@not_available) { + print qq{# The following modules are not available.\n}; + print qq{# `perl $0 | cpanm` will install them:\n}; + print $_, "\n" for @not_available; + exit 1; + } +} +use inc::Module::Install; + + +all_from 'lib/Plack/Handler/Nginx.pm'; + +use_xshelper; +cc_warnings; +cc_src_paths 'src'; + +my $nginx_src_path = $ARGV[0] || $ENV{NGINX_SRC_PATH} || '/tmp/nginx/'; +$nginx_src_path =~ s{/$}{}g; +unless ( + -d $nginx_src_path . '/src/http/' && + -d $nginx_src_path . '/src/http/modules/' && + -d $nginx_src_path . '/src/core/' && + -d $nginx_src_path . '/src/event/' && + -d $nginx_src_path . '/src/os/unix/' && + -d $nginx_src_path . '/objs/' +) { + print "Usage: perl Makefile.PL /path/to/nginx_src_path/\n"; + exit(-1); +} +cc_include_paths + $nginx_src_path . '/src/http/', + $nginx_src_path . '/src/http/modules/', + $nginx_src_path . '/src/core/', + $nginx_src_path . '/src/event/', + $nginx_src_path . '/src/os/unix/', + $nginx_src_path . '/objs/', +; + +test_requires 'Test::More' => '0.88'; +test_requires 'Test::Requires' => '0.06'; + +requires 'Plack'; + +auto_set_repository; + +tests_recursive; +author_tests 'xt'; + + +clean_files qw( + Plack-Handler-Nginx-* + *.stackdump + cover_db *.gcov *.gcda *.gcno + nytprof + *.out +); + +WriteAll(check_nmake => 0); diff --git a/README b/README new file mode 100644 index 0000000..de2be06 --- /dev/null +++ b/README @@ -0,0 +1,39 @@ +This is Perl module Plack::Handler::Nginx. + +INSTALLATION + +Type the following command: + + $ curl -L http://cpanmin.us | perl - Plack::Handler::Nginx + +Or install cpanm and then run the following command to install +Plack::Handler::Nginx: + + $ cpanm Plack::Handler::Nginx + +If you get an archive of this distribution, unpack it and build it +as per the usual: + + $ tar xzf Plack-Handler-Nginx-$version.tar.gz + $ cd Plack-Handler-Nginx-$version + $ perl Makefile.PL + $ make && make test + +Then install it: + + $ make install + +DOCUMENTATION + +Plack::Handler::Nginx documentation is available as in POD. So you can do: + + $ perldoc Plack::Handler::Nginx + +to read the documentation online with your favorite pager. + +LICENSE AND COPYRIGHT + +Copyright (c) 2011, Masahiro Chiba. All rights reserved. + +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself. diff --git a/author/requires.cpanm b/author/requires.cpanm new file mode 100644 index 0000000..5c58b6a --- /dev/null +++ b/author/requires.cpanm @@ -0,0 +1,20 @@ +# for Plack-Handler-Nginx +# Makefile.PL +Module::Install +Module::Install::AuthorTests +Module::Install::Repository +Module::Install::XSUtil + +# author's tests +Test::Pod +Test::Pod::Coverage +Test::Spelling +Test::Perl::Critic +Test::Synopsis +Test::LeakTrace +Test::Valgrind + +# Release tools +ShipIt +ShipIt::Step::ChangeAllVersions +CPAN::Uploader diff --git a/lib/Plack/Handler/Nginx.pm b/lib/Plack/Handler/Nginx.pm new file mode 100644 index 0000000..97eaf93 --- /dev/null +++ b/lib/Plack/Handler/Nginx.pm @@ -0,0 +1,204 @@ +package Plack::Handler::Nginx; +use strict; +use warnings; +use 5.008_001; +use nginx; +use Carp; +use Plack::Util (); + +our $VERSION = '0.01'; + +require XSLoader; +XSLoader::load('Plack::Handler::Nginx', $VERSION); + +my $null_io = do { open my $io, "<", \""; $io }; + +my %apps = (); + +sub load_app { + my $psgi_app = shift; + + $apps{$psgi_app} ||= do { + Plack::Util::load_psgi $psgi_app; + }; +} +sub handler { + my $r = shift; + + my $ret = $r->has_request_body(\&psgi_handler_read_body); + unless ( $ret ) { + return psgi_handler($r, $null_io); + } + return OK; +} + +sub psgi_handler { + my ( $r, $input ) = @_; + my $app = load_app($r->variable('psgi')); + + my $env = { + REQUEST_METHOD => $r->request_method, + SCRIPT_NAME => '', + PATH_INFO => $r->uri, + REQUEST_URI => $r->variable('request_uri'), + QUERY_STRING => defined $r->args ? $r->args : '', + SERVER_NAME => $r->variable('server_addr'), + SERVER_PORT => $r->variable('server_port'), + SERVER_PROTOCOL => $r->variable('server_protocol'), + REMOTE_ADDR => $r->remote_addr, + 'psgi.version' => [1, 1], + 'psgi.url_scheme' => $r->variable('scheme'), + 'psgi.input' => $input, + 'psgi.errors' => *STDERR, + 'psgi.multithread' => Plack::Util::FALSE, + 'psgi.multiprocess' => Plack::Util::TRUE, + 'psgi.run_once' => Plack::Util::FALSE, + 'psgi.nonblocking' => Plack::Util::TRUE, + 'psgi.streaming' => Plack::Util::TRUE, + }; + if ( ngx_plack_handler_http_header_set($r, $env) != 0 ) { + warn("http_header_set fail"); + return HTTP_INTERNAL_SERVER_ERROR; + } + + my $res = Plack::Util::run_app $app, $env; + + if ( ref $res eq 'ARRAY' ) { + write_response_header($r, $res); + write_response_body($r, $res->[2]); + } + elsif ( ref $res eq 'CODE' ) { + $res->( + sub { + my $res = shift; + + if ( @$res < 2 ) { + croak "Insufficient arguments"; + } + elsif ( @$res == 2 ) { + my ( $status, $headers ) = @$res; + + write_response_header($r, $res); + $r->rflush; + + return Plack::Util::inline_object + write => sub { $r->print($_[0]); $r->rflush; }, + close => sub {} + ; + } + else { + write_response_header($r, $res); + write_response_body($r, $res->[2]); + } + } + ); + } + else { + warn("Unknown response type: $res"); + return HTTP_INTERNAL_SERVER_ERROR; + } + + return OK; +} +sub psgi_handler_read_body { + my $r = shift; + + my $input; + my $body = $r->request_body; + if ( defined $body ) { + unless ( open $input, '<', \$body ) { + warn "read body: $!"; + return HTTP_INTERNAL_SERVER_ERROR; + } + } + else { + my $file = $r->request_body_file; + if ( $file && -f $file ) { + unless ( open $input, '<', $file ) { + warn "$file: $!"; + return HTTP_INTERNAL_SERVER_ERROR; + } + } + } + return psgi_handler($r, $input); +} + +sub write_response_header { + my $r = shift; + my $res = shift; + + $r->status($res->[0]); + + my $content_type = ''; + Plack::Util::header_iter($res->[1], sub { + if ( uc $_[0] eq 'CONTENT-TYPE' ) { + $content_type = $_[1]; + } + else { + $r->header_out($_[0], $_[1]); + } + }); + $r->send_http_header($content_type); +} + +sub write_response_body { + my $r = shift; + my $body = shift; + + if (Scalar::Util::blessed($body) and $body->can('path') and my $path = $body->path) { + $r->sendfile($path); + } + else { + Plack::Util::foreach($body, sub { $r->print($_[0]) }); + } +} + +1; + + + +__END__ + +=head1 NAME + +Plack::Handler::Nginx - nginx handlers to run PSGI application + +=head1 SYNOPSIS + + http { + ... + perl_require Plack/Handler/Nginx.pm; + ... + } + + location / { + set $psgi '/path/to/app.psgi'; + perl Plack::Handler::Nginx::handler; + } + +=head1 INSTALL + + NGINX_SRC_PATH=/path/to/nginx_src_path/ perl Makefile.PL + NGINX_BIN=/path/to/nginx_bin_path make test + make install + +=head1 DESCRIPTION + +This is a handler module to run any PSGI application with Nginx with EmbeddedPerlModule + +=head1 AUTHOR + +Masahiro Chiba + +=head1 SEE ALSO + +L + +=cut + +=head1 LICENSE + +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself. + +=cut diff --git a/src/Plack-Handler-Nginx.xs b/src/Plack-Handler-Nginx.xs new file mode 100644 index 0000000..452f953 --- /dev/null +++ b/src/Plack-Handler-Nginx.xs @@ -0,0 +1,130 @@ +#define NEED_newSVpvn_flags +#include "xshelper.h" +#include +#include +#include + +#define ngx_http_perl_set_request(r) \ + r = INT2PTR(ngx_http_request_t *, SvIV((SV *) SvRV(ST(0)))) + +#define MAX_HEADER_NAME_LEN 1024 + +STATIC_INLINE +char tou(char ch) +{ + if ('a' <= ch && ch <= 'z') + ch -= 'a' - 'A'; + return ch; +} + + +STATIC_INLINE +int strncmp_tou(const char* lname, const char* rname, size_t len) +{ + const char* x, * y; + for (x = lname, y = rname; len != 0; --len, ++x, ++y) + if (tou(*x) != *y) + return -1; + return 0; +} + +MODULE = Plack::Handler::Nginx PACKAGE = Plack::Handler::Nginx + +PROTOTYPES: DISABLE + +int +ngx_plack_handler_http_header_set(r, SV* envref) +CODE: +{ + ngx_http_request_t *r; + HV* env; + ngx_uint_t i; + ngx_table_elt_t *h; + ngx_list_part_t *part; + char tmp[MAX_HEADER_NAME_LEN + sizeof("HTTP_") -1]; + int ret; + + ret = 0; + + ngx_http_perl_set_request(r); + + if ( !SvROK(envref) ) { + Perl_croak(aTHX_ "nginx_http_header_set_to_env param should be a hashref"); + } + + env = (HV*)SvRV(envref); + if ( SvTYPE(env) != SVt_PVHV ) { + Perl_croak(aTHX_ "nginx_http_header_set_to_env param should be a hashref"); + } + + part = &r->headers_in.headers.part; + h = part->elts; + for (i = 0; /* void */ ; i++) { + const char* name; + size_t name_len; + SV** slot; + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + h = part->elts; + i = 0; + } + + if ( h[i].key.len == sizeof("CONTENT-TYPE") - 1 && + strncmp_tou((char*)h[i].key.data, "CONTENT-TYPE", sizeof("CONTENT-TYPE") - 1) == 0 + ) { + name = "CONTENT_TYPE"; + name_len = sizeof("CONTENT_TYPE") - 1; + } + else if ( h[i].key.len == sizeof("CONTENT-LENGTH") - 1 && + strncmp_tou((char*)h[i].key.data, "CONTENT-LENGTH", sizeof("CONTENT-LENGTH") - 1) == 0 + ) { + name = "CONTENT_LENGTH"; + name_len = sizeof("CONTENT_LENGTH") - 1; + } + else { + const char* s; + char* d; + size_t n; + + if (sizeof(tmp) - 5 < h[i].key.len ) { + ret = -1; + goto done; + } + + strcpy(tmp, "HTTP_"); + for ( + s = (char*)h[i].key.data, n = h[i].key.len, d = tmp + 5; + n != 0; + s++, --n, d++ + ) { + *d = *s == '-' ? '_' : tou(*s); + } + name = tmp; + name_len = h[i].key.len + 5; + } + + slot = hv_fetch(env, name, name_len, 1); + + if ( !slot ) + Perl_croak(aTHX_ "failed to create hash entry"); + + if ( SvOK(*slot)) { + sv_catpvn(*slot, ", ", 2); + sv_catpvn(*slot, (char*)h[i].value.data, h[i].value.len); + } + else { + sv_setpvn(*slot, (char*)h[i].value.data, h[i].value.len); + } + } + + done: + RETVAL = ret; +} +OUTPUT: + RETVAL + diff --git a/t/000_load.t b/t/000_load.t new file mode 100644 index 0000000..0bb4047 --- /dev/null +++ b/t/000_load.t @@ -0,0 +1,10 @@ +#!perl -w +use strict; +use Test::More tests => 1; +use Test::Requires 'nginx'; + +BEGIN { + use_ok 'Plack::Handler::Nginx'; +} + +diag "Testing Plack::Handler::Nginx/$Plack::Handler::Nginx::VERSION"; diff --git a/t/001_basic.t b/t/001_basic.t new file mode 100644 index 0000000..264b698 --- /dev/null +++ b/t/001_basic.t @@ -0,0 +1,90 @@ +#!perl -w +use strict; +use Test::More; + +use FindBin; +use Plack; +use Plack::Test::Suite; +use Cwd qw/realpath/; +my $blib_path = realpath($FindBin::Bin . '/../blib'); +my $tmpdir = $ENV{NGINX_TMP_DIR} || File::Temp::tempdir( CLEANUP => 1 ); +$tmpdir =~ s{/$}{}g; + +Plack::Test::Suite->run_server_tests(run_httpd(\&_render_conf)); +kill 'TERM', `cat $tmpdir/nginx_pid`; + +done_testing; + + +sub run_httpd { + my $render_conf = shift; + my $nginx_bin; + for my $_nginx_bin ( $ENV{NGINX_BIN}, '/usr/local/nginx/sbin/nginx', '/usr/sbin/nginx', '/usr/local/sbin/nginx' ) { + if ( $_nginx_bin && -f $_nginx_bin ) { + diag("nginx_bin: $_nginx_bin"); + $nginx_bin = $_nginx_bin; + last; + } + } + if ( !$nginx_bin ) { + die("not found nginx_bin") + } + sub { + my $port = shift; + + + write_file("$tmpdir/app.psgi", _render_psgi()); + write_file("$tmpdir/nginx.conf", $render_conf->($tmpdir, $port, "$tmpdir/app.psgi")); + + exec "$nginx_bin -c $tmpdir/nginx.conf"; + }; +} + + +sub write_file { + my($path, $content) = @_; + + open my $out, ">", $path or die "$path: $!"; + print $out $content; +} + + +sub _render_psgi { + return <<'EOF'; +use lib "blib"; +use Plack::Test::Suite; + +Plack::Test::Suite->test_app_handler; +EOF +} + + +sub _render_conf { + my ($tmpdir, $port, $psgi_path) = @_; + <<"END"; +pid $tmpdir/nginx_pid; +lock_file $tmpdir/nginx_lock; +error_log $tmpdir/error_log; + +events { + worker_connections 1024; + multi_accept on; +} + +http { + access_log off; + client_body_temp_path $tmpdir/client_body_temp; + merge_slashes off; + perl_modules $blib_path/lib; + perl_modules $blib_path/arch; + perl_require Plack/Handler/Nginx.pm; + server { + listen $port default; + location / { + set \$psgi '$tmpdir/app.psgi'; + perl Plack::Handler::Nginx::handler; + } + } +} +END +} diff --git a/xshelper.h b/xshelper.h new file mode 100644 index 0000000..b0ffc3f --- /dev/null +++ b/xshelper.h @@ -0,0 +1,101 @@ +/* THIS FILE IS AUTOMATICALLY GENERATED BY Module::Install::XSUtil 0.39. */ +/* +=head1 NAME + +xshelper.h - Helper C header file for XS modules + +=head1 DESCRIPTION + + // This includes all the perl header files and ppport.h + #include "xshelper.h" + +=head1 SEE ALSO + +L, where this file is distributed as a part of + +=head1 AUTHOR + +Fuji, Goro (gfx) Egfuji at cpan.orgE + +=head1 LISENCE + +Copyright (c) 2010, Fuji, Goro (gfx). All rights reserved. + +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself. + +=cut +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#define PERL_NO_GET_CONTEXT /* we want efficiency */ +#include +#include +#define NO_XSLOCKS /* for exceptions */ +#include + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#include "ppport.h" + +/* portability stuff not supported by ppport.h yet */ + +#ifndef STATIC_INLINE /* from 5.13.4 */ +# if defined(__GNUC__) || defined(__cplusplus) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) +# define STATIC_INLINE static inline +# else +# define STATIC_INLINE static +# endif +#endif /* STATIC_INLINE */ + +#ifndef __attribute__format__ +#define __attribute__format__(a,b,c) /* nothing */ +#endif + +#ifndef LIKELY /* they are just a compiler's hint */ +#define LIKELY(x) (!!(x)) +#define UNLIKELY(x) (!!(x)) +#endif + +#ifndef newSVpvs_share +#define newSVpvs_share(s) Perl_newSVpvn_share(aTHX_ STR_WITH_LEN(s), 0U) +#endif + +#ifndef get_cvs +#define get_cvs(name, flags) get_cv(name, flags) +#endif + +#ifndef GvNAME_get +#define GvNAME_get GvNAME +#endif +#ifndef GvNAMELEN_get +#define GvNAMELEN_get GvNAMELEN +#endif + +#ifndef CvGV_set +#define CvGV_set(cv, gv) (CvGV(cv) = (gv)) +#endif + +/* general utility */ + +#if PERL_BCDVERSION >= 0x5008005 +#define LooksLikeNumber(x) looks_like_number(x) +#else +#define LooksLikeNumber(x) (SvPOKp(x) ? looks_like_number(x) : (I32)SvNIOKp(x)) +#endif + +#define newAV_mortal() (AV*)sv_2mortal((SV*)newAV()) +#define newHV_mortal() (HV*)sv_2mortal((SV*)newHV()) +#define newRV_inc_mortal(sv) sv_2mortal(newRV_inc(sv)) +#define newRV_noinc_mortal(sv) sv_2mortal(newRV_noinc(sv)) + +#define DECL_BOOT(name) EXTERN_C XS(CAT2(boot_, name)) +#define CALL_BOOT(name) STMT_START { \ + PUSHMARK(SP); \ + CALL_FPTR(CAT2(boot_, name))(aTHX_ cv); \ + } STMT_END diff --git a/xt/perlcritic.t b/xt/perlcritic.t new file mode 100644 index 0000000..a18d885 --- /dev/null +++ b/xt/perlcritic.t @@ -0,0 +1,20 @@ +use strict; +use Test::More; +eval q{ + use Perl::Critic 1.105; + use Test::Perl::Critic -profile => \do { local $/; }; +}; +plan skip_all => "Test::Perl::Critic is not available." if $@; +all_critic_ok('lib'); +__DATA__ + +exclude=ProhibitStringyEval ProhibitExplicitReturnUndef RequireBarewordIncludes + +[TestingAndDebugging::ProhibitNoStrict] +allow=refs + +[TestingAndDebugging::RequireUseStrict] +equivalent_modules = Mouse Mouse::Role Mouse::Exporter Mouse::Util Mouse::Util::TypeConstraints Moose Moose::Role Moose::Exporter Moose::Util::TypeConstraints Any::Moose + +[TestingAndDebugging::RequireUseWarnings] +equivalent_modules = Mouse Mouse::Role Mouse::Exporter Mouse::Util Mouse::Util::TypeConstraints Moose Moose::Role Moose::Exporter Moose::Util::TypeConstraints Any::Moose diff --git a/xt/pod.t b/xt/pod.t new file mode 100644 index 0000000..1a7ed47 --- /dev/null +++ b/xt/pod.t @@ -0,0 +1,8 @@ +#!perl -w +use strict; +use Test::More; +eval q{use Test::Pod 1.14}; +plan skip_all => 'Test::Pod 1.14 required for testing POD' + if $@; + +all_pod_files_ok(); diff --git a/xt/podcoverage.t b/xt/podcoverage.t new file mode 100644 index 0000000..a8d9bb0 --- /dev/null +++ b/xt/podcoverage.t @@ -0,0 +1,9 @@ +#!perl -w +use Test::More; +eval q{use Test::Pod::Coverage 1.04}; +plan skip_all => 'Test::Pod::Coverage 1.04 required for testing POD coverage' + if $@; + +all_pod_coverage_ok({ + also_private => [qw(unimport BUILD DEMOLISH init_meta)], +}); diff --git a/xt/podspell.t b/xt/podspell.t new file mode 100644 index 0000000..d14a654 --- /dev/null +++ b/xt/podspell.t @@ -0,0 +1,115 @@ +#!perl -w +use strict; +use Test::More; + +eval q{ use Test::Spelling }; +plan skip_all => q{Test::Spelling is not available.} + if $@; + +my @stopwords; +while(my $line = ) { + $line =~ s/ \# [^\n]+ //xms; + push @stopwords, $line =~ /(\w+)/g; +} +add_stopwords(@stopwords); + +$ENV{LC_ALL} = 'C'; +all_pod_files_spelling_ok('lib'); + +__DATA__ +Masahiro Chiba +chiba@everqueue.com +Plack::Handler::Nginx + +# computer terms +API +APIs +arrayrefs +arity +Changelog +codebase +committer +committers +compat +cpan +extention +datetimes +dec +definedness +destructor +destructors +destructuring +dev +DWIM +GitHub +hashrefs +hotspots +immutabilize +immutabilizes +immutabilized +inline +inlines +invocant +invocant's +irc +IRC +isa +JSON +login +namespace +namespaced +namespaces +namespacing +OO +OOP +ORM +overridable +parameterizable +parameterization +parameterize +parameterized +parameterizes +params +pluggable +prechecking +prepends +rebase +rebased +rebasing +reblesses +refactored +refactoring +rethrows +RT +runtime +serializer +stacktrace +subclassable +subname +subtyping +TODO +unblessed +unexport +unimporting +Unported +unsets +unsettable +utils +whitelist +Whitelist +workflow +XS +MacOS +MacOSX +CLI +HTTP + +versa # vice versa +ish # something-ish +ness # something-ness +pre # pre-something +maint # co-maint + +EmbeddedPerlModule +PSGI +nginx