#!/usr/bin/perl use strict; use warnings; use YAML; use File::Spec; use Template; use PadWalker 'peek_my'; sub dir { mkdir File::Spec->catfile(@_), 0777 } sub file { my @args = @_; my $tmpl = pop @args; my $ofile = File::Spec->catfile(@args); my $tt = Template->new( TAG_STYLE => 'asp' ); $tt->process(\$tmpl, {proj => ${peek_my(1)->{'$proj'}}}, $ofile) or die $tt->error; $ofile; } sub executable($) { chmod oct(766), shift } my $proj = shift @ARGV or die "Usage: $0 ProjectName"; dir $proj; dir $proj, 'lib'; dir $proj, 'tmpl'; dir $proj, 'htdocs'; dir $proj, 'htdocs', 'js'; dir $proj, 'htdocs', 'css'; file $proj, 'lib', "$proj.pm" => <<'...'; package <% proj %>; use strict; use warnings; 1; ... file $proj, 'lib', $proj, "C.pm" => <<'...'; package <% proj %>::C; use strict; use warnings; use strict; use warnings; use base 'Sledge::Pages::CGI'; use Sledge::Template::TT; use Scalar::Util qw/blessed/; use Carp; use Sledge::Utils; use autobox; use autobox::Core; use Sledge::Plugin::Stash; use Template::Provider::Encoding; use Sledge::Authorizer::Null; sub create_authorizer { Sledge::Authorizer::Null->new(shift) } use Sledge::SessionManager::Null; sub create_manager { Sledge::SessionManager::Null->new(shift) } use Sledge::Session::File; sub create_session { Sledge::Session::File->new(shift) } use Sledge::Charset::UTF8; sub create_charset { Sledge::Charset::UTF8->new(shift) } use <% proj %>::Config; sub create_config { <% proj %>::Config->instance } *config = *create_config; sub set_args { my ( $self, $args ) = @_; croak "this is instance method" unless blessed $self; $self->{args} = $args; $self; } sub args { shift->{args} } sub tmpl_dirname { my $class = shift; my $proto = ref $class || $class; $proto =~ s/^<% proj %>::C:://; my $ret = $proto->split(qr/::/)->map( sub { my $path = shift; String::CamelCase::decamelize($path); } )->join('/'); return "/$ret"; } __PACKAGE__->add_trigger( BEFORE_DISPATCH => sub { my $self = shift; $self->tmpl->add_option( LOAD_TEPLATES => [ Template::Provider::Encoding->new ], ); } ); 1; ... file $proj, 'lib', $proj, 'C', 'Root.pm' => <<'...'; package <% proj %>::C::Root; use strict; use warnings; use base '<% proj %>::C'; sub dispatch_index { } 1; ... file $proj, 'lib', $proj, 'Router.pm' => <<'...'; package <% proj %>::Router; use strict; use warnings; use Carp; use Switch; sub route { my ($class, $path) = @_; croak "path is empty" unless defined $path; switch ($path) { case '/' { return {controller => '<% proj %>::C::Root', page => 'index'}; } else { die "unknown path: $path"; } } } 1; ... file $proj, 'lib', $proj, 'Config.pm' => <<'...'; package <% proj %>::Config; use strict; use warnings; use Class::AutoAccess::Deep; use FindBin; use File::Spec; my $conf = { tmpl_path => File::Spec->catfile($FindBin::Bin, '..', 'tmpl'), }; sub instance { Class::AutoAccess::Deep->new($conf) } 1; ... file $proj, 'tmpl', 'include', 'header.html' => <<'...'; <% proj %> ... file $proj, 'tmpl', 'include', 'footer.html' => <<'...'; ... file $proj, 'tmpl', 'root', 'index.html' => <<'...'; [% INCLUDE 'include/header.html' %] Sledge Startup Page. [% INCLUDE 'include/footer.html' %] ... file $proj, 'htdocs', 'css', lc("$proj.css") => <<'...'; ... executable file $proj, 'script', lc("${proj}-lighty-runner.pl") => <<'...'; #!/usr/bin/perl use strict; use warnings; use FindBin; use Template; use File::Temp; my $fh = File::Temp->new; my $tt = Template->new; $tt->process( \*DATA, { fcgi_path => File::Spec->catfile( $FindBin::Bin, '<% proj | lower %>.fcgi' ), htdocs_path => File::Spec->catfile( $FindBin::Bin, '..', 'htdocs' ), }, $fh ) or die $tt->error; system 'lighttpd', '-D', '-f', $fh->filename; __END__ server.document-root = "[% htdocs_path %]" server.port = 1192 server.modules = ( "mod_fastcgi", "mod_setenv", ) mimetype.assign = ( "css" => "text/css", ) $HTTP["url"] =~"^/(?!favicon\.ico$|static/|js/|css/|images?)" { fastcgi.server = ( "/" => ( "<% proj | lower %>" => ( "bin-path" => "[% fcgi_path %]", "socket" => "/tmp/perl.<% proj | lower %>.socket", "max-procs" => 2, "idle-timeout" => 20, "check-local" => "disable", "broken-scriptfilename" => "enable" ) ), ) } ... executable file $proj, 'script', lc("${proj}.fcgi") => <<'...'; #!/usr/bin/perl use strict; use warnings; use CGI::Fast; use CGI::Carp qw(fatalsToBrowser); use CGI::Fast; use UNIVERSAL::require; use File::Spec; use FindBin; use lib File::Spec->catfile($FindBin::Bin, '..', 'lib'); use <% proj %>::Router; while ( my $q = CGI::Fast->new ) { my $info = <% proj %>::Router->route( $ENV{REQUEST_URI} ); $info->{controller}->use or die $@; $info->{controller}->new($q)->set_args( $info->{args} ) ->dispatch( $info->{page} ); } ... file $proj, 'Makefile.PL' => <<'...'; use inc::Module::Install; name '<% proj %>'; all_from 'lib/<% proj %>.pm'; license 'perl'; requires 'Sledge::Pages::Base'; requires 'Class::AutoAccess::Deep'; requires 'Sledge::Utils'; build_requires 'Test::More'; use_test_base; auto_include; WriteAll; ... file $proj, 't', '00_compile.t' => <<'...'; use strict; use warnings; use Test::More tests => 4; use_ok '<% proj %>::Config'; use_ok '<% proj %>::C'; use_ok '<% proj %>::Router'; use_ok '<% proj %>::C::Root'; ... chdir $proj; !system "perl Makefile.PL" or die $!; !system "make test" or die $!; !system "make distclean" or die $!;