File Coverage

blib/lib/Nile.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             # Copyright Infomation
2             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3             # Author : Dr. Ahmed Amin Elsheshtawy, Ph.D.
4             # Website: https://github.com/mewsoft/Nile, http://www.mewsoft.com
5             # Email : mewsoft@cpan.org, support@mewsoft.com
6             # Copyrights (c) 2014-2015 Mewsoft Corp. All rights reserved.
7             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8             package Nile;
9              
10             our $VERSION = '0.46';
11             our $AUTHORITY = 'cpan:MEWSOFT';
12              
13             =pod
14              
15             =encoding utf8
16              
17             =head1 NAME
18              
19             Nile - Android Like Visual Web App Framework Separating Code From Design Multi Lingual And Multi Theme.
20              
21             =head1 SYNOPSIS
22            
23             #!/usr/bin/perl
24              
25             use Nile;
26              
27             my $app = Nile->new();
28            
29             # initialize the application with the shared and safe sessions settings
30             $app->init({
31             # base application path, auto detected if not set
32             path => dirname(File::Spec->rel2abs(__FILE__)),
33            
34             # load config files, default extension is xml
35             config => [ qw(config) ],
36              
37             # force run mode if not auto detected by default. modes: "psgi", "fcgi" (direct), "cgi" (direct)
38             #mode => "fcgi", # psgi, cgi, fcgi
39             });
40            
41             # inline actions, return content. url: /forum/home
42             $app->action("get", "/forum/home", sub {
43             my ($self) = @_;
44             # $self is set to the application context object same as $self->app in plugins
45             my $content = "Host: " . ($self->request->virtual_host || "") ."<br>\n";
46             $content .= "Request method: " . ($self->request->request_method || "") . "<br>\n";
47             $content .= "App Mode: " . $self->mode . "<br>\n";
48             $content .= "Time: ". time . "<br>\n";
49             $content .= "Hello world from inline action /forum/home" ."<br>\n";
50             $content .= "أحمد الششتاوى" ."<br>\n";
51             $self->response->encoded(0); # encode content
52             return $content;
53             });
54              
55             # inline actions, capture print statements, ignore the return value. url: /accounts/login
56             $app->capture("get", "/accounts/login", sub {
57             my ($self) = @_;
58             # $self is set to the application context object same as $self->app in plugins
59             say "Host: " . ($self->request->virtual_host || "") . "<br>\n";
60             say "Request method: " . ($self->request->request_method || "") . "<br>\n";
61             say "App Mode: " . $self->mode . "<br>\n";
62             say "Time: ". time . "<br>\n";
63             say "Hello world from inline action with capture /accounts/login", "<br>\n";
64             say $self->encode("أحمد الششتاوى ") ."<br>\n";
65             $self->response->encoded(1); # content already encoded
66             });
67              
68             # inline actions, capture print statements and the return value. url: /blog/new
69             $app->command("get", "/blog/new", sub {
70             my ($self) = @_;
71             # $self is set to the application context object same as $self->app in plugins
72             say "Host: " . ($self->request->virtual_host || "") . "<br>\n";
73             say "Request method: " . ($self->request->request_method || "") . "<br>\n";
74             say "App Mode: " . $self->mode . "<br>\n";
75             say "Time: ". time . "<br>\n";
76             say "Hello world from inline action with capture /blog/new and return value.", "<br>\n";
77             say $self->encode("أحمد الششتاوى ") ."<br>\n";
78             $self->response->encoded(1); # content already encoded
79             return " This value is returned from the command.";
80             });
81              
82             # run the application and return the PSGI response or print to the output
83             # the run process will also run plugins with matched routes files loaded
84             $app->run();
85              
86             =head1 DESCRIPTION
87              
88             Nile - Android Like Visual Web App Framework Separating Code From Design Multi Lingual And Multi Theme.
89              
90             B<Beta> version, API may change. The project's homepage L<https://github.com/mewsoft/Nile>.
91              
92             The main idea in this framework is to separate all the html design and layout from programming.
93             The framework uses html templates for the design with special xml tags for inserting the dynamic output into the templates.
94             All the application text is separated in langauge files in xml format supporting multi lingual applications with easy translating and modifying all the text.
95             The framework supports PSGI and also direct CGI and direct FCGI without any modifications to your applications.
96              
97             =head1 EXAMPLE APPLICATION
98              
99             Download and uncompress the module file. You will find an example application folder named B<app>.
100              
101             =head1 URLs
102              
103             This framework support SEO friendly url's, routing specific urls and short urls to actions.
104              
105             The url routing system works in the following formats:
106              
107             http://domain.com/module/controller/action # mapped from route file or to Module/Controller/action
108             http://domain.com/module/action # mapped from route file or to Module/Module/action or Module/Module/index
109             http://domain.com/module # mapped from route file or to Module/Module/module or Module/Module/index
110             http://domain.com/index.cgi?action=module/controller/action
111             http://domain.com/?action=module/controller/action
112             http://domain.com/blog/2014/11/28 # route mapped from route file and args passed as request params
113              
114             The following urls formats are all the same and all are mapped to the route /Home/Home/index or /Home/Home/home (/Module/Controller/Action):
115            
116             # direct cgi call, you can use action=home, route=home, or cmd=home
117             http://domain.com/index.cgi?action=home
118              
119             # using .htaccess to redirect to index.cgi
120             http://domain.com/?action=home
121              
122             # SEO url using with .htaccess. route is auto detected from url.
123             http://domain.com/home
124              
125             =head1 APPLICATION DIRECTORY STRUCTURE
126              
127             Applications built with this framework must have basic folder structure. Applications may have any additional directories.
128              
129             The following is the basic application folder tree that must be created manually before runing:
130              
131             ├───api
132             ├───cache
133             ├───cmd
134             ├───config
135             ├───cron
136             ├───data
137             ├───file
138             ├───lang
139             │ ├───ar
140             │ └───en-US
141             ├───lib
142             │ └───Nile
143             │ ├───Module
144             │ │ └───Home
145             │ └───Plugin
146             ├───log
147             ├───route
148             ├───temp
149             ├───theme
150             │ └───default
151             │ ├───css
152             │ ├───icon
153             │ ├───image
154             │ ├───js
155             │ ├───view
156             │ └───widget
157             └───web
158              
159             =head1 CREATING YOUR FIRST MODULE 'HOME'
160              
161             To create your first module called Home for your site home page, create a folder called B<Home> in your application path
162             C</path/lib/Nile/Module/Home>, then create the module Controller file say B<Home.pm> and put the following code:
163              
164             package Nile::Module::Home::Home;
165              
166             our $VERSION = '0.46';
167              
168             use Nile::Module; # automatically extends Nile::Module
169             use DateTime qw();
170             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
171             # plugin action, return content. url is routed direct or from routes files. url: /home
172             sub home : GET Action {
173            
174             my ($self, $app) = @_;
175            
176             # $app is set to the application context object, same as $self->app inside any method
177             #my $app = $self->app;
178            
179             my $view = $app->view("home");
180            
181             $view->var(
182             fname => 'Ahmed',
183             lname => 'Elsheshtawy',
184             email => 'sales@mewsoft.com',
185             website => 'http://www.mewsoft.com',
186             singleline => 'Single line variable <b>Good</b>',
187             multiline => 'Multi line variable <b>Nice</b>',
188             );
189            
190             #my $var = $view->block();
191             #say "block: " . $app->dump($view->block("first/second/third/fourth/fifth"));
192             #$view->block("first/second/third/fourth/fifth", "Block Modified ");
193             #say "block: " . $app->dump($view->block("first/second/third/fourth/fifth"));
194              
195             $view->block("first", "1st Block New Content ");
196             $view->block("six", "6th Block New Content ");
197              
198             #say "dump: " . $app->dump($view->block->{first}->{second}->{third}->{fourth}->{fifth});
199            
200             # module settings from config files
201             my $setting = $self->setting();
202            
203             # plugin session must be enabled in config.xml
204             if (!$app->session->{first_visit}) {
205             $app->session->{first_visit} = time;
206             }
207             my $dt = DateTime->from_epoch(epoch => $app->session->{first_visit});
208             $view->set("first_visit", $dt->strftime("%a, %d %b %Y %H:%M:%S"));
209            
210             # save visitors count to the cache
211             $app->cache->set("visitor_count", $app->cache->get("visitor_count") + 1, "1 year");
212             $view->set("visitor_count", $app->cache->get("visitor_count"));
213              
214             return $view->out();
215             }
216             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
217             # run action and capture print statements, no returns. url: /home/news
218             sub news: GET Capture {
219              
220             my ($self, $app) = @_;
221              
222             say qq{Hello world. This content is captured from print statements.
223             The action must be marked by 'Capture' attribute. No returns.};
224              
225             }
226             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
227             # run action and capture print statements and the return value. url: /home/info
228             sub info: GET Command {
229              
230             my ($self, $app) = @_;
231              
232             say qq{This content is captured from print statements.
233             The action marked by 'Command' attribute. };
234            
235             return qq{This content is the return value on the action.};
236             }
237             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
238             # regular method, can be invoked by views:
239             # <vars type="module" method="Home::Home->welcome" message="Welcome back!" />
240             sub welcome {
241             my ($self, %args) = @_;
242             my $app = $self->app();
243             return "Nice to see you, " . $args{message};
244             }
245             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
246             1;
247              
248             =head1 YOUR FIRST VIEW 'home'
249              
250             Create an html file name it as B<home.html>, put it in the default theme folder B</path/theme/default/views>
251             and put in this file the following code:
252              
253             <vars type="widget" name="header" charset_name="UTF-8" lang_name="en" />
254              
255             {first_name} <vars name="fname" /><br>
256             {last_name} <vars name="lname" /><br>
257             {email} <vars type="var" name='email' /><br>
258             {website} <vars type="var" name="website" /><br>
259             <br>
260              
261             global variables:<br>
262             language: <vars name='lang' /><br>
263             theme: <vars name="theme" /><br>
264             base url: <vars name="base_url" /><br>
265             image url: <vars name="image_url" /><br>
266             css url: <vars name="css_url" /><br>
267             new url: <a href="<vars name="base_url" />comments" >comments</a><br>
268             image: <img src="<vars name="image_url" />logo.png" /><br>
269             <br>
270             first visit: <vars name="first_visit" /><br>
271             <br>
272              
273             {date_now} <vars type="plugin" method="Date->date" format="%a, %d %b %Y %H:%M:%S" /><br>
274             {time_now} <vars type="plugin" method="Date->time" format="%A %d, %B %Y %T %p" /><br>
275             {date_time} <vars type="plugin" method="Date::now" capture="1" format="%B %d, %Y %r" /><br>
276              
277             <br>
278             <vars type="module" method="Home::Home->welcome" message="Welcome back!" /><br>
279             <br>
280              
281             Our Version: <vars type="perl"><![CDATA[print $self->app->VERSION; return;]]></vars><br>
282             <br>
283              
284             <pre>
285             <vars type="perl">system ('dir *.cgi');</vars>
286             </pre>
287             <br>
288              
289             <vars type="var" name="singleline" width="400px" height="300px" content="ahmed<b>class/subclass">
290             cdata start here is may have html tags and 'single' and "double" qoutes
291             </vars>
292             <br>
293              
294             <vars type="var" name="multiline" width="400px" height="300px"><![CDATA[
295             cdata start here is may have html tags <b>hello</b> and 'single' and "double" qoutes
296             another cdata line
297             ]]></vars>
298             <br>
299              
300             <vars type="perl"><![CDATA[
301             say "";
302             say "<br>active language: " . $self->app->var->get("lang");
303             say "<br>active theme: " . $self->app->var->get("theme");
304             say "<br>app path: " . $self->app->var->get("path");
305             say "<br>";
306             ]]></vars>
307             <br><br>
308              
309             html content 1-5 top
310             <!--block:first-->
311             <table border="1" style="color:red;">
312             <tr class="lines">
313             <td align="left" valign="<--valign-->">
314             <b>bold</b><a href="http://www.mewsoft.com">mewsoft</a>
315             <!--hello--> <--again--><!--world-->
316             some html content here 1 top
317             <!--block:second-->
318             some html content here 2 top
319             <!--block:third-->
320             some html content here 3 top
321             <!--block:fourth-->
322             some html content here 4 top
323             <!--block:fifth-->
324             some html content here 5a
325             some html content here 5b
326             <!--endblock-->
327             <!--endblock-->
328             some html content here 3a
329             some html content here 3b
330             <!--endblock-->
331             some html content here 2 bottom
332             </tr>
333             <!--endblock-->
334             some html content here 1 bottom
335             </table>
336             <!--endblock-->
337             html content 1-5 bottom
338              
339             <br><br>
340              
341             html content 6-8 top
342             <!--block:six-->
343             some html content here 6 top
344             <!--block:seven-->
345             some html content here 7 top
346             <!--block:eight-->
347             some html content here 8a
348             some html content here 8b
349             <!--endblock-->
350             some html content here 7 bottom
351             <!--endblock-->
352             some html content here 6 bottom
353             <!--endblock-->
354             html content 6-8 bottom
355              
356             <br><br>
357              
358             <vars type="widget" name="footer" title="cairo" lang="ar" />
359              
360             =head1 YOUR FIRST WIDGETS 'header' AND 'footer'
361              
362             The framework supports widgets, widgets are small views that can be repeated in many views for easy layout and design.
363             For example, you could make the site header template as a widget called B<header> and the site footer template as a
364             widget called B<footer> and just put the required xml special tag for these widgets in all the B<Views> you want.
365             Widgets files are html files located in the theme B<'widget'> folder
366              
367             Example widget B<header.html>
368              
369             <!doctype html>
370             <html lang="{lang_code}">
371             <head>
372             <meta http-equiv="content-type" content="text/html; charset=[:charset_name:]" />
373             <title>{page_title}</title>
374             <meta name="Keywords" content="{meta_keywords}" />
375             <meta name="Description" content="{meta_description}" />
376             </head>
377             <body>
378              
379             Example widget B<footer.html>
380              
381             </body>
382             </html>
383              
384             then all you need to include the widget in the view is to insert these tags:
385              
386             <vars type="widget" name="header" charset_name="UTF-8" />
387             <vars type="widget" name="footer" />
388              
389             You can pass args to the widget like B<charset_name> to the widget above and will be replaced with their values.
390              
391              
392             =head1 LANGUAGES
393              
394             All application text is located in text files in xml format. Each language supported should be put under a folder named
395             with the iso name of the langauge under the folder path/lang.
396              
397             Example langauge file B<'general.xml'>:
398              
399             <?xml version="1.0" encoding="UTF-8" ?>
400              
401             <lang_code>en</lang_code>
402             <site_name>Site Name</site_name>
403             <home>Home</home>
404             <register>Register</register>
405             <contact>Contact</contact>
406             <about>About</about>
407             <copyright>Copyright</copyright>
408             <privacy>Privacy</privacy>
409              
410             <page_title>Create New Account</page_title>
411             <first_name>First name:</first_name>
412             <middle_name>Middle name:</middle_name>
413             <last_name>Last name:</last_name>
414             <full_name>Full name:</full_name>
415             <email>Email:</email>
416             <job>Job title:</job>
417             <website>Website:</website>
418             <agree>Agree:</agree>
419             <company>Company</company>
420              
421             <date_now>Date: </date_now>
422             <time_now>Time: </time_now>
423             <date_time>Now: </date_time>
424              
425             =head1 Routing
426              
427             The framework supports url routing, route specific short name actions like 'register' to specific plugins like Accounts/Register/create.
428              
429             Below is B<route.xml> file example should be created under the path/route folder.
430              
431             <?xml version="1.0" encoding="UTF-8" ?>
432              
433             <home route="/home" action="/Home/Home/home" method="get" />
434             <register route="/register" action="/Accounts/Register/register" method="get" defaults="year=1900|month=1|day=23" />
435             <post route="/blog/post/{cid:\d+}/{id:\d+}" action="/Blog/Article/Post" method="post" />
436             <browse route="/blog/{id:\d+}" action="/Blog/Article/Browse" method="get" />
437             <view route="/blog/view/{id:\d+}" action="/Blog/Article/View" method="get" />
438             <edit route="/blog/edit/{id:\d+}" action="/Blog/Article/Edit" method="get" />
439              
440             =head1 CONFIG
441              
442             The framework supports loading and working with config files in xml formate located in the folder 'config'.
443              
444             Example config file path/config/config.xml:
445              
446             <?xml version="1.0" encoding="UTF-8" ?>
447              
448             <app>
449             <config></config>
450             <route>route.xml</route>
451             <log_file>log.pm</log_file>
452             <action_name>action,route,cmd</action_name>
453             <default_route>/Home/Home/home</default_route>
454             <charset>utf-8</charset>
455             <theme>default</theme>
456             <lang>en-US</lang>
457             <lang_param_key>lang</lang_param_key>
458             <lang_cookie_key>lang</lang_cookie_key>
459             <lang_session_key>lang</lang_session_key>
460             <lang_file>general</lang_file>
461             </app>
462              
463             <admin>
464             <user>admin_user</user>
465             <password>admin_pass</password>
466             </admin>
467              
468             <database>
469             <driver>mysql</driver>
470             <host>localhost</host>
471             <dsn></dsn>
472             <port>3306</port>
473             <name>auctions</name>
474             <user>auctions</user>
475             <pass>auctions</pass>
476             <attr>
477             </attr>
478             <encoding>utf8</encoding>
479             </database>
480              
481             <module>
482             <home>
483             <header>home</header>
484             <footer>footer</footer>
485             </home>
486             </module>
487              
488             <plugin>
489             <email>
490             <transport>Sendmail</transport>
491             <sendmail>/usr/sbin/sendmail</sendmail>
492             </email>
493              
494             <session>
495             <autoload>1</autoload>
496             <key>nile_session_key</key>
497             <expire>1 year</expire>
498             <cache>
499             <driver>File</driver>
500             <root_dir></root_dir>
501             <namespace>session</namespace>
502             </cache>
503             <cookie>
504             <path>/</path>
505             <secure></secure>
506             <domain></domain>
507             <httponly></httponly>
508             </cookie>
509             </session>
510              
511             <cache>
512             <autoload>0</autoload>
513             </cache>
514             </plugin>
515              
516             =head1 APPLICATION INSTANCE SHARED DATA
517              
518             The framework is fully Object-oriented to allow multiple separate instances. Inside any module or plugin
519             you will be able to access the application instance by calling the method C<< $self->app >> which is automatically
520             injected into all modules with the application instance.
521              
522             The plugins and modules files will have the following features.
523              
524             Moose enabled
525             Strict and Warnings enabled.
526             a Moose attribute called C<app> injected holds the application singleton instance to access all the data and methods.
527              
528             Inside your modules and plugins, you will be able to access the application instance by:
529            
530             my $app = $self->app;
531              
532             Then you can access the application methods and objects like:
533            
534             $app->request->param("username");
535             # same as
536             $self->app->request->param("username");
537              
538             $app->response->code(200);
539              
540             $app->var->set("name", "value");
541              
542             =head1 URL REWRITE .htaccess for CGI and FCGI
543              
544             To hide the script name B<index.cgi> from the url and allow nice SEO url routing, you need to turn on url rewrite on
545             your web server and have .htaccess file in the application folder with the index.cgi.
546              
547             Below is a sample .htaccess which redirects all requests to index.cgi file and hides index.cgi from the url,
548             so instead of calling the application as:
549              
550             http://domain.com/index.cgi?action=register
551              
552             using the .htaccess you will be able to call it as:
553              
554             http://domain.com/register
555              
556             without any changes in the code.
557              
558             For direct FCGI, just replace .cgi with .fcgi in the .htaccess and rename index.cgi to index.fcgi.
559              
560             # Don't show directory listings for URLs which map to a directory.
561             Options -Indexes -MultiViews
562              
563             # Follow symbolic links in this directory.
564             Options +FollowSymLinks
565              
566             #Note that AllowOverride Options and AllowOverride FileInfo must both be in effect for these directives to have any effect,
567             #i.e. AllowOverride All in httpd.conf
568             Options +ExecCGI
569             AddHandler cgi-script cgi pl
570              
571             # Set the default handler.
572             DirectoryIndex index.cgi index.html index.shtml
573              
574             # save this file as UTF-8 and enable the next line for utf contents
575             #AddDefaultCharset UTF-8
576              
577             # REQUIRED: requires mod_rewrite to be enabled in Apache.
578             # Please check that, if you get an "Internal Server Error".
579             RewriteEngine On
580             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
581             # force use www with http and https so http://domain.com redirect to http://www.domain.com
582             #add www with https support - you have to put this in .htaccess file in the site root folder
583             # skip local host
584             RewriteCond %{HTTP_HOST} !^localhost
585             # skip IP addresses
586             RewriteCond %{HTTP_HOST} ^([a-z.]+)$ [NC]
587             RewriteCond %{HTTP_HOST} !^www\.
588             RewriteCond %{HTTPS}s ^on(s)|''
589             RewriteRule ^ http%1://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
590             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
591             RewriteCond %{REQUEST_FILENAME} !-f
592             RewriteCond %{REQUEST_FILENAME} !-d
593             RewriteCond %{REQUEST_URI} !=/favicon.ico
594             RewriteRule ^(.*)$ index.cgi [L,QSA]
595              
596             =head1 REQUEST
597              
598             The http request is available as a shared object extending the L<CGI::Simple> module. This means that all methods supported
599             by L<CGI::Simple> is available with the additions of these few methods:
600              
601             is_ajax
602             is_post
603             is_get
604             is_head
605             is_put
606             is_delete
607             is_patch
608              
609             You access the request object by $self->app->request.
610              
611             =head1 ERRORS, WARNINGS, ABORTING
612            
613             To abort the application at anytime with optional message and stacktrace, call the method:
614            
615             $self->app->abort("application error, can not find file required");
616              
617             For fatal errors with custom error message
618            
619             $self->app->error("error message");
620              
621             For fatal errors with custom error message and full starcktrace
622            
623             $self->app->errors("error message");
624              
625             For displaying warning message
626              
627             $self->app->warning("warning message");
628              
629             =head1 LOGS
630              
631             The framework supports a log object which is a L<Log::Tiny> object which supports unlimited log categories, so simply
632             you can do this:
633              
634             $app->log->info("application run start");
635             $app->log->DEBUG("application run start");
636             $app->log->ERROR("application run start");
637             $app->log->INFO("application run start");
638             $app->log->ANYTHING("application run start");
639              
640             =head1 FILE
641              
642             The file object provides tools for reading files, folders, and most of the functions in the modules L<File::Spec> and L<File::Basename>.
643              
644             to get file content as single string or array of strings:
645            
646             $content = $app->file->get($file);
647             @lines = $app->file->get($file);
648              
649             supports options same as L<File::Slurp>.
650              
651             To get list of files in a specific folder:
652            
653             #files($dir, $match, $relative)
654             @files = $app->file->files("c:/apache/htdocs/nile/", "*.pm, *.cgi");
655            
656             #files_tree($dir, $match, $relative, $depth)
657             @files = $app->file->files_tree("c:/apache/htdocs/nile/", "*.pm, *.cgi");
658              
659             #folders($dir, $match, $relative)
660             @folders = $app->file->folders("c:/apache/htdocs/nile/", "", 1);
661              
662             #folders_tree($dir, $match, $relative, $depth)
663             @folders = $app->file->folders_tree("c:/apache/htdocs/nile/", "", 1);
664              
665             =head1 XML
666              
667             Loads xml files into hash tree using L<XML::TreePP>
668            
669             $xml = $app->xml->load("configs.xml");
670              
671             =head1 DATABASE
672              
673             See L<Nile::Database>
674              
675             The database class provides methods for connecting to the sql database and easy methods for sql operations.
676              
677             =head1 METHODS
678              
679             =cut
680             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
681             # the first thing to do, catch and show errors nicely
682             BEGIN {
683             $|=1;
684 1     1   70810 use CGI::Carp qw(fatalsToBrowser warningsToBrowser set_message);
  1         8829  
  1         8  
685 1     1   5984 use Devel::StackTrace;
  1         22793  
  1         31  
686 1     1   12107 use Devel::StackTrace::AsHTML;
  1         22531  
  1         42  
687 1     1   815 use PadWalker;
  1         6475  
  1         92  
688 1     1   1074 use Devel::StackTrace::WithLexicals;
  0            
  0            
689              
690             sub handle_errors {
691             my $msg = shift;
692             #my $trace = Devel::StackTrace->new(indent => 1, message => $msg, ignore_package => [qw(Carp CGI::Carp)]);
693             my $trace = Devel::StackTrace::WithLexicals->new(indent => 1, message => $msg, ignore_package => [qw(Carp CGI::Carp)]);
694             #$trace->frames(reverse $trace->frames);
695             print $trace->as_html;
696             }
697             set_message(\&handle_errors);
698             }
699             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
700             use Moose;
701             use namespace::autoclean;
702             use MooseX::MethodAttributes;
703             #use MooseX::ClassAttribute;
704              
705             use utf8;
706             use File::Spec;
707             use File::Basename;
708             use Cwd;
709             use URI;
710             use Encode ();
711             use URI::Escape;
712             use Crypt::RC4;
713             #use Crypt::CBC;
714             use Capture::Tiny ();
715             use Time::Local;
716             use File::Slurp;
717             use Time::HiRes qw(gettimeofday tv_interval);
718             use MIME::Base64 3.11 qw(encode_base64 decode_base64 decode_base64url encode_base64url);
719              
720             use Data::Dumper;
721             $Data::Dumper::Deparse = 1; #stringify coderefs
722             #use LWP::UserAgent;
723              
724             #no warnings qw(void once uninitialized numeric);
725              
726             use Nile::App;
727             use Nile::Say;
728             use Nile::Plugin;
729             use Nile::Plugin::Object;
730             use Nile::Module;
731             use Nile::View;
732             use Nile::XML;
733             use Nile::Var;
734             use Nile::File;
735             use Nile::Lang;
736             use Nile::Config;
737             use Nile::Router;
738             use Nile::Dispatcher;
739             use Nile::Database;
740             use Nile::Setting;
741             use Nile::Timer;
742             use Nile::HTTP::Request;
743             use Nile::HTTP::Response;
744              
745             #use base 'Import::Base';
746             use Import::Into;
747             use Module::Load;
748             use Module::Runtime qw(use_module);
749             our @EXPORT_MODULES = (
750             #strict => [],
751             #warnings => [],
752             Moose => [],
753             utf8 => [],
754             #'File::Spec' => [],
755             #'File::Basename' => [],
756             Cwd => [],
757             'Nile::Say' => [],
758             'MooseX::MethodAttributes' => [],
759             );
760              
761             use base 'Exporter';
762             our @EXPORT = qw();
763             our @EXPORT_OK = qw();
764             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
765             sub import {
766              
767             my ($class, @args) = @_;
768              
769             my ($package, $script) = caller;
770            
771             # import list of modules to the calling package
772             my @modules = @EXPORT_MODULES;
773             while (@modules) {
774             my $module = shift @modules;
775             my $imports = ref $modules[0] eq 'ARRAY' ? shift @modules : [];
776             use_module($module)->import::into($package, @{$imports});
777             }
778             #------------------------------------------------------
779             $class->detect_app_path($script);
780             #------------------------------------------------------
781             my $caller = $class.'::';
782             {
783             no strict 'refs';
784             @{$caller.'EXPORT'} = @EXPORT;
785             foreach my $sub (@EXPORT) {
786             next if (*{"$caller$sub"}{CODE});
787             *{"$caller$sub"} = \*{$sub};
788             }
789             }
790              
791             $class->export_to_level(1, $class, @args);
792             #------------------------------------------------------
793             }
794             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
795             sub detect_app_path {
796              
797             my ($self, $script) = @_;
798              
799             $script ||= (caller)[1];
800              
801             my ($vol, $dirs, $name) = File::Spec->splitpath(File::Spec->rel2abs($script));
802              
803             if (-d (my $fulldir = File::Spec->catdir($dirs, $name))) {
804             $dirs = $fulldir;
805             $name = "";
806             }
807              
808             my $path = $vol? File::Spec->catpath($vol, $dirs) : File::Spec->catdir($dirs);
809            
810             $ENV{NILE_APP_DIR} = $path;
811              
812             return ($path);
813             }
814             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
815             sub BUILD { # our sub new {...}
816             my ($self, $arg) = @_;
817             }
818             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
819             =head2 init()
820            
821             use Nile;
822              
823             my $app = Nile->new();
824              
825             $app->init({
826             # base application path, auto detected if not set
827             path => dirname(File::Spec->rel2abs(__FILE__)),
828            
829             # load config files, default extension is xml
830             config => [ qw(config) ],
831              
832             # force run mode if not auto detected by default. modes: "psgi", "fcgi" (direct), "cgi" (direct)
833             #mode => "fcgi", # psgi, cgi, fcgi
834             });
835              
836             Initialize the application with the shared and safe sessions settings.
837              
838             =cut
839              
840             has 'init' => (
841             is => 'rw',
842             isa => 'HashRef',
843             default => sub { +{} }
844             );
845             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
846             =head2 var()
847            
848             See L<Nile::Var>.
849              
850             =cut
851              
852             has 'var' => (
853             is => 'rw',
854             lazy => 1,
855             default => sub {
856             shift->object ("Nile::Var", @_);
857             }
858             );
859             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
860             =head2 config()
861            
862             See L<Nile::Config>.
863              
864             =cut
865              
866             has 'config' => (
867             is => 'rw',
868             isa => 'Nile::Config',
869             lazy => 1,
870             default => sub {
871             shift->object("Nile::Config", @_);
872             }
873             );
874             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
875             =head2 run()
876            
877             $app->run();
878              
879             Run the application and dispatch the command.
880              
881             =cut
882              
883             sub run {
884              
885             my ($self, $arg) = @_;
886            
887             #$self->log->info("application run start in mode: ". uc($self->mode));
888             #say "run_time: " . $self->run_time->total;
889             #------------------------------------------------------
890             $arg = $self->init();
891              
892             my ($package, $script) = caller;
893            
894             $arg->{path} ||= $self->detect_app_path($script);
895              
896             my $file = $self->file;
897              
898             # setup the path for the app folders
899             foreach (qw(api cache cmd config cron data file lib log route temp web)) {
900             $self->var->set($_."_dir" => $file->catdir($arg->{path}, $_));
901             }
902              
903             $self->var->set(
904             'path' => $arg->{path},
905             'langs_dir' => $file->catdir($arg->{path}, "lang"),
906             'themes_dir' => $file->catdir($arg->{path}, "theme"),
907             'log_file' => $arg->{log_file} || "log.pm",
908             'action_name' => $arg->{action_name} || "action,route,cmd",
909             'default_route' => $arg->{default_route} || "/Home/Home/index",
910             );
911            
912             push @INC, $self->var->get("lib_dir");
913             #------------------------------------------------------
914             # detect and load request and response handler classes
915             $arg->{mode} ||= "cgi";
916             $arg->{mode} = lc($arg->{mode});
917             $self->mode($arg->{mode});
918            
919             #$self->log->debug("mode: $arg{mode}");
920              
921             # force PSGI if PLACK_ENV is set
922             if ($ENV{'PLACK_ENV'}) {
923             $self->mode("psgi");
924             }
925             #$self->log->debug("mode after PLACK_ENV: $arg{mode}");
926            
927             # FCGI sets $ENV{GATEWAY_INTERFACE }=> 'CGI/1.1' inside the accept request loop but nothing is set before the accept loop
928             # command line invocations will not set this variable also
929             if ($self->mode() ne "psgi") {
930             if (exists $ENV{GATEWAY_INTERFACE} ) {
931             # CGI
932             $self->mode("cgi");
933             }
934             else {
935             # FCGI or command line
936             $self->mode("fcgi");
937             }
938             }
939            
940             #$self->log->debug("mode to run: $arg{mode}");
941              
942             if ($self->mode() eq "psgi") {
943             load Nile::HTTP::Request::PSGI;
944             load Nile::Handler::PSGI;
945             }
946             elsif ($self->mode() eq "fcgi") {
947             load Nile::HTTP::Request;
948             load Nile::Handler::CGI;
949             load Nile::Handler::FCGI;
950             }
951             else {
952             load Nile::HTTP::Request;
953             load Nile::Handler::CGI;
954             }
955             #------------------------------------------------------
956             # load config files from init
957             foreach (@{$arg->{config}}) {
958             #$self->config->xml->keep_order(1);
959             $self->config->load($_);
960             }
961             #------------------------------------------------------
962             #------------------------------------------------------
963             # load extra config files from config files settings
964             foreach my $config ($self->config->get("app/config")) {
965             $config = $self->filter->trim($config);
966             $self->config->load($config) if ($config);
967             }
968             #------------------------------------------------------
969             # load route files
970             foreach my $route($self->config->get("app/route")) {
971             $route = $self->filter->trim($route);
972             $self->router->load($route) if ($route);
973             }
974             #------------------------------------------------------
975             foreach my $config (qw(charset action_name lang theme default_route log_file)) {
976             if ($self->config->get("app/$config")) {
977             $self->var->set($config, $self->config->get("app/$config"));
978             }
979             }
980             #------------------------------------------------------
981             my $class = "Nile::Handler::" . uc($self->mode());
982             my $handler = $self->object($class);
983             my $psgi = $handler->run();
984              
985             #say "run_time: " . $self->run_time->total;
986             #$self->log->info("application run end");
987            
988             # return the PSGI app
989             return $psgi;
990             }
991             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
992             =head2 action()
993            
994             # inline actions, return content. url: /forum/home
995             $app->action("get", "/forum/home", sub {
996             my ($self) = @_;
997             # $self is set to the application context object same as $self->app in plugins
998             my $content = "Host: " . ($self->request->virtual_host || "") ."<br>\n";
999             $content .= "Request method: " . ($self->request->request_method || "") . "<br>\n";
1000             $content .= "App Mode: " . $self->mode . "<br>\n";
1001             $content .= "Time: ". time . "<br>\n";
1002             $content .= "Hello world from inline action /forum/home" ."<br>\n";
1003             $content .= "أحمد الششتاوى" ."<br>\n";
1004             $self->response->encoded(0); # encode content
1005             return $content;
1006             });
1007              
1008             Add inline action, return content to the dispatcher.
1009              
1010             =cut
1011              
1012             sub action {
1013             my $self = shift;
1014             $self->add_action_route(undef, @_);
1015             }
1016             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1017             =head2 capture()
1018            
1019             # inline actions, capture print statements, no returns. url: /accounts/login
1020             $app->capture("get", "/accounts/login", sub {
1021             my ($self) = @_;
1022             # $self is set to the application context object same as $self->app in plugins
1023             say "Host: " . ($self->request->virtual_host || "") . "<br>\n";
1024             say "Request method: " . ($self->request->request_method || "") . "<br>\n";
1025             say "App Mode: " . $self->mode . "<br>\n";
1026             say "Time: ". time . "<br>\n";
1027             say "Hello world from inline action with capture /accounts/login", "<br>\n";
1028             say $self->encode("أحمد الششتاوى ") ."<br>\n";
1029             $self->response->encoded(1); # content already encoded
1030             });
1031              
1032             Add inline action, capture print statements, no returns to the dispatcher.
1033              
1034             =cut
1035              
1036             sub capture {
1037             my $self = shift;
1038             $self->add_action_route("capture", @_);
1039             }
1040             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1041             =head2 command()
1042            
1043             # inline actions, capture print statements and return value. url: /blog/new
1044             $app->command("get", "/blog/new", sub {
1045             my ($self) = @_;
1046             # $self is set to the application context object same as $self->app in plugins
1047             say "Host: " . ($self->request->virtual_host || "") . "<br>\n";
1048             say "Request method: " . ($self->request->request_method || "") . "<br>\n";
1049             say "App Mode: " . $self->mode . "<br>\n";
1050             say "Time: ". time . "<br>\n";
1051             say "Hello world from inline action with capture /blog/new and return value.", "<br>\n";
1052             say $self->encode("أحمد الششتاوى ") ."<br>\n";
1053             $self->response->encoded(1); # content already encoded
1054             return " This value is returned from the command.";
1055             });
1056              
1057             Add inline action, capture print statements and returns to the dispatcher.
1058              
1059             =cut
1060              
1061             sub command {
1062             my $self = shift;
1063             $self->add_action_route("command", @_);
1064             }
1065             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1066             sub add_action_route {
1067             my $self = shift;
1068             my $type = shift;
1069             my ($method, $route, $action) = $self->action_args(@_);
1070             $self->router->add_route(
1071             name => "",
1072             path => $route,
1073             target => $action,
1074             method => $method,
1075             defaults => {
1076             #id => 1
1077             },
1078             attributes => $type,
1079             );
1080             }
1081             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1082             sub action_args {
1083            
1084             my $self = shift;
1085              
1086             #my @methods = qw(get post put patch delete options head);
1087              
1088             my ($method, $route, $action);
1089              
1090             if (@_ == 1) {
1091             #$app->action(sub {});
1092             ($action) = @_;
1093             }
1094             elsif (@_ == 2) {
1095             #$app->action("/home", sub {});
1096             ($route, $action) = @_;
1097             }
1098             elsif (@_ == 3) {
1099             #$app->action("get", "/home", sub {});
1100             ($method, $route, $action) = @_;
1101             }
1102             else {
1103             $self->abort("Action error. Empty action and route. Syntax \$app->action(\$method, \$route, \$coderef) ");
1104             }
1105              
1106             $method ||= "";
1107             $route ||= "/";
1108            
1109             if (ref($action) ne "CODE") {
1110             $self->abort("Action error, must be a valid code reference. Syntax \$app->action(\$method, \$route, \$coderef) ");
1111             }
1112            
1113             return ($method, $route, $action);
1114             }
1115             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1116             =head2 router()
1117            
1118             See L<Nile::Router>.
1119              
1120             =cut
1121              
1122             has 'router' => (
1123             is => 'rw',
1124             isa => 'Nile::Router',
1125             lazy => 1,
1126             default => sub {
1127             shift->object("Nile::Router", @_);
1128             }
1129             );
1130             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1131             =head2 filter()
1132            
1133             See L<Nile::Filter>.
1134              
1135             =cut
1136              
1137             has 'filter' => (
1138             is => 'rw',
1139             isa => 'Nile::Filter',
1140             lazy => 1,
1141             default => sub {
1142             load Nile::Filter;
1143             shift->object("Nile::Filter", @_);
1144             }
1145             );
1146             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1147             =head2 file()
1148              
1149             See L<Nile::File>.
1150              
1151             =cut
1152              
1153             has 'file' => (
1154             is => 'rw',
1155             isa => 'Nile::File',
1156             default => sub {
1157             shift->object("Nile::File", @_);
1158             }
1159             );
1160             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1161             =head2 xml()
1162            
1163             See L<Nile::XML>.
1164              
1165             =cut
1166              
1167             has 'xml' => (
1168             is => 'rw',
1169             lazy => 1,
1170             default => sub {
1171             my $self = shift;
1172             $self->object("Nile::XML", @_);
1173             }
1174             );
1175             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1176             =head2 mode()
1177            
1178             my $mode = $app->mode;
1179              
1180             Returns the current application mode PSGI, FCGI or CGI.
1181              
1182             =cut
1183              
1184             has 'mode' => (
1185             is => 'rw',
1186             isa => 'Str',
1187             default => "cgi",
1188             );
1189             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1190             =head2 lang()
1191            
1192             See L<Nile::Lang>.
1193              
1194             =cut
1195              
1196             has 'lang' => (
1197             is => 'rw',
1198             isa => 'Nile::Lang',
1199             lazy => 1,
1200             default => sub {
1201             shift->object("Nile::Lang", @_);
1202             }
1203             );
1204             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1205             =head2 object()
1206            
1207             $obj = $app->object("Nile::MyClass", @args);
1208             $obj = $app->object("Nile::Plugin::MyClass", @args);
1209             $obj = $app->object("Nile::Module::MyClass", @args);
1210              
1211             #...
1212              
1213             $me = $obj->app;
1214            
1215             Creates and returns an object. This automatically adds the method L<me> to the object
1216             and sets it to the current context so your object or class can access the current instance.
1217              
1218             =cut
1219              
1220             sub object {
1221              
1222             my ($self, $class, @args) = @_;
1223             my ($object, $app);
1224            
1225             #if (@args == 1 && ref($args[0]) eq "HASH") {
1226             # # Moose single arguments must be hash ref
1227             # $object = $class->new(@args);
1228             #}
1229              
1230             if (@args && @args % 2) {
1231             # Moose needs args as hash, so convert odd size arrays to even for hashing
1232             $object = $class->new(@args, undef);
1233             }
1234             else {
1235             $object = $class->new(@args);
1236             }
1237              
1238             my $meta = $object->meta;
1239              
1240             #$meta->add_method( 'hello' => sub { return "Hello inside hello method. @_" } );
1241             #$meta->add_class_attribute( $_, %options ) for @{$attrs}; #MooseX::ClassAttribute
1242             #$meta->add_class_attribute( 'cash', ());
1243              
1244             # add method "me" or one of its alt
1245             $self->add_object_context($object, $meta);
1246              
1247             # if class has defined "main" method, then call it
1248             if ($object->can("main")) {
1249             $object->main(@args);
1250             }
1251            
1252             #no strict 'refs';
1253             #*{"$object"."::app"} = \&app;
1254             #${"${package}::$apps"} = 1;
1255            
1256             return $object;
1257             }
1258             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1259             sub add_object_context {
1260             my ($self, $object, $meta) = @_;
1261             $meta ||= $object->meta;
1262             # add method "me" or one of its alt
1263             #foreach (qw(app APP _app)) {
1264             foreach (qw(app)) {
1265             unless ($object->can($_)) {
1266             $meta->add_attribute($_ => (is => 'rw', default => sub{$self}));
1267             $object->$_($self);
1268             last;
1269             }
1270             }
1271             }
1272             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1273             =head2 dump()
1274            
1275             $app->dump({...});
1276              
1277             Print object to the STDOUT. Same as C<say Dumper (@_);>.
1278              
1279             =cut
1280              
1281             sub dump {
1282             my $self = shift;
1283             say Dumper (@_);
1284             return;
1285             }
1286             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1287             =head2 is_loaded()
1288            
1289             if ($app->is_loaded("Nile::SomeModule")) {
1290             #...
1291             }
1292            
1293             if ($app->is_loaded("Nile/SomeModule.pm")) {
1294             #...
1295             }
1296              
1297             Returns true if module is loaded, false otherwise.
1298              
1299             =cut
1300              
1301             sub is_loaded {
1302             my ($self, $module) = @_;
1303             (my $file = $module) =~ s/::/\//g;
1304             $file .= '.pm' unless ($file =~ /\.pm$/);
1305             #note: do() does unconditional loading -- no lookup in the %INC hash is made.
1306             exists $INC{$file};
1307             #return eval { $module->can( 'can' ) };
1308             #return UNIVERSAL::can($module,'can');
1309             }
1310             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1311             =head2 cli_mode()
1312            
1313             if ($app->cli_mode) {
1314             say "Running from the command line";
1315             }
1316             else {
1317             say "Running from web server";
1318             }
1319              
1320             Returns true if running from the command line interface, false if called from web server.
1321              
1322             =cut
1323              
1324             sub cli_mode {
1325             my ($self) = @_;
1326            
1327             if (exists $ENV{REQUEST_METHOD} || defined $ENV{GATEWAY_INTERFACE} || exists $ENV{HTTP_HOST}){
1328             return 0;
1329             }
1330            
1331             # PSGI
1332             if (exists $self->env->{REQUEST_METHOD} || defined $self->env->{GATEWAY_INTERFACE} || exists $self->env->{HTTP_HOST}){
1333             return 0;
1334             }
1335            
1336             # CLI
1337             return 1;
1338              
1339             #if (-t STDIN) { }
1340             #use IO::Interactive qw(is_interactive interactive busy);if ( is_interactive() ) {print "Running interactively\n";}
1341             }
1342             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1343             =head2 error()
1344            
1345             $app->error("error message");
1346              
1347             Fatal errors with custom error message. This is the same as C<croak> in L<CGI::Carp|CGI::Carp/croak>.
1348              
1349             =cut
1350              
1351             sub error {
1352             my $self = shift;
1353             goto &CGI::Carp::croak;
1354             }
1355              
1356             =head2 errors()
1357            
1358             $app->errors("error message");
1359              
1360             Fatal errors with custom error message and full starcktrace. This is the same as C<confess> in L<CGI::Carp|CGI::Carp/confess>.
1361              
1362             =cut
1363              
1364             sub errors {
1365             my $self = shift;
1366             goto &CGI::Carp::confess;
1367             }
1368              
1369             =head2 warn()
1370            
1371             $app->warn("warning message");
1372              
1373             Display warning message. This is the same as C<carp> in L<CGI::Carp|CGI::Carp/carp>.
1374              
1375             To view warnings in the browser, switch to the view source mode since warnings appear as
1376             a comment at the top of the page.
1377              
1378             =cut
1379              
1380             sub warn {
1381             my $self = shift;
1382             # warnings appear commented at the top of the page, use view source
1383             warningsToBrowser(1) unless ($self->cli_mode);
1384             goto &CGI::Carp::carp;
1385             }
1386              
1387             =head2 warns()
1388            
1389             $app->warns("warning message");
1390              
1391             Display warning message and full starcktrace. This is the same as C<cluck> in L<CGI::Carp|CGI::Carp/cluck>.
1392              
1393             To view warnings in the browser, switch to the view source mode since warnings appear as
1394             a comment at the top of the page.
1395              
1396             =cut
1397              
1398             sub warns {
1399             my $self = shift;
1400             # warnings appear commented at the top of the page, use view source
1401             warningsToBrowser(1) unless ($self->cli_mode);
1402             goto &CGI::Carp::cluck;
1403             }
1404             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1405             =head2 abort()
1406            
1407             $app->abort("error message");
1408              
1409             $app->abort("error title", "error message");
1410              
1411             Stop and quit the application and display message to the user. See L<Nile::Abort> module.
1412              
1413             =cut
1414              
1415             sub abort {
1416             my ($self) = shift;
1417             load Nile::Abort;
1418             Nile::Abort->abort(@_);
1419             }
1420             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1421             #__PACKAGE__->meta->make_immutable;#(inline_constructor => 0)
1422             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1423              
1424             =head1 Sub Modules
1425              
1426             App L<Nile::App>.
1427              
1428             Views L<Nile::View>.
1429              
1430             Shared Vars L<Nile::Var>.
1431              
1432             Langauge L<Nile::Lang>.
1433              
1434             Request L<Nile::HTTP::Request>.
1435              
1436             PSGI Request L<Nile::HTTP::Request::PSGI>.
1437              
1438             PSGI Request Base L<Nile::HTTP::PSGI>.
1439              
1440             Response L<Nile::HTTP::Response>.
1441              
1442             PSGI Handler L<Nile::Handler::PSGI>.
1443              
1444             FCGI Handler L<Nile::Handler::FCGI>.
1445              
1446             CGI Handler L<Nile::Handler::CGI>.
1447              
1448             Dispatcher L<Nile::Dispatcher>.
1449              
1450             Router L<Nile::Router>.
1451              
1452             File Utils L<Nile::File>.
1453              
1454             Database L<Nile::Database>.
1455              
1456             XML L<Nile::XML>.
1457              
1458             Settings L<Nile::Setting>.
1459              
1460             Serializer L<Nile::Serializer>.
1461              
1462             Deserializer L<Nile::Deserializer>.
1463              
1464             Serialization Base L<Nile::Serialization>.
1465              
1466             Filter L<Nile::Filter>.
1467              
1468             MIME L<Nile::MIME>.
1469              
1470             Timer L<Nile::Timer>.
1471              
1472             Plugin L<Nile::Plugin>.
1473              
1474             Session L<Nile::Plugin::Session>.
1475              
1476             Cache L<Nile::Plugin::Cache>.
1477              
1478             Cache Redis L<Nile::Plugin::Cache::Redis>.
1479              
1480             Email L<Nile::Plugin::Email>.
1481              
1482             Paginatation L<Nile::Plugin::Paginate>.
1483              
1484             Module L<Nile::Module>.
1485              
1486             Hook L<Nile::Hook>.
1487              
1488             Base L<Nile::Base>.
1489              
1490             Abort L<Nile::Abort>.
1491              
1492             =head1 Bugs
1493              
1494             This project is available on github at L<https://github.com/mewsoft/Nile>.
1495              
1496             =head1 HOMEPAGE
1497              
1498             Please visit the project's homepage at L<https://metacpan.org/release/Nile>.
1499              
1500             =head1 SOURCE
1501              
1502             Source repository is at L<https://github.com/mewsoft/Nile>.
1503              
1504             =head1 AUTHOR
1505              
1506             Ahmed Amin Elsheshtawy, احمد امين الششتاوى <mewsoft@cpan.org>
1507             Website: http://www.mewsoft.com
1508              
1509             =head1 COPYRIGHT AND LICENSE
1510              
1511             Copyright (C) 2014-2015 by Dr. Ahmed Amin Elsheshtawy mewsoft@cpan.org, support@mewsoft.com,
1512             L<https://github.com/mewsoft/Nile>, L<http://www.mewsoft.com>
1513              
1514             This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
1515              
1516             =cut
1517              
1518              
1519             1;