File Coverage

blib/lib/SweetPea.pm
Criterion Covered Total %
statement 261 557 46.8
branch 79 308 25.6
condition 10 81 12.3
subroutine 32 57 56.1
pod 33 33 100.0
total 415 1036 40.0


line stmt bran cond sub pod time code
1             package SweetPea;
2 19     19   653881 use 5.006;
  19         82  
  19         1212  
3              
4             =head1 NAME
5              
6             SweetPea - A web framework that doesn't get in the way, or suck.
7              
8             =cut
9              
10             BEGIN {
11 19     19   118 use Exporter();
  19         38  
  19         524  
12 19     19   95 use vars qw( @ISA @EXPORT @EXPORT_OK );
  19         43  
  19         1912  
13 19     19   354 @ISA = qw( Exporter );
14 19         641 @EXPORT = qw(sweet);
15             }
16              
17 19     19   62852 use CGI;
  19         486576  
  19         209  
18 19     19   23488 use CGI::Carp qw/fatalsToBrowser/;
  19         98715  
  19         155  
19 19     19   26234 use FindBin;
  19         42936  
  19         958  
20 19     19   137 use File::Find;
  19         42  
  19         51275  
21              
22             =head1 VERSION
23              
24             Version 2.3664
25              
26             =cut
27              
28             our $VERSION = '2.3664';
29              
30             =head1 DESCRIPTION
31              
32             SweetPea is a modern web application framework that is fast, scalable, and
33             light-weight. SweetPea has no dependencies so it runs everywhere Perl does.
34             SweetPea has a short learning curve and a common sense object-oriented API.
35              
36             =head1 SYNOPSIS
37              
38             Oh how Sweet web application development can be ...
39              
40             # from the command-line (requires SweetPea::Cli)
41             sweetpea make -s
42            
43             use SweetPea;
44             sweet->routes({
45            
46             '/' => sub {
47             shift->forward('/way');
48             },
49            
50             '/way' => sub {
51             shift->html('I am the way the truth and the light!');
52             }
53            
54             })->run;
55              
56             =cut
57              
58             =head1 DOCUMENTATION
59              
60             Learn more about SweetPea here, L
61              
62             Also Note!
63             The sweetpea application generator script has been moved to
64             L and the usage and syntax has changed a bit.
65              
66             =head1 METHODS
67              
68             =head2 new
69              
70             I
71              
72             new B
73              
74             =over 3
75              
76             =item L
77              
78             =back
79              
80             new B
81              
82             $self = SweetPea->new(\%options)
83            
84             takes 1 argument
85             1st argument - optional
86             \%options - sweetpea runtime options
87            
88             example:
89             my $self = sweet;
90            
91             my $self = SweetPea->new({
92             local_session => 1
93             });
94            
95             my $self = SweetPea->new({
96             session_folder => '/tmp/site1'
97             });
98              
99             =cut
100              
101             sub new {
102 18     18 1 52 my $class = shift;
103 18         46 my $options = shift;
104 18         48 my $self = {};
105 18         50 bless $self, $class;
106              
107             #declare config stuff
108 18         220 $self->{store}->{application}->{html_content} = [];
109 18         99 $self->{store}->{application}->{action_discovery} = 1;
110 18         63 $self->{store}->{application}->{content_type} = 'text/html';
111 18         74 $self->{store}->{application}->{path} = $FindBin::Bin;
112 18 50       104 $self->{store}->{application}->{local_session} =
113             $options->{local_session} ? $options->{local_session} : 0; # debugging
114 18 50       79 $self->{store}->{application}->{session_folder} =
115             $options->{session_folder} if $options->{session_folder};
116            
117 18         261 return $self;
118             }
119              
120             =head2 run
121              
122             I
123             executes internal pre and post request processing routines.>
124              
125             run B
126              
127             no arguments
128              
129             run B
130              
131             $self = $self->run
132            
133             takes 0 arguments
134            
135             example:
136             my $self = sweet;
137             $self->run;
138              
139             =cut
140              
141             sub run {
142 18     18 1 48 my $self = shift;
143 18         139 $self->_plugins;
144 18         104 $self->_self_check;
145 18         99 $self->_init_dispatcher;
146 0         0 return $self;
147             }
148              
149             =head2 test
150              
151             I
152             command line. Equivalent to the `run` method.>
153              
154             test B
155              
156             =over 3
157              
158             =item L L
159              
160             =back
161              
162             test B
163              
164             $self = $self->test($route, \%options)
165            
166             takes 2 arguments
167             1st argument - optional
168             $route - sweetpea url route
169             2nd argument - optional
170             \%options - sweetpea runtime options
171            
172             example:
173             my $self = sweet->test;
174              
175             =cut
176              
177             sub test {
178 18     18 1 427 my ($self, $route, $options) = @_;
179            
180             # set up testing environment
181 18 50       83 $route = '/' unless $route;
182 18         278 $self->{store}->{application}->{test}->{route} =
183             $ENV{SCRIPT_NAME} = "/.pl";
184 18         108 $ENV{PATH_INFO} = "$route";
185 18         122 $self->run($options);
186             }
187              
188             =head2 mock
189              
190             I
191             output without breaking the existing request. Useful for fetching pages
192             to display or attach in email messages.>
193              
194             mock B
195              
196             =over 3
197              
198             =item L
199              
200             =back
201              
202             mock B
203              
204             $self = $self->mock($route, \%options)
205            
206             takes 2 arguments
207             1st argument - required
208             $route - url path
209             2nd argument - optional
210             \%options - sweetpea runtime options
211            
212             example:
213             my $self = sweet;
214             my @content = $self->mock('/path');
215              
216             =cut
217              
218             sub mock {
219 0     0 1 0 my ($self, $route, $options) = @_;
220             # mock can only be run as a get request
221 0         0 my $original_request = $ENV{REQUEST_METHOD};
222 0         0 my $original_pathinfo = $ENV{PATH_INFO};
223 0         0 $ENV{REQUEST_METHOD} = 'GET';
224             # set up mock runtime environment
225 0 0       0 $route = '/' unless $route;
226 0         0 $self->{store}->{application}->{mock_run} = 1;
227 0         0 $self->{store}->{application}->{mock_data} = [];
228 0 0       0 $self->{store}->{application}->{test}->{route} =
229             $ENV{SCRIPT_NAME} = "/.pl" unless $ENV{SCRIPT_NAME};
230 0         0 $ENV{PATH_INFO} = "$route";
231 0         0 $self->run;
232 0         0 $ENV{REQUEST_METHOD} = $original_request;
233 0         0 $ENV{PATH_INFO} = $original_pathinfo;
234 0         0 push @{$self->{store}->{application}->{mock_data}}, @{$self->html};
  0         0  
  0         0  
235 0         0 my @return = @{$self->{store}->{application}->{mock_data}};
  0         0  
236 0         0 $self->{store}->{application}->{mock_run} = 0;
237 0         0 $self->{store}->{application}->{mock_data} = [];
238 0         0 $self->{store}->{application}->{test}->{route} = '';
239 0         0 return @return;
240             }
241              
242             =head2 mock_data
243              
244             I
245             various stages of the sub-processing.>
246              
247             mock_data B
248              
249             =over 3
250              
251             =item L
252              
253             =back
254              
255             mock_data B
256              
257             $self->mock_data(@data);
258            
259             takes 1 argument
260             1st argument - required
261             @data - content to be pushed into the mock datastore for
262             later retrieval
263            
264             example:
265             This method is/should be only used by the `mock` method.
266              
267             =cut
268              
269             sub mock_data {
270 0     0 1 0 my ( $self, @data ) = @_;
271 0 0       0 if (@data) {
272 0         0 my @existing_data =
273             $self->{store}->{application}->{mock_data}
274 0 0       0 ? @{ $self->{store}->{application}->{mock_data} }
275             : ();
276 0         0 push @existing_data, @data;
277 0         0 $self->{store}->{application}->{mock_data} = \@existing_data;
278 0         0 return;
279             }
280             else {
281 0 0       0 if ( $self->{store}->{application}->{mock_data} ) {
282 0         0 my @content = @{ $self->{store}->{application}->{mock_data} };
  0         0  
283 0         0 $self->{store}->{application}->{mock_data} = [];
284 0         0 return \@content;
285             }
286             }
287             }
288              
289             =head2 _plugins
290              
291             I
292             pre-defined plugins and load user-defined plugins.>
293              
294             _plugins B
295              
296             no arguments
297              
298             _plugins B
299              
300             $self = $self->_plugins;
301            
302             takes 0 arguments
303            
304             example:
305             This method is used mainly by the `run` method.
306              
307             =cut
308              
309             sub _plugins {
310 18     18   51 my $self = shift;
311              
312             # NOTE! The database and email plugins are not used internally so changing
313             # them to a module of you choice won't effect any core functionality. Those
314             # modules/plugins should be configured in App.pm.
315             # load modules using the following procedure, they will be available to the
316             # application as $s->nameofobject.
317              
318             $self->plug(
319             'cgi',
320             sub {
321 18     18   39 my $self = shift;
322 18         149 return CGI->new;
323             }
324 18         195 );
325              
326             $self->plug(
327             'cookie',
328             sub {
329 0     0   0 require 'CGI/Cookie.pm';
330 0         0 my $self = shift;
331 0         0 push @{ $self->{store}->{application}->{cookie_data} },
  0         0  
332             CGI::Cookie->new(@_);
333 0         0 return $self->{store}->{application}->{cookie_data}
334 0         0 ->[ @{ $self->{store}->{application}->{cookie_data} } ];
335             }
336 18         134 );
337              
338             $self->plug(
339             'session',
340             sub {
341 18     18   1702 eval 'require q(CGI/Session.pm)';
342 18 50       127850 unless ($@) {
343 18         65 my $self = shift;
344 18         52 my $opts = {};
345 18 50       143 if ($self->{store}->{application}->{session_folder}) {
346 0         0 $opts->{Directory} =
347             $self->{store}->{application}->{session_folder};
348             }
349             else {
350 18 50       110 if ($self->{store}->{application}->{local_session}) {
351 0         0 my $path = $self->{store}->{application}->{path};
352 0 0       0 mkdir "./sweet" unless -e "./sweet";
353            
354 0 0       0 mkdir "./sweet/sessions" unless -e "./sweet/sessions";
355            
356 0         0 $opts->{Directory} = './sweet/sessions';
357             }
358             else {
359 18   50     128 my $session_folder = $ENV{HOME} || "";
360 18 50       121 $session_folder = (split /\;/, $session_folder)[0]
361             if $session_folder =~ m/\;/;
362 18         139 $session_folder =~ s/[\\\/]$//;
363            
364 18 50       696 if ( -d -w "$session_folder/tmp" ) {
365 18         88 $opts->{Directory} = "$session_folder/tmp";
366             }
367             else {
368 0 0       0 if ( -d -w $session_folder ) {
369 0 0       0 mkdir "$session_folder/tmp", 0777
370             unless -d "$session_folder/tmp";
371             }
372 0 0       0 if ( -d -w "$session_folder/tmp" ) {
373 0         0 $opts->{Directory} = "$session_folder/tmp";
374             }
375             else {
376 0         0 $opts->{Directory} = $session_folder;
377             }
378             }
379             }
380             }
381 18         110 $self->{store}->{application}->{session_folder} =
382             $opts->{Directory};
383 18         149 CGI::Session->name("SID");
384 18         226 my $sess = CGI::Session->new("driver:file", undef, $opts);
385 18         1632082 $sess->flush;
386 18         14600 return $sess;
387             }
388             }
389 18         161 );
390            
391             # try to pinup a session
392 18         119 $self->session;
393              
394             # load non-core plugins from App.pm
395 18 50       243 if (-e "sweet/App.pm") {
396 0         0 eval 'require q(App.pm)';
397 0 0       0 if ($@) {
398 0         0 warn $@;
399             }
400             else {
401 0         0 eval { App->plugins($self) };
  0         0  
402             }
403             }
404 18         53 return $self;
405             }
406              
407             =head2 _load_path_and_actions
408              
409             I
410             and Actions, create the actions table, by treversing the Controllers
411             folder.>
412              
413             _load_path_and_actions B
414              
415             no arguments
416              
417             _load_path_and_actions B
418              
419             \%actions = $self->_load_path_and_actions;
420            
421             takes 0 arguments
422            
423             example:
424             This method is use by the `run` method. And is not called manually.
425              
426             =cut
427              
428             sub _load_path_and_actions {
429 18     18   40 my $self = shift;
430              
431 18 50       63 if ( $self->application->{action_discovery} ) {
432 18 50       64 if (-e $self->application->{path} . '/sweet/application/Controller') {
433 0         0 my $actions = {};
434 0         0 find( \&_load_path_actions,
435             $self->application->{path} . '/sweet/application/Controller' );
436            
437             sub _load_path_actions {
438 19     19   163 no warnings 'redefine';
  19         44  
  19         2216  
439 19     19   120 no strict 'refs';
  19         333  
  19         152694  
440 0     0   0 my $name = $File::Find::name;
441 0         0 my $magic = '';
442 0         0 my @dir = ();
443 0 0       0 if ( $name =~ /.pm$/ ) {
444 0         0 require $name;
445 0         0 my $controller = $name;
446 0         0 $controller =~ s/\\/\//g; # convert non-unix paths
447 0         0 $controller =~ s/.*Controller\/(.*)\.pm$/$1/;
448 0         0 my $controller_ref = $controller;
449 0         0 $controller_ref =~ s/\//\:\:/g;
450 0         0 @dir = split /\//, $controller;
451 0 0       0 open( INPUT, "<", $name )
452             or die "Couldn't open $name for reading: $!\n";
453 0         0 my @code = ;
454 0         0 my @routines = grep { /^sub\s?(.*)[\s\n]{0,}?\{/ } @code;
  0         0  
455 0         0 $_ =~ s/sub//g foreach @routines;
456 0         0 $_ =~ s/[^a-zA-Z0-9\_\-]//g foreach @routines;
457            
458             # dynamically create new (initialization routine)
459 0 0       0 my $new = "Controller::" . $controller_ref . "::_new"
460             if $controller_ref;
461 0         0 *{$new} = sub {
462 0     0   0 my $class = shift;
463 0         0 my $self = {};
464 0         0 bless $self, $class;
465 0         0 return $self;
466             }
467 0 0       0 if $new;
468            
469 0         0 foreach (@routines) {
470            
471             # dynamically create method references
472 0         0 my $code =
473             '$actions->{lc("/$controller/$_")} = '
474             . 'sub{ my ($s, $class) = @_; if ($class) { return $class->'
475             . $_
476             . '($s) } else { $class = Controller::'
477             . $controller_ref
478             . '->_new; return $class->'
479             . $_
480             . '($s); } }';
481 0         0 eval $code;
482             }
483 0         0 close(INPUT);
484             }
485             }
486 0 0       0 map {
487 0         0 $self->application->{actions}->{$_} = $actions->{$_} if
488             not defined $self->application->{actions}->{$_};
489 0         0 } keys %{$actions};
490             }
491             }
492 18         68 return $self->application->{actions};
493             }
494              
495             sub _self_check {
496 18     18   47 my $self = shift;
497              
498             # used to do something useful, not anymore
499 18         103 my $path = $self->application->{path};
500 18         52 return $self;
501             }
502              
503             =head2 _init_dispatcher
504              
505             I
506             current request routines.>
507              
508             _init_dispatcher B
509              
510             no arguments
511              
512             _init_dispatcher B
513              
514             $self->_init_dispatcher;
515            
516             takes 0 arguments
517            
518             example:
519             This method is use by the `run` method and is not called manually.
520              
521             =cut
522              
523             sub _init_dispatcher {
524 18     18   42 my $self = shift;
525 18   50     93 my $actions = $self->_load_path_and_actions() || {};
526 18         44 my $path;
527            
528             # url parser - this is informative
529 18         98 $self->_url_parser($actions);
530            
531 18         287 my $controller = $self->{store}->{application}->{url}->{controller};
532 18         62 my $action = $self->{store}->{application}->{url}->{action};
533 18         65 my $request = $self->{store}->{application}->{url}->{here};
534 18         44 my $handler = '';
535            
536             # check/balance
537 18 50       75 $controller = '/' unless $controller;
538            
539 18 100       101 $handler = $action ? "$controller/$action" : $controller;
540 18 50       83 $handler = $actions->{$handler} if $handler;
541 18         47 my $package = $controller;
542            
543             # hack
544 18 100       100 if ($action) {
    50          
545 1         15 $package =~ s/\/$action$//;
546             }
547             elsif ($package) {
548 17 100       68 if ($package eq '/') {
549 3         8 $package = '';
550             }
551             }
552              
553             # alter environment for testing
554 18 50       108 if ($self->{store}->{application}->{test}->{route}) {
555 18         43 $controller = $request;
556 18         42 $package = '';
557             }
558              
559             # restrict access to hidden methods (methods prefixed with an underscore)
560 18 50       89 if ( $request =~ /.*\/_\w+$/ ) {
561 0 0       0 if ($self->{store}->{application}->{mock_run}) {
562 0         0 $self->mock_data("Access denied to private action $request.");
563 0         0 return $self->finish;
564             }
565             print
566 0         0 $self->cgi->header,
567             $self->cgi->start_html('Access Denied To Private Action'),
568             $self->cgi->h1('Access Denied'),
569             $self->cgi->end_html;
570 0         0 exit;
571             }
572              
573             # try global index
574 18 50       92 if ( ref($handler) ne "CODE" ) {
575             # last resort, revert to root controller index action
576 0 0 0     0 if (exists $actions->{"/root/_index"}
      0        
577             && (!$actions->{"$controller"}
578             && !$actions->{"$package/_index"})) {
579 0         0 $handler = $actions->{"/root/_index"};
580             }
581             }
582            
583 18 50       80 if ( ref($handler) eq "CODE" ) {
584              
585             #run master _startup routine
586 18 50       78 $actions->{"/root/_startup"}->($self)
587             if exists $actions->{"/root/_startup"};
588              
589             #run user-defined begin routine or default to root begin
590 18 50       91 $actions->{"$package/_begin"}->($self)
591             if exists $actions->{"$package/_begin"};
592            
593 18 50 33     102 $actions->{"/root/_begin"}->($self)
594             if exists $actions->{"/root/_begin"}
595             && !$actions->{"$package/_begin"};
596              
597             #run user-defined response routines
598 18         109 $handler->($self);
599              
600             #run user-defined end routine or default to root end
601 0 0       0 $actions->{"$package/_end"}->($self)
602             if exists $actions->{"$package/_end"};
603            
604 0 0 0     0 $actions->{"/root/_end"}->($self)
605             if exists $actions->{"/root/_end"}
606             && !$actions->{"$package/_end"};
607              
608             #run master _shutdown routine
609 0 0       0 $actions->{"/root/_shutdown"}->($self)
610             if exists $actions->{"/root/_shutdown"};
611              
612             #run pre-defined response routines
613 0         0 $self->start();
614              
615             #run finalization and cleanup routines
616 0         0 $self->finish();
617             }
618             else {
619 0 0       0 if ($self->{store}->{application}->{mock_run}) {
620 0         0 $self->mock_data("Resource not found.");
621 0         0 return $self->finish;
622             }
623             # print http header
624 0         0 print $self->cgi->header, $self->cgi->start_html('Resource Not Found'),
625             $self->cgi->h1('Not Found'), $self->cgi->end_html;
626 0         0 exit;
627             }
628             }
629              
630             =head2 _url_parser
631              
632             I
633             the current request as well as parse vaiable data in the url path.>
634              
635             _url_parser B
636              
637             no arguments
638              
639             _url_parser B
640              
641             $boolean = $self->_url_parser;
642            
643             takes 0 argument
644            
645             example:
646             This method is use by the `run` method and is not called manually.
647              
648             =cut
649              
650             sub _url_parser {
651 18     18   47 my ($self, $actions) = @_;
652             # this allows us to deduce the web root, true current path, etc
653            
654 18   50     173 my $script = $self->{store}->{application}->{dispatcher} || '\.pl';
655 18         364 my $root = $self->cgi->script_name();
656 18         23187 $root =~ s/$script//;
657 18         109 $root =~ s/(^\/+|\/+$)//g;
658 18         61 $root = "/$root";
659 18         93 my $here = $self->cgi->path_info();
660 18         7443 $here =~ s/(^\/+|\/+$)//g;
661 18         69 $here = "/$here";
662 18         57 my $path = $here;
663 18 50       113 $here = $here ? "$root$here" : $root;
664 18 50       169 $here =~ s/^\/// if $here =~ /^\/{2,}/;
665            
666             # A: action finding
667 18         118 $self->{store}->{application}->{'url'}->{root} = $root;
668 18         81 $self->{store}->{application}->{'url'}->{here} = $path;
669 18         75 $self->{store}->{application}->{'url'}->{path} = $here;
670            
671 18         41 my ($controller, $action);
672            
673             # 1. check if the path specified has a corresponding action
674 18 100       107 if (ref($actions->{$path}) eq "CODE") {
675 3 50       16 if ($here =~ m/\//) {
676 3         18 my @act = split /\//, $path;
677 3         8 $action = pop @act;
678 3         10 $controller = join("/", @act);
679 3 50       30 $controller = "/$controller" if $controller !~ m/^\//;
680 3         13 $self->{store}->{application}->{'url'}->{controller} = $controller;
681 3         11 $self->{store}->{application}->{'url'}->{action} = $action;
682 3         21 return 1;
683             }
684             }
685            
686             # 2. check if the path specified matches against inline url params
687 15         37 foreach my $a (reverse sort keys %{$actions}) {
  15         136  
688 16         35 my $pattern = $a;
689 16 100       104 if ($pattern =~ /\:([\w]+)/) {
690 11         93 my @keys = ($pattern =~ /\:([\w]+)/g);
691 11         69 $pattern =~ s/\:[\w]+/\(\.\*\)/gi;
692 11         197 my @values = $path =~ /$pattern/;
693 11 50       134 if (scalar(@keys) == scalar(@values)) {
694 11         56 for (my $i = 0; $i < @keys; $i++) {
695 16         503 $self->cgi->param(-name => $keys[$i],
696             -value => $values[$i]);
697             }
698 11         1471 $controller = "$a";
699 11         32 $action = "";
700 11         44 $self->{store}->{application}->{'url'}->{controller} = $controller;
701 11         38 $self->{store}->{application}->{'url'}->{action} = $action;
702 11         60 return 1;
703             }
704             }
705             }
706            
707             # 3. check if the path specified matched against a paths with wildcards
708 4         11 foreach my $a (reverse sort keys %{$actions}) {
  4         18  
709 4         10 my $pattern = $a;
710 4 100       35 if ($pattern =~ /\*/) {
711 3         13 $pattern =~ s/\*/\(\.\*\)/;
712 3 50       54 if ($path =~ m/$pattern/) {
713 3 50 33     25 if ($0 && $1) {
714 3         13 $self->cgi->param(-name => '*', -value => $1);
715 3         513 $controller = "$a";
716 3         8 $action = "";
717 3         15 $self->{store}->{application}->{'url'}->{controller} = $controller;
718 3         11 $self->{store}->{application}->{'url'}->{action} = $action;
719 3         12 return 1;
720             }
721             }
722             }
723             }
724            
725             # 4. perform recursion tests as a last ditch effort
726 1 50       8 if ($path =~ m/\//) {
727 1         9 my @acts = split /\//, $path;
728 1         4 my @trail = ();
729 1         2 my $possibilities = @acts;
730 1         6 for (my $i = 0; $i < $possibilities; $i++) {
731 10         14 my $a = $acts[$i];
732 10 50       23 if (@acts > 1) {
733 10 100       31 if (ref($actions->{join("/", @acts)}) eq "CODE") {
734 1         2 $action = pop @acts;
735 1         4 $controller = join("/", @acts);
736 1         4 $self->{store}->{application}->{'url'}->{controller} = $controller;
737 1         4 $self->{store}->{application}->{'url'}->{action} = $action;
738 1         5 $self->cgi->param(-name => '*', -value => join("/", reverse @trail));
739 1         124 return 1;
740             }
741             else {
742             # wow, still nothing, look for local index
743 9 50       38 if (ref($actions->{join("/", @acts)."/_index"}) eq "CODE") {
744 0         0 $action = "_index";
745 0         0 $controller = join("/", @acts);
746 0         0 $self->{store}->{application}->{'url'}->{controller} = join("/", @acts);
747 0         0 $self->{store}->{application}->{'url'}->{action} = $action;
748 0         0 $self->cgi->param(-name => '*', -value => join("/", reverse @trail));
749 0         0 return 1;
750             }
751             }
752 9         34 push @trail, pop @acts;
753             }
754             else {
755 0 0       0 if (ref($actions->{"/$acts[0]"}) eq "CODE") {
756 0         0 $controller = "/$acts[0]";
757 0         0 $actions = "";
758 0         0 $self->{store}->{application}->{'url'}->{controller} = $controller;
759 0         0 $self->{store}->{application}->{'url'}->{action} = $action;
760 0         0 $self->cgi->param(-name => '*', -value => join("/", reverse @trail));
761 0         0 return 1;
762             }
763             else {
764             # this better work, look for local index
765 0 0       0 if (ref($actions->{"/$acts[0]/_index"}) eq "CODE") {
766 0         0 $action = "_index";
767 0         0 $controller = "/$acts[0]";
768 0         0 $self->{store}->{application}->{'url'}->{controller} = $controller;
769 0         0 $self->{store}->{application}->{'url'}->{action} = $action;
770 0         0 $self->cgi->param(-name => '*', -value => join("/", reverse @trail));
771 0         0 return 1;
772             }
773             }
774             }
775             }
776             }
777            
778 0         0 return 0;
779             }
780              
781             =head2 start
782              
783             I
784             as well as perform other pre-print activities.>
785              
786             start B
787              
788             no arguments
789              
790             start B
791              
792             $self->start;
793            
794             takes 0 arguments
795            
796             example:
797             This method is use by the `_init_dispatcher` method and is not called
798             manually.
799              
800             =cut
801              
802             sub start {
803 0     0 1 0 my $self = shift;
804              
805             # handle session
806 0 0       0 if ( defined $self->session ) {
807 0 0       0 $self->session->expire(
808             defined $self->application->{session}->{expiration}
809             ? $self->application->{session}->{expiration}
810             : '1h' );
811 0         0 $self->cookie(
812             -name => $self->session->name,
813             -value => $self->session->id
814             );
815             }
816            
817 0 0       0 unless ($self->{store}->{application}->{mock_run}) {
818 0         0 print $self->cgi->header(
819             -type => $self->application->{content_type},
820             -status => 200,
821             -cookie => $self->cookies
822             );
823             }
824             }
825              
826             =head2 finish
827              
828             I
829             last-minute activities.>
830              
831             finish B
832              
833             no arguments
834              
835             finish B
836              
837             $self->finish;
838            
839             takes 0 arguments
840            
841             example:
842             This method is use by the `_init_dispatcher` method and is not called
843             manually.
844              
845             =cut
846              
847             sub finish {
848 0     0 1 0 my $self = shift;
849              
850             # return captured data for mock transactions
851 0 0       0 if ($self->{store}->{application}->{mock_run}) {
852 0         0 $self->session->flush();
853 0         0 return 1;
854             }
855              
856             # print gathered html
857 0         0 foreach ( @{ $self->html } ) {
  0         0  
858 0         0 print "$_\n";
859             }
860              
861             # commit session changes if a session has been created
862 0         0 $self->session->flush();
863             }
864              
865             =head2 forward
866              
867             I
868             process related information then returns to the original action to finish
869             processing.>
870              
871             forward B
872              
873             =over 3
874              
875             =item L
876              
877             =item L
878              
879             =back
880              
881             forward B
882              
883             $self->forward($route, $self);
884            
885             takes 2 arguments
886             1st argument - required
887             $route - display help for a specific command
888             2nd argument - optional
889             $self - The current class, used as a reference
890            
891             example:
892             my $self = sweet;
893             $self->routes({
894             '/' => sub {
895             shift->forward('/more');
896             print ', buddy';
897             }
898             '/more' => sub {
899             print '... here i am :)';
900             }
901             });
902            
903             # prints here i am, buddy
904              
905             =cut
906              
907             sub forward {
908 0     0 1 0 my ( $self, $path, $class ) = @_;
909              
910             #run requested routine
911 0 0       0 $self->application->{actions}->{"$path"}->( $self, $class ) if
912             exists $self->application->{actions}->{"$path"};
913             }
914              
915             =head2 detach
916              
917             I
918             process related information but does NOT return to the original action to
919             finish processing. Actually it invokes the finalization routines and
920             the exits.>
921              
922             detach B
923              
924             =over 3
925              
926             =item L
927              
928             =item L
929              
930             =back
931              
932             detach B
933              
934             $self->detach($route, $self);
935            
936             takes 2 arguments
937             1st argument - required
938             $route - display help for a specific command
939             2nd argument - optional
940             $self - The current class, used as a reference
941            
942             example:
943             my $self = sweet;
944             $self->routes({
945             '/' => sub {
946             shift->detach('/more');
947             print ', buddy';
948             }
949             '/more' => sub {
950             print '... here i am :)';
951             }
952             });
953            
954             # prints here i am
955              
956             =cut
957              
958             sub detach {
959 0     0 1 0 my ( $self, $path, $class ) = @_;
960 0         0 $self->forward( $path, $class );
961 0         0 $self->start();
962 0         0 $self->finish();
963 0         0 exit;
964             }
965              
966             =head2 redirect
967              
968             I
969             resource.>
970              
971             redirect B
972              
973             =over 3
974              
975             =item L
976              
977             =back
978              
979             redirect B
980              
981             $self->redirect($url);
982            
983             takes 1 argument
984             1st argument - required
985             $url - absolute or relative url
986            
987             example:
988             my $self = sweet;
989             $self->redirect('http://www.sweetpea.com');
990             $self->redirect('/static/index.html');
991              
992             =cut
993              
994             sub redirect {
995 0     0 1 0 my ( $self, $url ) = @_;
996 0 0       0 if ($self->{store}->{application}->{mock_run}) {
997 0         0 $self->mock_data("Attempted to redirect to url $url.");
998 0         0 return $self->finish;
999             }
1000 0 0       0 $url = $self->url($url) unless $url =~ /^http/;
1001 0         0 print $self->cgi->redirect($url);
1002 0         0 exit;
1003             }
1004              
1005             =head2 store
1006              
1007             I
1008             object.>
1009              
1010             store B
1011              
1012             no arguments
1013              
1014             store B
1015              
1016             my $stash = $self->store;
1017            
1018             takes 0 arguments
1019            
1020             example:
1021             my $self = sweet;
1022             my $stash = $self->store;
1023             $self->store->{foo} = 'bar';
1024             print $self->store->{foo};
1025            
1026             # prints 'bar'
1027              
1028             =cut
1029              
1030             sub store {
1031 0     0 1 0 my $self = shift;
1032 0         0 return $self->{store};
1033             }
1034              
1035             =head2 application
1036              
1037             I
1038             sweetpea stash reserved for application configuration variables.>
1039              
1040             application B
1041              
1042             no arguments
1043              
1044             application B
1045              
1046             $self->application;
1047            
1048             takes 0 arguments
1049            
1050             example:
1051             my $self = sweet;
1052             my $stash = $self->application;
1053             $self->application->{foo} = 'bar';
1054             print $self->application->{foo};
1055            
1056             # prints 'bar'
1057              
1058             =cut
1059              
1060             sub application {
1061 92     92 1 157 my $self = shift;
1062 92         1024 return $self->{store}->{application};
1063             }
1064              
1065             =head2 content_type
1066              
1067             I
1068             should expect to be returned.>
1069              
1070             content_type B
1071              
1072             =over 3
1073              
1074             =item L
1075              
1076             =back
1077              
1078             content_type B
1079              
1080             $self->content_type($content_type);
1081            
1082             takes 1 argument
1083             1st argument - required
1084             $content_type - type of content to be returned
1085            
1086             example:
1087             my $self = sweet;
1088             $self->content_type('text/html');
1089             $self->content_type('text/plain');
1090              
1091             =cut
1092              
1093             sub content_type {
1094 0     0 1 0 my ( $self, $type ) = @_;
1095 0         0 $self->application->{content_type} = $type;
1096             }
1097              
1098             =head2 request_method
1099              
1100             I
1101             browser to request the specified resource.>
1102              
1103             request_method B
1104              
1105             =over 3
1106              
1107             =item L
1108              
1109             =back
1110              
1111             request_method B
1112              
1113             $self->request_method;
1114            
1115             takes 1 argument
1116             1st argument - optional
1117             $method - method to match against the current request
1118            
1119             example:
1120             my $self = sweet;
1121             my $foo = $self->request_method;
1122             # $foo equals Get, Post, etc
1123            
1124             my $foo = $self->request_method('get');
1125             # foo is 1 if current request method is 'get' or 0 if not
1126              
1127             =cut
1128              
1129             sub request_method {
1130 0     0 1 0 my ($self, $method) = @_;
1131 0 0       0 if ($method) {
1132 0 0       0 return lc($ENV{REQUEST_METHOD}) eq lc($method) ? 1 : 0;
1133             }
1134             else {
1135 0         0 return $ENV{REQUEST_METHOD};
1136             }
1137             }
1138              
1139             =head2 request
1140              
1141             I
1142              
1143             =cut
1144              
1145             sub request {
1146 0     0 1 0 shift->request_method(@_);
1147             }
1148              
1149             =head2 push_download
1150              
1151             I
1152             user to download the specified content rather than to display it.>
1153              
1154             push_download B
1155              
1156             =over 3
1157              
1158             =item L
1159              
1160             =back
1161              
1162             push_download B
1163              
1164             $self->push_download($file_or_data);
1165            
1166             takes 1 argument
1167             1st argument - required
1168             $file_or_data - file or data to be sent as a download
1169            
1170             example:
1171             my $self = sweet;
1172             $self->push_download('/tmp/text_file.txt');
1173             $self->push_download('this is a test');
1174              
1175             =cut
1176              
1177             sub push_download {
1178 0     0 1 0 my ($self, $file) = @_;
1179 0 0       0 if ($self->{store}->{application}->{mock_run}) {
1180 0         0 $self->mock_data("Attempted to force download file $file.");
1181 0         0 return $self->finish;
1182             }
1183            
1184 0         0 my $data;
1185             my $ext;
1186            
1187 0 0 0     0 if (-e $file && $file) {
1188 0 0       0 my $name = $file =~ /\/?([\w\.]+)$/ ? $1 : $file;
1189 0 0       0 $ext = $name =~ s/(\.\w+)$/$1/ ? $1 : '';
1190 0         0 $data = $self->file('<', $file);
1191             }
1192             else {
1193 0         0 $data = $file;
1194 0         0 $ext = '.txt';
1195             }
1196 0 0       0 if ($data) {
1197 0         0 my $ctype = "application/force-download";
1198 0 0       0 $ctype = "application/pdf"
1199             if $ext eq ".pdf";
1200 0 0       0 $ctype = "application/octet-stream"
1201             if $ext eq ".exe";
1202 0 0       0 $ctype = "application/zip"
1203             if $ext eq ".zip";
1204 0 0       0 $ctype = "application/msword"
1205             if $ext eq ".doc";
1206 0 0       0 $ctype = "application/vnd.ms-excel"
1207             if $ext eq ".xls";
1208 0 0       0 $ctype = "application/vnd.ms-powerpoint"
1209             if $ext eq ".ppt";
1210 0 0 0     0 $ctype = "image/jpg"
1211             if $ext eq ".jpg" || $ext eq ".jpeg";
1212 0 0       0 $ctype = "image/gif"
1213             if $ext eq ".gif";
1214 0 0       0 $ctype = "image/png"
1215             if $ext eq ".png";
1216 0 0       0 $ctype = "text/plain"
1217             if $ext eq ".txt";
1218 0 0 0     0 $ctype = "text/html"
1219             if $ext eq ".html" || $ext eq ".htm";
1220              
1221 0         0 print("Content-Type: $ctype\n");
1222 0         0 print("Content-Transfer-Encoding: binary\n");
1223 0         0 print("Content-Length: " . length($data) . "\n" );
1224 0         0 print("Content-Disposition: attachment; filename=\"$name\";\n\n");
1225 0         0 print("$data");
1226 0         0 exit;
1227             }
1228             }
1229              
1230             =head2 controller
1231              
1232             I
1233              
1234             controller B
1235              
1236             =over 3
1237              
1238             =item L
1239              
1240             =back
1241              
1242             controller B
1243              
1244             $self->controller;
1245            
1246             takes 1 argument
1247             1st argument - optional
1248             $route - route to append to the current route
1249            
1250             example:
1251             my $self = sweet;
1252             my $foo = $self->controller;
1253             # foo equals '/by' if current url path is '/by'
1254            
1255             my $foo = $self->controller('/theway');
1256             # foo equals '/by/theway' if current url path is '/by/theway'
1257              
1258             =cut
1259              
1260             sub controller {
1261 0     0 1 0 my ( $self, $path ) = @_;
1262 0         0 my $controller = $self->uri->{controller};
1263 0 0 0     0 return "$controller$path" if $controller || $path;
1264             }
1265              
1266             =head2 action
1267              
1268             I
1269             requested.>
1270              
1271             action B
1272              
1273             no arguments
1274              
1275             action B
1276              
1277             my $action = $self->action;
1278            
1279             takes 0 arguments
1280            
1281             example:
1282             my $action = $self->action;
1283             # $action equals 'test' if url is http://localhost/do/test
1284             # $action equals '_index' if url is http://localhost/do/test and
1285             # controller is Do::Test
1286              
1287             =cut
1288              
1289             sub action {
1290 0     0 1 0 my $self = shift;
1291 0         0 return $self->uri->{action};
1292             }
1293              
1294             =head2 uri
1295              
1296             I
1297             or return the existing/new URL.>
1298              
1299             uri B
1300              
1301             =over 3
1302              
1303             =item L
1304              
1305             =back
1306              
1307             uri B
1308              
1309             $self->uri($route);
1310            
1311             takes 1 argument
1312             1st argument - optional
1313             $route - route for use in the creation of the url
1314            
1315             example:
1316             my $self = sweet;
1317             my $url = $self->uri;
1318             # if the current url is http://localhost/newapp/by/theway and newapp
1319             # is a subfolder under the docroot where our app is stored
1320             # $url->{here} equals http://localhost/newapp/by/theway
1321             # $url->{root} equals http://localhost/newapp
1322            
1323             my $url = $self->uri('/my_friend');
1324             # $url equals http://localhost/newapp/by/theway/my_friend
1325              
1326             =cut
1327              
1328             sub uri {
1329 0     0 1 0 my ( $self, $path ) = @_;
1330 0 0       0 return $self->{store}->{application}->{'url'} unless $path;
1331 0         0 $path =~ s/^\///; # remove leading slash for use with root
1332             return
1333 0 0       0 $self->cgi->url( -base => 1 )
1334             . ( $self->{store}->{application}->{'url'}->{'root'} =~ /\/$/
1335             ? "$self->{store}->{application}->{'url'}->{'root'}$path"
1336             : "$self->{store}->{application}->{'url'}->{'root'}/$path" );
1337             }
1338              
1339             =head2 url
1340              
1341             I
1342              
1343             =cut
1344              
1345 0     0 1 0 sub url { return shift->uri(@_); }
1346              
1347             =head2 path
1348              
1349             I
1350             application or return a new path based on the specified path.>
1351              
1352             path B
1353              
1354             =over 3
1355              
1356             =item L
1357              
1358             =back
1359              
1360             path B
1361              
1362             $self->path($path);
1363            
1364             takes 1 argument
1365             1st argument - optional
1366             $path - path to append to the root path to be returned
1367            
1368             example:
1369             my $self = sweet;
1370             my $doc_root = $self->path;
1371             # $doc_root equals /var/www/site01 if /var/www/site01 is where the
1372             # application root is
1373            
1374             my $path = $self->path('/sweet/sessions');
1375             # $path equals /var/www/site01/sweet/sessions if /var/www/site01
1376             # is where the application root is
1377              
1378             =cut
1379              
1380             sub path {
1381 3     3 1 10 my ( $self, $path ) = @_;
1382 3         7 $path =~ s/^\///;
1383 3 50       22 return $path
1384             ? $self->{store}->{application}->{'path'} . "/$path"
1385             : $self->{store}->{application}->{'path'};
1386             }
1387              
1388             =head2 cookies
1389              
1390             I
1391             existing browser cookies.>
1392              
1393             cookies B
1394              
1395             no arguments
1396              
1397             cookies B
1398              
1399             my @cookies = $self->cookies;
1400            
1401             takes 0 arguments
1402            
1403             example:
1404             my @cookies = $self->cookies;
1405             # where each @cookies element is a CGI::Cookie object
1406              
1407             =cut
1408              
1409             sub cookies {
1410 0     0 1 0 my $self = shift;
1411             return
1412 0         0 ref $self->{store}->{application}->{cookie_data} eq "ARRAY"
1413 0 0       0 ? @{ $self->{store}->{application}->{cookie_data} }
1414             : ();
1415             }
1416              
1417             =head2 flash
1418              
1419             I
1420             store for use across requests.>
1421              
1422             flash B
1423              
1424             =over 3
1425              
1426             =item L L
1427              
1428             =back
1429              
1430             flash B
1431              
1432             $self->flash($message, $type);
1433             $self->flash($type);
1434            
1435             takes 2 arguments
1436             1st argument - required
1437             $message - display help for a specific command
1438             2nd argument - optional
1439             $type - type of message to flash [error|info|warn|success]
1440            
1441             example:
1442             my $self = sweet;
1443             $self->flash('info', 'something weird happened');
1444             $self->flash('warn', 'something weird happened');
1445             $self->flash('error', 'something really bad happened');
1446             $self->flash('success', 'something went terribly right');
1447             # the above commands all set (flash) session messages in thier
1448             # respective stores, stores being info, warn, error or success
1449            
1450             $self->flash('success', 'something went terribly right');
1451             # now the flash `success` store is an array and the new entry has
1452             # been appended
1453            
1454             my $success_message = $self->flash('success');
1455             my $warn_message = $self->flash('warn');
1456             ...
1457             # now $success_message, and $warn_message, etc are equal to the last
1458             # messages stored in thier respective stores and the stores themselves
1459             # are cleared
1460              
1461             =cut
1462              
1463             sub flash {
1464 0     0 1 0 my ( $self, $type, $message ) = @_;
1465 0         0 my $store;
1466            
1467 0 0       0 $store = '_INFO' if lc($type) eq 'info';
1468 0 0       0 $store = '_WARN' if lc($type) eq 'warn';
1469 0 0       0 $store = '_ERROR' if lc($type) eq 'error';
1470 0 0       0 $store = '_SUCCESS' if lc($type) eq 'success';
1471            
1472             # sets a default, backwards compatibility
1473 0 0 0     0 if ((lc($type) ne 'info' && lc($type) ne 'warn'
      0        
      0        
      0        
      0        
      0        
1474             && lc($type) ne 'error' && lc($type) ne 'success')
1475             && ($type && !$store && !$message)) {
1476 0         0 $message = $type;
1477 0         0 $store = '_INFO';
1478             }
1479            
1480             # prepare for return value
1481 0 0 0     0 if (((lc($type) eq 'info' || lc($type) eq 'warn'
      0        
      0        
      0        
1482             || lc($type) eq 'error' || lc($type) eq 'success'))
1483             && ($type && $store && !$message)) {
1484 0         0 $message = '';
1485             }
1486            
1487 0 0       0 if ( defined $message ) {
1488 0         0 my $last_message = $self->session->param( $store );
1489            
1490             # append magic if message is not empty
1491 0 0 0     0 if ($message ne '' && $last_message) {
1492 0         0 my $arrayref = [];
1493 0 0       0 if ($last_message) {
1494 0 0       0 if (ref ($last_message) eq "ARRAY") {
1495 0         0 push @{$arrayref}, $_ foreach @{$last_message};
  0         0  
  0         0  
1496             }
1497             else {
1498 0         0 push @{$arrayref}, $last_message;
  0         0  
1499             }
1500             }
1501 0         0 push @{$arrayref}, $message;
  0         0  
1502 0         0 $message = $arrayref;
1503             }
1504            
1505 0         0 $self->session->param( $store => $message );
1506 0         0 $self->session->flush;
1507 0 0       0 return $message eq '' ? $last_message : $message;
1508             }
1509             else {
1510 0         0 return $self->session->param($store);
1511             }
1512             }
1513              
1514             =head2 file
1515              
1516             I
1517             root with ease.>
1518              
1519             file B
1520              
1521             =over 3
1522              
1523             =item L L L
1524              
1525             =back
1526              
1527             file B
1528              
1529             my $content = $self->file($filemode, $filename, @data);
1530            
1531             takes 3 arguments
1532             1st argument - required
1533             $filemode - method used to open a file, e.g. [>>, >, <]
1534             2nd argument - required
1535             $filename - name and path of the file to read or write to
1536             3rd argument - optional
1537             @data - content to be written to the specified file
1538            
1539             example:
1540             my $self = sweet;
1541             my $data = $self->file('>', 'new_folder/new_text.txt', 'a test');
1542             # creates a file new_text.txt in folder new_folder with one line
1543            
1544             my $data = $self->file('<', 'new_folder/new_text.txt');
1545             # read in file content from new_folder/new_text.txt
1546            
1547             =cut
1548              
1549             sub file {
1550 4     4 1 9 my ($self, $op, $file, @content) = @_;
1551 4         4 my $output;
1552 4 50       8 if ($file) {
1553 4 100       6 if (grep {/^(\<|\>|\>\>)$/} $op) {
  4 50       26  
1554 3 100       7 if ($op =~ /\>/) {
1555 1 50       5 my $bmsk = $content[0] if $content[0] =~ /^\d{3,4}$/;
1556 1 50       3 if ($bmsk) {
1557 0 0       0 $bmsk = ($bmsk !~ /^\d{4}$/ ? oct($bmsk) : $bmsk);
1558             }
1559             else {
1560 1         2 $bmsk = '0777';
1561             }
1562             # mkdirs if neccessary
1563 1         2 my @dirs = ();
1564 1         5 my @path = split /\//, $file;
1565 1         2 $file = pop @path;
1566 5         8 map {
1567 1         3 push @dirs, $_;
1568 5 100       88 mkdir( join('/', @dirs), $bmsk) unless -d
1569             join('/', @dirs);
1570             } @path;
1571 1         2 $output = join "\n", @content;
1572 1 50       107 open (my $in, $op,
    50          
1573             (@path ? join('/', @path)."/".$file : $file))
1574             || die "Error: $file, $!";
1575 1         6 print $in $output;
1576 1         43 close $in;
1577 1         18 chmod $bmsk, $file;
1578             }
1579             else {
1580 2 50       48 if (-e $file) {
1581 2 50       87 open( my $out, $op, $file ) || die "Error: $file, $!";
1582 2         31 while (<$out>) {
1583 2         38 $output .= $_;
1584             }
1585 2         26 close $out;
1586             }
1587             }
1588             }
1589             elsif ($op eq 'x') {
1590 1 50       33 if (-e $file) {
1591 1         9 $output = $self->file('<', $file);
1592 1         121 unlink $file;
1593             }
1594             }
1595             }
1596 4         20 return $output;
1597             }
1598              
1599             =head2 upload
1600              
1601             I
1602             the application server space.>
1603              
1604             upload B
1605              
1606             =over 3
1607              
1608             =item L L
1609             L
1610              
1611             =back
1612              
1613             upload B
1614              
1615             my $filename = $self->upload($upload_field, $path, $filename);
1616            
1617             takes 3 arguments
1618             1st argument - required
1619             $upload_field - name of the field input element
1620             2nd argument - required
1621             $path - path to folder where file will be saved
1622             3rd argument - optional
1623             $filename - name of file to be created
1624            
1625             example:
1626             my $self = sweet;
1627             $self->upload('form_field', '/tmp/uploads');
1628             # uploads a file from the client to the server using localtime to
1629             # create the filename
1630              
1631             =cut
1632              
1633             sub upload {
1634 0     0 1 0 my ($self, $upload_field, $location, $filename) = @_;
1635 0         0 my $fh = $self->cgi->upload($upload_field);
1636 0 0       0 unless ($filename) {
1637 0 0       0 $filename =
1638             $self->param($upload_field) =~ /([\w\.]+)$/ ?
1639             $1 : time();
1640             }
1641 0         0 $location =~ s/\/$//;
1642 0 0       0 $location = '.' unless $location;
1643 0 0       0 if ( not -e "$location/$filename" ) {
1644 0         0 open (OUTFILE, ">$location/$filename");
1645 0         0 while (<$fh>) {
1646 0         0 print OUTFILE $_;
1647             }
1648 0         0 close OUTFILE;
1649 0         0 return $filename;
1650             }
1651             else {
1652 0         0 return 0;
1653             }
1654             }
1655              
1656             =head2 html
1657              
1658             I
1659             and return that data for output.>
1660              
1661             html B
1662              
1663             =over 3
1664              
1665             =item L
1666              
1667             =back
1668              
1669             html B
1670              
1671             my @data = $self->html;
1672            
1673             takes 1 argument
1674             1st argument - optional
1675             @data - data to be stored for output
1676            
1677             example:
1678             my $self =sweet;
1679             $self->html('save this for me', 'oh yeah, and this too');
1680             my @data = $self->html;
1681             # @data equals ['save this for me', 'oh yeah, and this too']
1682             my @data = $self->html;
1683             # @data equals [] because $self->html (no args) clears the store
1684            
1685             # Note! This method is called automatically and rendered if no
1686             # template is specified.
1687              
1688             =cut
1689              
1690             sub html {
1691 0     0 1 0 my ( $self, @html ) = @_;
1692 0 0       0 if (@html) {
1693 0         0 my @existing_html =
1694             $self->{store}->{application}->{html_content}
1695 0 0       0 ? @{ $self->{store}->{application}->{html_content} }
1696             : ();
1697 0         0 push @existing_html, @html;
1698 0         0 $self->{store}->{application}->{html_content} = \@existing_html;
1699 0         0 return;
1700             }
1701             else {
1702 0 0       0 if ( $self->{store}->{application}->{html_content} ) {
1703 0         0 my @content = @{ $self->{store}->{application}->{html_content} };
  0         0  
1704 0         0 $self->{store}->{application}->{html_content} = [];
1705 0         0 return \@content;
1706             }
1707             }
1708             }
1709              
1710             =head2 debug
1711              
1712             I
1713             for debugging purposes.>
1714              
1715             debug B
1716              
1717             =over 3
1718              
1719             =item L
1720              
1721             =back
1722              
1723             debug B
1724              
1725             $self->debug;
1726            
1727             takes 1 argument
1728             1st argument - optional
1729             @data - data to be stored for output
1730            
1731             example:
1732             my $self =sweet;
1733             $self->debug('something happened here', "\$var has a val of $var");
1734             my @data = $self->data;
1735             # @data equals ['something happened here', "$var has a val of blah"]
1736             my @data = $self->data;
1737             # @data equals [] because $self->data (no args) clears the store
1738              
1739             =cut
1740              
1741             sub debug {
1742 36     36 1 10947 my ( $self, @debug ) = @_;
1743 36 100       13995 if (@debug) {
1744 0         0 my @existing_debug =
1745             $self->{store}->{application}->{debug_content}
1746 18 50       125 ? @{ $self->{store}->{application}->{debug_content} }
1747             : ();
1748 18         83 my ( $package, $filename, $line ) = caller;
1749 18         54 my $count = (@existing_debug+1);
1750 18         567 @debug =
1751 18         50 map { $count . ". $_ at $package [$filename], on line $line." }
1752             @debug;
1753 18         54 push @existing_debug, @debug;
1754 18         102 $self->{store}->{application}->{debug_content} = \@existing_debug;
1755 18         77 return;
1756             }
1757             else {
1758 18 50       167 if ( $self->{store}->{application}->{debug_content} ) {
1759 18         196 my @content = @{ $self->{store}->{application}->{debug_content} };
  18         78  
1760 18         419 $self->{store}->{application}->{debug_content} = [];
1761 18         77 return \@content;
1762             }
1763             }
1764             }
1765              
1766             =head2 output
1767              
1768             I
1769             command-line.>
1770              
1771             output B
1772              
1773             =over 3
1774              
1775             =item L L
1776             L
1777              
1778             =back
1779              
1780             output B
1781              
1782             $self->output($output_what, $output_where, $seperator);
1783            
1784             takes 3 arguments
1785             1st argument - required
1786             $output_what - what data store to render [html|debug]
1787             2nd argument - optional
1788             $output_where- where to render content [web|cli]
1789             3rd argument - optional
1790             $seperator - printable line seperator
1791            
1792             example:
1793             my $self = sweet;
1794             $self->output('html'); # print html store to browser using
1795             $self->output('debug'); # print debug store to browser using
1796            
1797             $self->output('html', 'cli');
1798             # print html store to the command-line using \n
1799            
1800             $self->output('debug', 'cli', ',');
1801             # print debug store to the command-line using `,` as a seperator
1802              
1803             =cut
1804              
1805             sub output {
1806 18     18 1 119 my ( $self, $what, $where, $using ) = @_;
1807 18 50       79 if ($what eq 'debug') {
1808 18 50       99 if ($where eq 'cli') {
1809 18         68 my $input = $self->debug;
1810 18 50       79 my @output = $input ? @{$input} : ();
  18         56  
1811 18 50       88 my $seperator = defined $using ? $using : "\n";
1812 18         1494 print join( $seperator, @output );
1813 18         3508 exit;
1814             }
1815             else {
1816 0         0 my $input = $self->debug;
1817 0 0       0 my @output = $input ? @{$input} : ();
  0         0  
1818 0 0       0 my $seperator = defined $using ? $using : "
";
1819 0         0 $self->start();
1820 0         0 print join( $seperator, @output );
1821 0         0 exit;
1822             }
1823             }
1824             else {
1825 0 0       0 if ($where eq 'cli') {
1826 0         0 my $input = $self->html;
1827 0 0       0 my @output = $input ? @{$input} : ();
  0         0  
1828 0 0       0 my $seperator = defined $using ? $using : "\n";
1829 0         0 print join( $seperator, @output );
1830 0         0 exit;
1831             }
1832             else {
1833 0         0 my $input = $self->html;
1834 0 0       0 my @output = $input ? @{$input} : ();
  0         0  
1835 0 0       0 my $seperator = defined $using ? $using : "
";
1836 0         0 $self->start();
1837 0         0 print join( $seperator, @output );
1838 0         0 exit;
1839             }
1840             }
1841             }
1842              
1843             =head2 plug
1844              
1845             I
1846              
1847             plug B
1848              
1849             =over 3
1850              
1851             =item L L
1852              
1853             =back
1854              
1855             plug B
1856              
1857             $self->plug($accessor_name, $code_ref);
1858            
1859             takes 2 argument
1860             1st argument - required
1861             $accessor_name - name to be used in the app to access the code
1862             2ns argument - required
1863             $code_ref - code that instantiates an object of a class
1864            
1865             example:
1866             my $self = sweet;
1867             $self->plug('cgi', sub {
1868             shift;
1869             CGI->new(@_);
1870             });
1871            
1872             # elsewhere in the code
1873             $self->cgi->param('foo'); # etc
1874             $self->cgi->url_param('bar'); # same instance, different method call
1875            
1876             $self->unplug('cgi')->cgi->param('foo'); # new instance
1877              
1878             =cut
1879              
1880             sub plug {
1881 54     54 1 153 my ( $self, $name, $init ) = @_;
1882 54 50 33     348 if ( $name && $init ) {
1883 19     19   266 no warnings 'redefine';
  19         46  
  19         1646  
1884 19     19   130 no strict 'refs';
  19         48  
  19         15720  
1885 54         143 my $routine = ref($self) . "::$name";
1886 54 50       153 if ( ref $init eq "CODE" ) {
1887 54         312 *{$routine} = sub {
1888 130 100   130   2523 $self->{".$name"} = $init->(@_) unless $self->{".$name"};
1889 130         15983 return $self->{".$name"};
1890 54         262 };
1891             }
1892             else {
1893 0         0 *{$routine} = sub {
1894 0 0   0   0 $self->{".$name"} = $init unless $self->{".$name"};
1895 0         0 return $self->{".$name"};
1896 0         0 };
1897             }
1898             }
1899             }
1900              
1901             =head2 unplug
1902              
1903             I
1904             instance so a new one can be created.>
1905              
1906             unplug B
1907              
1908             =over 3
1909              
1910             =item L
1911              
1912             =back
1913              
1914             unplug B
1915              
1916             $self = $self->unplug($accessor_name);
1917            
1918             takes 1 argument
1919             1st argument - required
1920             $accessor_name - name to be used in the app to access the code
1921            
1922             example:
1923             my $self = sweet;
1924             $self->unplug('cgi');
1925             # creates a new instance of the CGI class object the next time
1926             # $self->cgi is called.
1927              
1928             =cut
1929              
1930             sub unplug {
1931 0     0 1 0 my ( $self, $name ) = @_;
1932 0         0 delete $self->{".$name"};
1933 0         0 return $self;
1934             }
1935              
1936             =head2 routes
1937              
1938             I
1939             controllers and actions.>
1940              
1941             routes B
1942              
1943             =over 3
1944              
1945             =item L
1946              
1947             =back
1948              
1949             routes B
1950              
1951             $self = $self->routes($actions);
1952            
1953             takes 1 argument
1954             1st argument - required
1955             \%actions - hashref of urls and coderef
1956            
1957             example:
1958             my $self = sweet;
1959             $self->routes({
1960             '/' => sub {
1961             my $s = shift;
1962             $s->html('Im an index page.');
1963             },
1964             '/about' => sub {
1965             my $s = shift;
1966             $s->html('Im an about us page');
1967             }
1968             });
1969              
1970             =cut
1971              
1972             sub routes {
1973 18     18 1 53 my ( $self, $routes ) = @_;
1974 20         43 map {
1975 18         101 my $url = $_;
1976 20 50 66     251 $url =~ s/\/$// if $url =~ /\/$/ && length($url) > 1;
1977 20         124 $self->application->{actions}->{$url} = $routes->{$_};
1978 18         75 } keys %{$routes};
1979 18         181 return $self;
1980             }
1981              
1982             =head2 param
1983              
1984             I
1985              
1986             param B
1987              
1988             =over 3
1989              
1990             =item L L
1991             L
1992              
1993             =back
1994              
1995             param B
1996              
1997             my $value = $self->param($param_name, $param_type);
1998            
1999             takes 2 argument
2000             1st argument - required
2001             $param_name - name of the get, post or session parameter
2002             2nd argument - optional
2003             $param_type - type of parameter
2004            
2005             example:
2006             my $self = sweet;
2007             my $value = $self->param('foo');
2008             my $value = $self->param('foo', 'get');
2009            
2010             my $new = $self->param('foo', 'session', 'something new');
2011             # sets value as well
2012            
2013              
2014             =cut
2015              
2016             sub param {
2017 18     18 1 13115 my ( $self, $name, $type, $value ) = @_;
2018            
2019 18 50       82 if ($value) {
2020 0 0 0     0 $self->cgi->param($name, $value)
2021             if $type eq 'get' or $type eq 'post';
2022 0 0       0 $self->session->param($name, $value)
2023             if $type eq 'session';
2024             }
2025            
2026 18 50 33     220 if ( $name && $type ) {
    50 33        
2027             return (
2028 0 0       0 $type eq 'get' ? $self->cgi->url_param($name)
    0          
    0          
2029             : ( $type eq 'post' ? $self->cgi->param($name)
2030             : ( $type eq 'session' ? $self->session->param($name) : '' ) )
2031             );
2032             }
2033             elsif ( $name && !$type ) {
2034 18 50       62 return $self->cgi->url_param($name) if $self->cgi->url_param($name);
2035 18 50       6091 return $self->cgi->param($name) if $self->cgi->param($name);
2036 0 0       0 return $self->session->param($name) if $self->session->param($name);
2037 0 0       0 return $self->application->{action_params}->{$self->controller}->{$name} if
2038             defined $self->application->{action_params}->{$self->controller}->{$name};
2039             }
2040             else {
2041 0         0 return 0;
2042             }
2043             }
2044              
2045             =head2 sweet
2046              
2047             I
2048              
2049             sweet B
2050              
2051             =over 3
2052              
2053             =item L
2054              
2055             =back
2056              
2057             sweet B
2058              
2059             $self = sweet;
2060            
2061             takes 1 argument
2062             1st argument - optional
2063             \%options - sweetpea runtime options
2064            
2065             example:
2066             my $s = sweet;
2067             my $s = sweet({ session_folder => '/tmp' });
2068              
2069             =cut
2070              
2071             sub sweet {
2072 18     18 1 294 return SweetPea->new(@_);
2073             }
2074              
2075             =head1 VARIABLE LEGEND
2076              
2077             =head2 \%actions
2078              
2079             my $routes = {
2080             '/url_path' => sub {
2081             $sweetpea_object = shift;
2082             ...
2083             },
2084             'other_url_path' => sub {
2085             $sweetpea_object = shift;
2086             ...
2087             }
2088             };
2089            
2090             =head2 \%options
2091              
2092             my $sweetpea_runtime_options = {
2093             local_session => 1,
2094             session_folder => '/tmp/site1'
2095             };
2096              
2097             =head2 $route
2098              
2099             my $route = '/'; # index/default page
2100             my $route = '/contact'; # good
2101             my $route = 'contact'; # bad
2102              
2103             =head2 $self
2104              
2105             my $self = sweet; # a SweetPea object
2106             my $self = SweetPea->new;
2107              
2108             =head2 @data
2109              
2110             my @data = qw(this is a test);
2111             # a simple array of data to be stored
2112              
2113             =head2 $url
2114              
2115             my $url = '/path/under/application/root/'; # good
2116             my $url = 'http://www.somesite.com/path/under/blah'; #bad
2117              
2118             =head2 $content_type
2119              
2120             my $content_type = 'text/html';
2121             my $content_type = 'text/plain';
2122             # etc
2123              
2124             =head2 $method
2125              
2126             my $method = 'get'; # valid request method
2127             my $method = 'post'; # valid request method
2128             my $method = 'put'; # valid request method
2129             # etc
2130              
2131             =head2 $file_or_data
2132              
2133             my $file_or_data = 'c:\tmp\file.txt'; # cool
2134             my $file_or_data = '/tmp/file.txt'; # good
2135             my $file_or_data = 'this is some content'; # works
2136            
2137             my $file_or_data = sweet->file('<', 'file.txt'); #bad
2138             my $file_or_data = join "\n", sweet->file('<', 'file.txt'); #better
2139              
2140             =head2 $path
2141              
2142             my $path = 'c:\tmp\file.txt'; # bad
2143             my $path = '/tmp/file.txt'; # bad
2144             my $path = '/under/application/root'; # yes, very nice
2145             my $path = 'under/application/root'; # works as well
2146              
2147             =head2 $flash_message
2148              
2149             my $flash_message = 'anything you need to convey to the user';
2150              
2151             =head2 $flash_type
2152              
2153             my $flash_type = 'info'; #good
2154             my $flash_type = 'warn'; #good
2155             my $flash_type = 'error'; #good
2156             my $flash_type = 'success'; #good
2157             my $flash_type = 'blah'; #bad
2158              
2159             =head2 $filemode
2160              
2161             my $filemode = 0666; # good
2162             my $filemode = 0777; #good
2163             my $filemode = 755; # bad
2164             my $filemode = 'catdog'; #bad
2165              
2166             =head2 $filename
2167              
2168             my $filename = 'c:\tmp\file.txt'; # cool
2169             my $filename = '/tmp/file.txt'; # good
2170              
2171             =head2 $output_what
2172              
2173             my $output_what = 'html'; # good
2174             my $output_what = 'debug'; # good
2175             my $output_what = 'textile'; # bad
2176              
2177             =head2 $output_where
2178              
2179             my $output_where = 'web'; # good
2180             my $output_where = 'cli'; # bad
2181              
2182             =head2 $seperator
2183              
2184             my $seperator = 'whatever'; # works, makes no sense though
2185             my $seperator = ',';
2186             my $seperator = "\n";
2187             my $seperator = "\r\n"; # windows
2188             my $seperator = "\t";
2189              
2190             =head2 $accessor_name
2191              
2192             my $accessor_name = 'math'; # good
2193             my $accessor_name = 'math_calc'; # good
2194             my $accessor_name = '_math_calc'; # ok
2195            
2196             my $accessor_name = '132'; # bad
2197             my $accessor_name = 'math-calc'; # very bad
2198              
2199             =head2 $code_ref
2200              
2201             my $code_ref = sub {
2202             my $sweetpea = shift; # always the first object
2203             ...
2204             };
2205              
2206             =head2 $param_name
2207              
2208             my $param_name = 'whatever';
2209              
2210             =head2 $param_type
2211              
2212             my $param_type = 'get'; # good
2213             my $param_type = 'post'; # good
2214             my $param_type = 'session'; # good
2215            
2216             my $param_type = 'csv'; # bad
2217              
2218             =head2 $param_value
2219              
2220             my $param_value = 'whatever';
2221              
2222             =cut
2223              
2224             1; # End of SweetPea