File Coverage

blib/lib/App/CatalystStarter/Bloated.pm
Criterion Covered Total %
statement 42 44 95.4
branch n/a
condition n/a
subroutine 15 15 100.0
pod n/a
total 57 59 96.6


line stmt bran cond sub pod time code
1             package App::CatalystStarter::Bloated;
2              
3 14     14   118308 use v5.10.1;
  14         48  
4              
5 14     14   1517 use utf8::all;
  14         570403  
  14         135  
6 14     14   28461 use warnings;
  14         36  
  14         334  
7 14     14   71 use strict;
  14         25  
  14         323  
8 14     14   12063 use autodie;
  14         229395  
  14         71  
9 14     14   173331 use Carp;
  14         31  
  14         848  
10              
11 14     14   10853 use version; our $VERSION = qv('0.9.3');
  14         29518  
  14         81  
12              
13 14     14   3123 use File::Which qw(which);
  14         1831  
  14         767  
14 14     14   2550 use Path::Tiny qw(path cwd);
  14         21902  
  14         789  
15 14     14   7059 use Capture::Tiny qw(capture_stdout capture);
  14         81630  
  14         897  
16 14     14   33645 use DBI;
  14         259047  
  14         970  
17              
18 14     14   150 use List::Util qw/first/;
  14         28  
  14         1247  
19 14     14   10838 use List::MoreUtils qw/all/;
  14         133177  
  14         129  
20              
21 14     14   27810 use Log::Log4perl qw/:easy/;
  14         722271  
  14         80  
22              
23 14     14   20872 use App::CatalystStarter::Bloated::Initializr;
  0            
  0            
24              
25             my $cat_dir;
26             my $logger = get_logger;
27             App::CatalystStarter::Bloated::Initializr::_set_logger($logger);
28             sub l{$logger}
29              
30             sub import {
31              
32             shift;
33             if (defined $_[0] and $_[0] eq ":test") {
34             Log::Log4perl->easy_init($FATAL);
35             }
36             elsif ($ARGV{'--debug'}) {
37             Log::Log4perl->easy_init($DEBUG);
38             }
39             else {
40             Log::Log4perl->easy_init($INFO);
41             }
42              
43             l->debug( "Log level set to DEBUG" );
44              
45             }
46              
47             ## related test files are listed at the closing } of each sub
48              
49             ## a helper for easy access to paths
50             sub _catalyst_path {
51             my $what = shift;
52             my @extra;
53             if ( $what eq "C" ) {
54             @extra = ("lib", $ARGV{"--name"}, "Controller");
55             }
56             elsif ( $what eq "M" ) {
57             @extra = ("lib", $ARGV{"--name"}, "Model");
58             }
59             elsif ( $what eq "V" ) {
60             @extra = ("lib", $ARGV{"--name"}, "View");
61             }
62             elsif ( $what eq "TT" ) {
63             @extra = ("lib", $ARGV{"--name"}, "View", $ARGV{"--TT"}.".pm");
64             @_ = ();
65             }
66             elsif ( $what eq "JSON" ) {
67             @extra = ("lib", $ARGV{"--name"}, "View", $ARGV{"--JSON"}.".pm");
68             @_ = ();
69             }
70             else {
71             @extra = ($what);
72             }
73             return path($cat_dir,@extra,@_)->absolute;
74             } ## catalyst_path.t
75             sub _set_cat_dir {
76             $cat_dir = $_[0] if defined $_[0];
77             return $cat_dir;
78             }
79             sub _creater {
80              
81             my($s) = path($cat_dir, "script")->children(qr/create\.pl/);
82             l->debug("located creater script $s" );
83              
84             return $s;
85              
86             } ## creater.t
87             sub _run_system {
88              
89             my @args = @_;
90             my @args_to_show = @args;
91              
92             my ($o,$e,$r);
93              
94             ## hide db password:
95             if (
96             $args_to_show[0] =~ /_create\.pl$/ and
97             $args_to_show[1] eq "model"
98             ) {
99             $args_to_show[8] = "<secret>" if
100             defined $args_to_show[8] and
101             $args_to_show[8] ne "";
102             }
103              
104             if ( $ARGV{"--verbose"} ) {
105             l->debug("system call [verbose]: @args_to_show");
106             $r = system @args;
107             }
108             else {
109             l->debug("system call: @args_to_show");
110             ($o,$e,$r) = capture { system @args };
111             }
112              
113             ## some known sdterr lines we do not show:
114             if ($e) {
115             my @e = split /\n/, $e;
116             my @e2 = @e;
117             @e2 = grep !/^Dumping manual schema for/, @e2;
118             @e2 = grep !/^Schema dump completed\./, @e2;
119             @e2 = grep !m{^Cannot determine perl version info from lib/.*\.pm}, @e2;
120              
121             ## hide all if we're testing non-verbosely
122             @e2 = () if "@args" eq "make test" and not $ARGV{'--verbose'};
123              
124             print $_,"\n" for @e2;
125             }
126              
127             if ( $r ) {
128             l->fatal( "system call died. It definitely shouldn't have." );
129             l->fatal( "command was: @args_to_show" );
130             }
131              
132             }
133             sub _finalize_argv {
134              
135             my $dsn_0 = $ARGV{'--dsn'};
136              
137             ## some booleans default on
138             if ( not $ARGV{'--nodsnfix'} ) {
139             $ARGV{'--dsnfix'} = $ARGV{'-dsnfix'} = 1
140             }
141              
142             if ( not $ARGV{'--nopgpass'} ) {
143             $ARGV{'--pgpass'} = $ARGV{'-pgpass'} = 1
144             }
145             ## defaults done
146              
147             ## html5 sets TT
148             if ($ARGV{'--html5'}) {
149             $ARGV{'-TT'} //= "HTML";
150             $ARGV{'--TT'} //= "HTML";
151             }
152              
153             ## views triggers json and tt
154             if ( $ARGV{'--views'} ) {
155             my %map;
156             @map{qw/-TT --TT -JSON --JSON/} = qw/HTML HTML JSON JSON/;
157             for (qw/-TT --TT -JSON --JSON/) {
158             $ARGV{$_} ||= $map{$_};
159             }
160             }
161              
162             ## model can have the dsn
163             if (defined $ARGV{'--model'} and $ARGV{'--model'} =~ /^dbi:/i ) {
164             $ARGV{'--dsn'} = $ARGV{'--model'};
165             $ARGV{'--model'} = 1;
166             }
167              
168             ## dsn gets a brush up
169             if ($ARGV{'--dsn'}) {
170              
171             if ( $ARGV{'--dsnfix'} ) {
172             $ARGV{'--dsn'} = _prepare_dsn( $ARGV{'--dsn'} );
173             $ARGV{'-dsn'} = $ARGV{'--dsn'};
174             }
175              
176             if ( not defined $ARGV{'--model'} ) {
177             $ARGV{'--model'} = 1;
178             }
179              
180             }
181              
182             ## model might have defaults
183             if ( $ARGV{'--model'} ) {
184              
185             if ( $ARGV{'--model'} eq '1' ) {
186             $ARGV{'--model'} = $ARGV{'--name'} . 'DB';
187             }
188              
189             $ARGV{'--model'} =~ s/^AppNameDB$/$ARGV{'--name'}DB/;
190             $ARGV{'-model'} = $ARGV{'--model'};
191              
192             if ( not $ARGV{'--schema'} or $ARGV{'--schema'} eq "1" ) {
193             $ARGV{'--schema'} = $ARGV{'--name'} . '::Schema';
194              
195             $ARGV{'-schema'} = $ARGV{'--schema'};
196              
197             }
198              
199             }
200             else {
201             delete $ARGV{'--schema'};
202             delete $ARGV{'-schema'};
203             }
204              
205             ## some defaults that will work for sqlite at least
206             $ARGV{'--dbuser'} //= "";
207             $ARGV{'--dbpass'} //= "";
208              
209             if ( defined $dsn_0 and $dsn_0 ne $ARGV{'--dsn'} ) {
210             l->debug( "dsn changed to '$ARGV{'--dsn'}'" );
211             }
212              
213             } ## finalize_argv.t
214              
215             ## dsn related
216             sub _prepare_dsn {
217              
218             my $dsn = shift;
219              
220             return $dsn if $ARGV{'--nodsnfix'};
221              
222             ## unlikely but guess it could happen
223             l->debug("Prepended litteral 'dbi' to dsn") if $dsn =~ s/^:/dbi:/;
224              
225             ## if it doesn't start with dbi: by now, we'll nicely provide that
226             if ( lc substr( $dsn, 0, 4 ) ne "dbi:" ) {
227             l->debug("Prepended 'dbi:' to dsn");
228             $dsn = "dbi:" . $dsn;
229             }
230              
231             ## taking care of case, should there be issues
232             l->info("Setting dsn scheme to lowercase 'dbi:'" )
233             if $dsn =~ /^.{0,2}[DBI]/;
234             $dsn =~ s/^dbi:/dbi:/i;
235              
236             ## if it doesn't end with a ":" but has one alerady, we'll append
237             ## one, should be enough to make it parseable by DBI, ie dbi:Pg
238             ## will do
239             if ( $dsn =~ y/:// == 1 and $dsn =~ /^dbi:/ and $dsn !~ /:$/ ) {
240             l->info("Appending ':' to make dsn valid");
241             $dsn .= ":";
242             }
243              
244             ## offer to correct the driver
245             my @parts = DBI->parse_dsn( $dsn );
246             my $driver = _fix_dbi_driver_case( $parts[1] );
247              
248             my $case_fixed_dsn = sprintf(
249             "%s:%s%s:%s",
250             $parts[0],
251             $driver, $parts[2]||"",
252             $parts[4]
253             );
254              
255             my $pgpass_fixed_dsn = _complete_dsn_from_pgpass($case_fixed_dsn);
256             return $pgpass_fixed_dsn;
257              
258             } ## dsn.t
259             sub _parse_dbi_dsn {
260              
261             my $dsn = shift;
262              
263             return unless defined $dsn;
264              
265             my @pairs = split /;/, $dsn;
266              
267             my %data;
268              
269             for (@pairs) {
270             my ($k,$v) = split /=/, $_;
271             $data{$k} = $v;
272             }
273              
274             my $db = first {$_} delete @data{qw/db database dbname/};
275             $data{database} = $db;
276              
277             my $host = first {$_} delete @data{qw/host hostname/};
278             $data{host} = $host;
279              
280             $data{port} //= undef;
281              
282             return %data;
283              
284             } ## dsn.t
285             sub _parse_dsn {
286              
287             my $dsn = shift ;
288              
289             my @parsed = DBI->parse_dsn($dsn);
290              
291             my $driver = _fix_dbi_driver_case($parsed[1]);
292              
293             my %hash = (driver => $driver, scheme => $parsed[0],
294             attr_string => $parsed[2]);
295              
296             my %extra = _parse_dbi_dsn($parsed[4]);
297              
298             %hash = (%hash, %extra);
299              
300             return %hash;
301              
302             } ## dsn.t
303             sub _known_drivers {
304             return qw/ ADO CSV DB2 DBM Firebird MaxDB mSQL mysql mysqlPP ODBC
305             Oracle Pg PgPP PO SQLite SQLite2 TSM XBase /;
306             }
307             sub _fix_dbi_driver_case {
308             my @args = @_;
309             my %hash;
310             $hash{ lc $_ } = $_ for _known_drivers;
311             ($_ = $hash{lc $_} || $_) for @args;
312              
313             if (not wantarray and @args == 1) {
314             return $args[0];
315             }
316             return @args;
317             } ## fix_dbi_driver_case.t
318             sub _dsn_hash_to_dsn_string {
319             my %dsn_hash = @_;
320              
321             my %dsn_last_part = %dsn_hash;
322             my @first_parts = delete @dsn_last_part{qw/scheme driver attr_string/};
323             $_ //= "" for @first_parts;
324              
325             my $last_part = "";
326             while ( my($k,$v) = each %dsn_last_part ) {
327             next if not defined $v or $v eq "";
328             $last_part .= "$k=$v;";
329             }
330             $last_part =~ s/;$//;
331              
332             my $fixed_dsn = sprintf(
333             "%s:%s%s:%s",
334             @first_parts,
335             $last_part
336             );
337              
338             return $fixed_dsn;
339              
340             }
341              
342              
343             ## pgpass functions
344             sub _parse_pgpass {
345              
346             if (not -r path("~/.pgpass")) {
347             l->debug( "~/.pgpass doesn't exist or can't be read" );
348             return;
349             }
350              
351             open my $fh, "<", path("~/.pgpass");
352              
353             my @entries;
354              
355             while ( <$fh> ) {
356             chomp;
357             my @values = split /:/, $_;
358              
359             my %row;
360             @row{qw/host port database user pass/} = @values;
361              
362             ## not sure if this can ever happen
363             $row{port} //= 5432;
364              
365             push @entries, \%row;
366              
367             }
368              
369             l->debug(sprintf "Parsed %d entries from ~/.pgpass",
370             scalar @entries );
371              
372             return @entries;
373              
374             } ## pgpass.t
375             sub _pgpass_entry_to_dsn {
376              
377             my $entry = shift;
378             my $dsn = "dbi:Pg:";
379              
380             if ( my $d = $entry->{database} ) {
381             $dsn .= "database=" . $d . ";";
382             }
383             if ( my $h = $entry->{host} ) {
384             ## don't add if it's localhost
385             $dsn .= "host=" . $h . ";" if $h !~ /^localhost(?:$|\.)/;
386             }
387             if ( my $p = $entry->{port} ) {
388             ## don't add if its default 5432
389             $dsn .= "port=" . $p . ";" if $p != 5432;
390             }
391              
392             $dsn =~ s/;$//;
393              
394             return $dsn;
395              
396             } ## pgpass.t
397             sub _complete_dsn_from_pgpass {
398              
399             my $dsn = shift;
400              
401             ## return unless there is a ~/.pgpass
402             my @pgpass = _parse_pgpass or return $dsn;
403              
404             my %dsn = _parse_dsn( $dsn );
405              
406             ## only works with pg for obvious reasons
407             if ( $dsn{driver} ne "Pg") {
408             return $dsn;
409             }
410              
411             ## if all is already set, no point to linger
412             if ( all {$_} (@dsn{qw/database port host/},
413             @ARGV{qw/--dbuser --dbpass/}) ) {
414             return $dsn;
415             }
416              
417             my @candidate_pgpass =
418             do {
419              
420             grep {
421              
422             my $entry = $_;
423              
424             all {
425              
426             # my $test = (not defined $dsn{$_} or
427             # ($dsn{$_}||"") eq ($entry->{$_}||""));
428              
429             # print "# $_; test is ", $test, "\n";
430              
431             ## This allows flexible matching, as long as there
432             ## is one single match, it could be on anything of
433             ## host, db or port
434             not defined $dsn{$_} or
435             ($dsn{$_}||"") eq ($entry->{$_}||"");
436              
437             } qw/host database port/;
438              
439             } @pgpass;
440              
441             };
442              
443             if ( not @candidate_pgpass) {
444             l->info("Found no pgpass entries, not adding to dsn");
445             return $dsn;
446             }
447             elsif ( @candidate_pgpass == 1 ) {
448             l->info("Using one matching pgpass entry to add to dsn");
449              
450             _fill_dsn_parameters_from_pgpass_data
451             ( \%dsn, $candidate_pgpass[0] );
452              
453             $ARGV{'--dbuser'} //= $candidate_pgpass[0]->{user};
454             $ARGV{'--dbpass'} //= $candidate_pgpass[0]->{pass};
455             }
456             # elsif ( @candidate_pgpass < 6 and not $ARGV{'--noconnectiontest'} ) {
457              
458             # ## in future we will grep for working connections
459             # my @passed_candidates = grep {
460              
461             # }
462              
463             # }
464             else {
465             ## too many matches, don't bother
466             l->info( sprintf "Too many (%d) matching ~/.pgpass entries found - using none",
467             scalar @candidate_pgpass );
468             return $dsn;
469             }
470              
471             return _dsn_hash_to_dsn_string( %dsn );
472              
473             }
474             sub _fill_dsn_parameters_from_pgpass_data {
475              
476             ## $data is a single entry as parsed from .pgpass
477             my( $dsn_hash, $data ) = @_;
478              
479             $dsn_hash->{$_} //= $data->{$_} for qw/host database port/;
480              
481             }
482              
483             # create functions
484             sub _mk_app {
485              
486             _run_system( "catalyst.pl" => $ARGV{"--name"} );
487             l->info( sprintf "Created catalyst app '%s'", $ARGV{"--name"} );
488              
489             _set_cat_dir( $ARGV{"--name"} );
490              
491             } ## mk_app.t
492             sub _create_TT {
493              
494             return unless my $tt = $ARGV{"--TT"};
495              
496             _run_system( _creater() => "view", $tt, "TT" );
497              
498             my $tt_pm = _catalyst_path( "TT" );
499              
500             if ( not -f $tt_pm ) {
501             l->error( "View module not found where it should be, exiting. " .
502             "You have to:\n 1: change ext to .tt2 and\n 2: set WRAPPER to wrapper.tt2." );
503             return;
504             }
505              
506             ## trust regex to modify the file
507             my $pm = $tt_pm->slurp;
508              
509             if ( $pm =~ s/(TEMPLATE_EXTENSION\s*=>\s*'.tt)(',)/${1}2$2/ ) {
510             l->debug("Changed template extension to .tt2");
511             }
512             else {
513             l->warn("Failed changing template extension to .tt2");
514             }
515              
516             if ( $pm =~ s/^(__PACKAGE__->config\()(\s+)/$1$2WRAPPER => 'wrapper.tt2',$2/ms ) {
517             l->debug( "Added wrapper.tt2" );
518             }
519             else {
520             l->warn( "Failed adding wrapper to view" );
521             }
522              
523             $tt_pm->spew( $pm );
524              
525             ## alter config to set default view
526             my $p = _catalyst_path( "lib", $ARGV{'--name'}.".pm" );
527             my $config = $p->slurp;
528             if ( $config =~ s/^(__PACKAGE__->config\()(\s+)/$1$2default_view => '$ARGV{"--TT"}',$2/ms ) {
529             l->debug( "Configured default view: " . $ARGV{'--TT'} );
530             $p->spew( $config );
531             }
532             else {
533             l->warn( "Failed configuring default view" );
534             }
535              
536             _catalyst_path( "root", "index.tt2" )->spew
537             ( "Welcome to the brand new [% c.config.name %]!" );
538             l->debug( "Wrote a basic index.tt2" );
539              
540              
541             _catalyst_path( "root", "wrapper.tt2" )->spew
542             ( "[% content %]\n" );
543             l->debug( "Wrote an empty wrapper.tt2" );
544              
545              
546             ## make index run template
547             my $r = _catalyst_path( "C", "Root.pm" );
548              
549             my $substitute_this = q[$c->response->body( $c->welcome_message );];
550             (my $root = $r->slurp) =~ s|\Q$substitute_this|# $&| and l->debug( "Commented response body message in sub index" );
551              
552             $r->spew( $root );
553              
554             l->info( sprintf "Created TT view as %s::View::%s",
555             @ARGV{qw/--name --TT/}
556             );
557              
558             _verify_TT_view();
559             _verify_Root_index();
560              
561             } ## create.tt
562             sub _create_JSON {
563              
564             return unless my $json = $ARGV{"--JSON"};
565              
566             _run_system( _creater() => "view", $json, "JSON" );
567              
568             my $p = _catalyst_path( "JSON" );
569             my $json_code = $p->slurp;
570              
571             my $extra = <<'JSON';
572              
573             __PACKAGE__->config(
574             # expose only the json key in stash
575             expose_stash => [ qw(json) ],
576             );
577             JSON
578              
579             if ( not $json_code =~ s/use base 'Catalyst::View::JSON';/$&\n$extra/ ) {
580             # l->error("failed configuring expose_stash in json");
581             }
582              
583             $p->spew( $json_code );
584              
585             l->info( sprintf "Created JSON view as %s::View::%s",
586             @ARGV{qw/--name --JSON/}
587             );
588              
589             _verify_JSON_view();
590              
591             } ## create_json.tt
592             sub _mk_views {
593              
594             if ( $ARGV{'--TT'} ) {
595             _create_TT;
596             }
597              
598             if ( $ARGV{'--JSON'} ) {
599             _create_JSON;
600             }
601              
602             }
603             sub _mk_model {
604              
605             return unless my $model_name = $ARGV{'--model'};
606              
607             _run_system( _creater() => "model", $model_name,
608             "DBIC::Schema", $ARGV{'--schema'},
609             "create=static",
610             @ARGV{qw/--dsn --dbuser --dbpass/},
611             );
612              
613             l->info(sprintf "Created model: dsn=%s, model=%s and schema=%s",
614             @ARGV{qw/--dsn --model --schema/}
615             );
616              
617             }
618             sub _mk_html5 {
619              
620             if ( not $ARGV{'--html5'} ) {
621             return
622             }
623              
624             App::CatalystStarter::Bloated::Initializr::deploy( _catalyst_path("root") );
625              
626             _catalyst_path( "root", "index.tt2" )->spew(<<'EOS');
627             <div class="row">
628              
629             <div class="col-lg-4">
630             <h2>Hi there</h2>
631             <p>Welcome to the brand new [% c.config.name %]!</p>
632             </div>
633              
634             <div class="col-lg-4">
635             <h2>Nav bar on top</h2>
636             <p>Nav bar setup is easily parameterized or edited in source.</p>
637             </div>
638              
639             <div class="col-lg-4">
640             <h2>Jumbotron</h2>
641             <p>The Jumbotron goes away is c->stash->{jumbotron} is not set. The
642             template comes from initializr.com. More templates will come in future
643             updates.</p>
644             <p><a class="btn btn-default" href="http://www.initializr.com">View details &raquo;</a></p>
645             </div>
646              
647             </div>
648             EOS
649              
650             my $p = _catalyst_path( "C", "Root.pm" );
651              
652             my $substitute_this = q[$c->response->body( $c->welcome_message );];
653             my $with_this = q[$c->stash->{jumbotron} = { header => "Splashy message", body => "This is a 'jumbotron' header, view source and check Root controller for details" };] . "\n";
654             (my $root = $p->slurp) =~ s|(?:# )?\Q$substitute_this|$&\n $with_this|
655             or l->error("Failed inserting jumbotron");
656              
657             $p->spew( $root );
658              
659             _verify_Root_jumbatron();
660              
661             }
662              
663              
664             ## test related
665             sub _test_new_cat {
666              
667             return if $ARGV{'--notest'};
668              
669             chdir $cat_dir;
670              
671             ## Assumes cwd is at cat_dir
672             if ( _run_system "perl" => "Makefile.PL" ) {
673             l->error( "Makefile.PL failed" );
674             return;
675             }
676             elsif ( _run_system "make" ) {
677             l->error( "make failed" );
678             return;
679             }
680             elsif ( _run_system "make" => "test" ) {
681             l->error( "make test failed" );
682             return;
683             }
684              
685             l->info( "Catalyst tests ok" );
686              
687             chdir "..";
688              
689             }
690             sub _verify_TT_view {
691              
692             my $view_file = $_[0] || _catalyst_path( "TT" );
693              
694             return if not defined $view_file;
695              
696             eval { require $view_file };
697              
698             if ( $@ ) {
699             l->error( "$view_file contains errors and must be edited by hand." );
700             l->error( "$@" );
701             return;
702             }
703              
704             my $view_class = $ARGV{'--name'} . "::View::" . $ARGV{'--TT'};
705              
706             my $cnf = $view_class->config;
707             if ( not defined $cnf->{WRAPPER} or $cnf->{WRAPPER} ne "wrapper.tt2" ) {
708             l->error( "$view_class didn't get WRAPPER properly configured, must be fixed manually." );
709             }
710             if ( not defined $cnf->{TEMPLATE_EXTENSION} or $cnf->{TEMPLATE_EXTENSION} ne ".tt2" ) {
711             l->error( "$view_class didn't get TEMPLATE_EXTENSION properly configured, must be fixed manually." );
712             }
713              
714             l->debug( "Modifications to TT view ok" );
715              
716             } ## verify_tt.t
717             sub _verify_Root_index {
718              
719             my $root_controller_file = $_[0] || _catalyst_path( "C", "Root.pm" );
720              
721             if ( not ref $root_controller_file ) {
722             $root_controller_file = path( $root_controller_file );
723             }
724              
725             my $root_controller = $root_controller_file->slurp;
726              
727             if ( $root_controller =~ /^\s+\$c->response->body.*welcome_message/m ) {
728             l->error( "Failed fixing Root controller. Comment out the response body line." );
729             l->error( "Root contents:" );
730             l->error( $root_controller );
731             }
732              
733             l->debug( "Root controller set to run index.tt2" );
734              
735             }
736             sub _verify_Root_jumbatron {
737              
738             my $root_controller_file = $_[0] || _catalyst_path( "C", "Root.pm" );
739              
740             if ( not ref $root_controller_file ) {
741             $root_controller_file = path( $root_controller_file );
742             }
743              
744             my $root_controller = $root_controller_file->slurp;
745              
746             if ( $root_controller !~ /stash.*jumbotron.*header.*body/ ) {
747             l->error( "Failed adding jumbotron example to Root controller" );
748             }
749              
750             l->debug( "Sample jumbotron data added to Root controller" );
751              
752             }
753             sub _verify_JSON_view {
754              
755             my $view_file = $_[0] || _catalyst_path( "JSON" );
756              
757             return if not defined $view_file;
758              
759             eval { require $view_file };
760              
761             if ( $@ ) {
762             l->error( "$view_file contains errors and must be edited by hand." );
763             l->error( "$@" );
764             return;
765             }
766              
767             my $view_class = $ARGV{'--name'} . "::View::" . $ARGV{'--JSON'};
768              
769             my $cnf = $view_class->config;
770             if ( not defined $cnf->{expose_stash} or
771             ref $cnf->{expose_stash} ne "ARRAY" or
772             $cnf->{expose_stash}[0] ne "json"
773             ) {
774             l->error( "$view_class didn't get expose_stash properly configured, ".
775             "must be fixed manually, expected to be ['json']." );
776             }
777              
778             l->debug( "Modifications to JSON view ok" );
779              
780             } ## verify_json.t
781              
782             ## This does it all
783             sub run {
784              
785             ## complete with logic not covered in G::E
786             _finalize_argv;
787              
788             ## 1: Create a catalyst
789             _mk_app;
790              
791             ## 2: Create views
792             _mk_views;
793              
794             ## 3: Make model
795             _mk_model;
796              
797             ## 4: setup html template
798             _mk_html5;
799              
800             ## 5: test new catalyst
801             _test_new_cat;
802              
803             l->info( "Catalyst setup done" );
804              
805             }
806              
807             1; # Magic true value required at end of module
808             __END__
809              
810             =encoding utf8
811              
812             =head1 NAME
813              
814             App::CatalystStarter::Bloated - Creates a catalyst app, a TT view, a model and a HTML5 wrapper template from initalizr.com.
815              
816             =head1 VERSION
817              
818             This document describes App::CatalystStarter::Bloated version 0.9.3
819              
820             =head1 SYNOPSIS
821              
822             # dont use this module, use the installed script
823             # catalyst-fatstart.pl instead
824              
825             =head1 DESCRIPTION
826              
827             This distribution provides an alternative script to start catalyst
828             projects: catalyst-fatstart.pl
829              
830             This script takes a number of options, see catalyst-fatstart.pl
831             --usage , --man and --help
832              
833             In short it does the following:
834              
835             =over
836              
837             =item *
838              
839             Calls catalyst.pl to create the catalyst project
840              
841             =item *
842              
843             Sets up a TT view as ::HTML and a JSON view as ::JSON
844              
845             =item *
846              
847             If given a --dsn, runs create model and provides default names
848             for schema and model classes.
849              
850             =item *
851              
852             If using a dbi:Pg dsn, looks in your ~/.pgpass to find usernames
853             and passwords and even intelligently completes your dsn if you are
854             missing hostname and or port.
855              
856             =item *
857              
858             Sets up a TT wrapper based on a HTML5 template intializr.com and
859             points its css, js images and fonts to /static
860              
861             =back
862              
863             =head1 INTERFACE
864              
865             =head2 run
866              
867             The function that does it all.
868              
869             =head1 DIAGNOSTICS
870              
871             Will come in next version
872              
873             =head1 CONFIGURATION AND ENVIRONMENT
874              
875             App::CatalystStarter::Bloated requires no configuration files or environment variables.
876              
877             =head1 DEPENDENCIES
878              
879             Several. Makefile/Build should take care of them.
880              
881             =head1 INCOMPATIBILITIES
882              
883             None reported.
884              
885             =head1 BUGS AND LIMITATIONS
886              
887             No bugs have been reported.
888              
889             Please report any bugs or feature requests to
890             C<bug-app-catalyststarter-bloated@rt.cpan.org>, or through the web interface at
891             L<http://rt.cpan.org>.
892              
893              
894             =head1 SEE ALSO
895              
896             L<Catalyst::Runtime>
897              
898             =head1 AUTHOR
899              
900             Torbjørn Lindahl C<< <torbjorn.lindahl@gmail.com> >>
901              
902              
903             =head1 LICENCE AND COPYRIGHT
904              
905             Copyright (c) 2014, Torbjørn Lindahl C<< <torbjorn.lindahl@gmail.com> >>. All rights reserved.
906              
907             This module is free software; you can redistribute it and/or
908             modify it under the same terms as Perl itself. See L<perlartistic>.