File Coverage

blib/lib/Nile/App.pm
Criterion Covered Total %
statement 102 278 36.6
branch 0 64 0.0
condition 0 23 0.0
subroutine 34 71 47.8
pod 4 36 11.1
total 140 472 29.6


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::App;
9              
10             our $VERSION = '0.55';
11             our $AUTHORITY = 'cpan:MEWSOFT';
12              
13             =pod
14              
15             =encoding utf8
16              
17             =head1 NAME
18              
19             Nile::App - App base class for the Nile framework.
20              
21             =head1 SYNOPSIS
22              
23             =head1 DESCRIPTION
24              
25             Nile::App - App base class for the Nile framework.
26              
27             =cut
28              
29 1     1   539 use Module::Load;
  1         815  
  1         5  
30 1     1   36 use Data::Dumper;
  1         1  
  1         43  
31             $Data::Dumper::Deparse = 1; #stringify coderefs
32 1     1   423 use HTTP::AcceptLanguage;
  1         1707  
  1         25  
33 1     1   5 use utf8;
  1         1  
  1         9  
34 1     1   18 use File::Spec;
  1         2  
  1         16  
35 1     1   4 use File::Basename;
  1         2  
  1         56  
36 1     1   5 use Cwd;
  1         1  
  1         40  
37 1     1   4 use URI;
  1         1  
  1         15  
38 1     1   4 use Encode ();
  1         1  
  1         14  
39 1     1   3 use URI::Escape;
  1         2  
  1         45  
40 1     1   4 use Crypt::RC4;
  1         1  
  1         31  
41             #use Crypt::CBC;
42 1     1   4 use Capture::Tiny ();
  1         19  
  1         13  
43 1     1   5 use Time::Local;
  1         1  
  1         37  
44 1     1   4 use File::Slurp;
  1         2  
  1         41  
45 1     1   3 use Time::HiRes qw(gettimeofday tv_interval);
  1         1  
  1         5  
46 1     1   114 use MIME::Base64 3.11 qw(encode_base64 decode_base64 decode_base64url encode_base64url);
  1         19  
  1         42  
47 1     1   916 use DateTime ();
  1         84635  
  1         43  
48              
49 1     1   482 use Nile::Plugin;
  1         36  
  1         4  
50 1     1   466 use Nile::Plugin::Object;
  1         2  
  1         32  
51 1     1   417 use Nile::Module;
  1         3  
  1         5  
52 1     1   611 use Nile::View;
  1         3  
  1         53  
53 1     1   638 use Nile::XML;
  1         4  
  1         53  
54 1     1   516 use Nile::Var;
  1         3  
  1         58  
55 1     1   552 use Nile::File;
  1         3  
  1         45  
56 1     1   438 use Nile::Lang;
  1         4  
  1         66  
57 1     1   635 use Nile::Config;
  1         4  
  1         66  
58 1     1   703 use Nile::Router;
  1         3  
  1         42  
59 1     1   528 use Nile::Dispatcher;
  1         3  
  1         37  
60 1     1   576 use Nile::DBI;
  1         2  
  1         12  
61 1     1   420 use Nile::Timer;
  1         3  
  1         12  
62 1     1   634 use Nile::HTTP::Request;
  1         3  
  1         7  
63 1     1   491 use Nile::HTTP::Response;
  1         4  
  1         14  
64              
65 1     1   40 use Nile::Base;
  1         2  
  1         8  
66             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
67             # Application 'Nile' object instance
68             has 'app' => (
69             is => 'rw',
70             default => undef
71             );
72             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
73             sub BUILD {
74 0     0 0   my ($self, $arg) = @_;
75 0           $self->app($arg->{app});
76             # start the app page load timer
77 0           $self->run_time->start();
78             }
79             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
80             =head2 object()
81            
82             $obj = $app->object("Nile::MyClass", @args);
83             $obj = $app->object("Nile::Plugin::MyClass", @args);
84             $obj = $app->object("Nile::Module::MyClass", @args);
85              
86             #...
87              
88             $app = $obj->app;
89             $request = $app->request;
90             $response = $app->response;
91            
92             Creates and returns an object. This automatically adds the method L<app> to the object
93             and sets it to the current context so your object or class can access the current instance.
94              
95             =cut
96              
97             sub object {
98              
99 0     0 0   my ($self, $class, @args) = @_;
100 0           my ($object);
101            
102             #if (@args == 1 && ref($args[0]) eq "HASH") {
103             # # Moose single arguments must be hash ref
104             # $object = $class->new(@args);
105             #}
106              
107 0 0 0       if (@args && @args % 2) {
108             # Moose needs args as hash, so convert odd size arrays to even for hashing
109 0           $object = $class->new(@args, undef);
110             }
111             else {
112 0           $object = $class->new(@args);
113             }
114              
115             #$meta->add_method( 'hello' => sub { return "Hello inside hello method. @_" } );
116             #$meta->add_class_attribute( $_, %options ) for @{$attrs}; #MooseX::ClassAttribute
117             #$meta->add_class_attribute( 'cash', ());
118              
119             # add attribute "app" to the object
120 0           $self->add_object_context($object);
121            
122             # if class has defined "main" method, then call it
123 0 0         if ($object->can("main")) {
124 0           my %ret = $object->main(@args);
125 0 0         if ($ret{rebless}) {
126 0           $object = $ret{rebless};
127             }
128             }
129            
130 0           return $object;
131             }
132             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
133             sub add_object_context {
134 0     0 0   my ($self, $object) = @_;
135 0           my $meta = $object->meta;
136             # add method "app" or one of its alt
137 0 0         if (!$object->can("app")) {
138 0     0     $meta->add_attribute(app => (is => 'rw', default => sub{$self}));
  0            
139             }
140 0           $object->app($self);
141             }
142             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
143             =head2 start()
144            
145             $app->start;
146              
147             Set the application startup variables.
148              
149             =cut
150              
151             sub start {
152              
153 0     0 0   my ($self) = @_;
154             #------------------------------------------------------
155 0           my $app = $self->app;
156 0           my $file = $self->file;
157            
158             # shared vars
159 0           my %arg = $app->var->vars();
160              
161 0           $self->var->set(%arg);
162              
163             #$self->dump({$app->var->vars()});
164             #$self->dump({$self->var->vars()});
165              
166 0           my $path = $self->var->get("path");
167              
168 0   0       $arg{lang} ||= "";
169 0   0       $arg{theme} ||= "default";
170              
171             # detect user language
172 0           $arg{lang} = $self->detect_user_language($arg{lang});
173            
174 0           foreach (qw(api cache cmd config cron data file lib log route temp web)) {
175 0           $self->var->set($_."_dir" => $file->catdir($path, $_));
176             }
177              
178             $self->var->set(
179 0           'lang' => $arg{lang},
180             'theme' => $arg{theme},
181             'lang_dir' => $file->catdir($path, "lang", $arg{lang}),
182             'theme_dir' => $file->catdir($path, "theme", $arg{theme}),
183             );
184            
185             # load language files
186 0           foreach ($self->config->get("app/lang_file")) {
187 0           $self->lang->load($_);
188             }
189             #------------------------------------------------------
190             #$self->hook->on_start;
191              
192 0           my $req = $self->request;
193              
194             # global variables, safe to render in views
195 0           $self->var->set(
196             url => $req->url,
197             base_url => $req->base_url,
198             abs_url => $req->abs_url,
199             url_path => $req->url_path,
200             );
201              
202             #$self->uri_mode(1);
203             # app folders url's
204 0           foreach (qw(api cache file temp web)) {
205 0           $self->var->set($_."_url" => $self->uri_for("$_/"));
206             }
207            
208             # themes and current theme url's
209             $self->var->set(
210 0           themes_url => $self->uri_for("theme/"),
211             theme_url => $self->uri_for("theme/$arg{theme}/"),
212             );
213            
214             # theme folders
215 0           foreach (qw(css icon image js view widget)) {
216 0           $self->var->set($_."_url" => $self->uri_for("theme/$arg{theme}/$_/"));
217 0           $self->var->set($_."_dir" => $file->catdir($self->var->get("theme_dir"), $_));
218             }
219             #------------------------------------------------------
220             # load plugins set to autoload in the config files
221 0           while (my ($name, $plugin) = each %{$self->config->get("plugin")} ) {
  0            
222 0 0         next if (!$plugin->{autoload});
223 0           $name = ucfirst($name);
224 0           my $class = "Nile::Plugin::$name";
225 0 0         if (!$self->is_loaded($class)) {
226 0           load $class;
227 0           $self->plugin->$name;
228             }
229             }
230             #------------------------------------------------------
231             # connect to database
232 0 0         if ($self->config->get("db_connect")) {
233 0           $self->connect;
234             }
235             #------------------------------------------------------
236             #$self->hook->off_start;
237             }
238             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
239             =head2 mode()
240            
241             my $mode = $app->mode;
242              
243             Returns the current application mode PSGI, FCGI or CGI.
244              
245             =cut
246              
247             has 'mode' => (
248             is => 'rw',
249             isa => 'Str',
250             lazy => 1,
251             default => sub {shift->app->mode(@_)},
252             );
253             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
254             =head2 config()
255            
256             See L<Nile::Config>.
257              
258             =cut
259              
260             has 'config' => (
261             is => 'rw',
262             lazy => 1,
263             default => sub {
264             shift->app->config(@_);
265             }
266             );
267             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
268             =head2 router()
269            
270             See L<Nile::Router>.
271              
272             =cut
273              
274             has 'router' => (
275             is => 'rw',
276             lazy => 1,
277             default => sub {
278             shift->app->router(@_);
279             }
280             );
281             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
282             =head2 lang()
283            
284             See L<Nile::Lang>.
285              
286             =cut
287              
288             has 'lang' => (
289             is => 'rw',
290             lazy => 1,
291             default => sub {
292             #shift->app->lang(@_);
293             shift->object("Nile::Lang", @_);
294             }
295             );
296             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
297             =head2 uri_mode()
298            
299             # uri mode: 0=full, 1=absolute, 2=relative
300             $app->uri_mode(1);
301              
302             Set the uri mode. The values allowed are: 0= full, 1=absolute, 2=relative
303              
304             =cut
305              
306             has 'uri_mode' => (
307             is => 'rw',
308             default => 0, # 0= full, 1=absolute, 2=relative
309             );
310              
311             =head2 uri_for()
312            
313             $url = $app->uri_for("/users", [$mode]);
314              
315             Returns the uri for specific action or route. The mode parameter is optional. The mode values allowed are: 0= full, 1=absolute, 2=relative.
316              
317             =cut
318              
319             sub uri_for {
320 0     0 1   my ($self, $uri, $mode) = @_;
321            
322 0 0         if (!defined $mode) {
323 0           $mode = $self->uri_mode;
324             }
325              
326 0 0         if ($self->uri_mode == 1) {
327 0           return $self->var->get("abs_url") . $uri;
328             }
329             else {
330 0           return $self->var->get("base_url") . $uri;
331             }
332             }
333             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
334             sub forward {
335 0     0 0   my ($self, $uri) = @_;
336            
337             #$me->forward($uri);
338              
339             }
340             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
341             =head2 debug()
342            
343             # 1=enabled, 0=disabled
344             $app->debug(1);
345              
346             Enable or disable debugging flag.
347              
348             =cut
349              
350             has 'debug' => (
351             is => 'rw',
352             isa => 'Bool',
353             default => 0,
354             );
355             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
356             =head2 bm()
357            
358             $app->bm->lap("start task");
359             ....
360             $app->bm->lap("end task");
361            
362             say $app->bm->stop->summary;
363              
364             # NAME TIME CUMULATIVE PERCENTAGE
365             # start task 0.123 0.123 34.462%
366             # end task 0.234 0.357 65.530%
367             # _stop_ 0.000 0.357 0.008%
368            
369             say "Total time: " . $app->bm->total_time;
370              
371             Benchmark specific parts of your code. This is a L<Benchmark::Stopwatch> object.
372              
373             =cut
374              
375             has 'bm' => (
376             is => 'rw',
377             lazy => 1,
378             default => sub{
379             #autoload, load CGI, ':all';
380             load Benchmark::Stopwatch;
381             Benchmark::Stopwatch->new->start;
382             }
383             );
384             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
385             =head2 file()
386            
387             See L<Nile::File>.
388              
389             =cut
390              
391             has 'file' => (
392             is => 'rw',
393             lazy => 1,
394             default => sub {
395             shift->object("Nile::File", @_);
396             }
397             );
398             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
399             =head2 xml()
400            
401             See L<Nile::XML>.
402              
403             =cut
404              
405             has 'xml' => (
406             is => 'rw',
407             lazy => 1,
408             default => sub {
409             shift->object("Nile::XML", @_);
410             }
411             );
412             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
413             =head2 setting()
414            
415             See L<Nile::Setting>.
416              
417             =cut
418              
419             has 'setting' => (
420             is => 'rw',
421             lazy => 1,
422             default => sub {
423             load Nile::Setting;
424             shift->object("Nile::Setting", @_);
425             }
426             );
427             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
428             =head2 mime()
429            
430             See L<Nile::MIME>.
431              
432             =cut
433              
434             has 'mime' => (
435             is => 'rw',
436             lazy => 1,
437             default => sub {
438             load Nile::MIME;
439             shift->object("Nile::MIME", only_complete => 1);
440             }
441             );
442             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
443             =head2 dispatcher()
444            
445             See L<Nile::Dispatcher>.
446              
447             =cut
448              
449             has 'dispatcher' => (
450             is => 'rw',
451             lazy => 1,
452             default => sub {
453             shift->object("Nile::Dispatcher", @_);
454             }
455             );
456             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
457             =head2 logger()
458            
459             Returns L<Log::Tiny> object.
460              
461             =cut
462              
463             has 'logger' => (
464             is => 'rw',
465             lazy => 1,
466             default => sub {
467             my $self = shift;
468             load Log::Tiny;
469             Log::Tiny->new($self->file->catfile($self->var->get("log_dir"), $self->var->get("log_file") || 'log.pm'));
470             }
471             );
472             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
473             =head2 log()
474              
475             $app->log->info("application run start");
476             $app->log->DEBUG("application run start");
477             $app->log->ERROR("application run start");
478             $app->log->INFO("application run start");
479             $app->log->ANYTHING("application run start");
480              
481             Log object L<Log::Tiny> supports unlimited log categories.
482              
483             =cut
484              
485             sub log {
486 0     0 0   my $self = shift;
487 0 0         $self->start_logger if (!$self->logger);
488 0           $self->logger(@_);
489             }
490              
491             =head2 start_logger()
492            
493             $app->start_logger();
494              
495             Start the log object and open the log file for writing logs.
496              
497             =cut
498              
499             sub start_logger {
500 0     0 1   my $self = shift;
501 0           $self->stop_logger;
502 0   0       $self->logger(Log::Tiny->new($self->file->catfile($self->var->get("log_dir"), $self->var->get("log_file") || 'log.pm')));
503             }
504              
505             =head2 stop_logger()
506            
507             $app->stop_logger();
508              
509             Stops the log object and close the log file.
510              
511             =cut
512              
513             sub stop_logger {
514 0     0 1   my $self = shift;
515             # close log file
516 0           $self->logger(undef);
517             }
518             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
519             =head2 timer()
520            
521             # start the timer
522             $app->timer->start;
523            
524             # do some operations...
525            
526             # get time elapsed since start called
527             say $app->timer->lap;
528              
529             # do some other operations...
530              
531             # get time elapsed since last lap called
532             say $app->timer->lap;
533              
534             # get another timer object, timer automatically starts
535             my $timer = $app->timer->new;
536             say $timer->lap;
537             #...
538             say $timer->lap;
539             #...
540             say $timer->total;
541              
542             Returns L<Nile::Timer> object. See L<Nile::Timer> for more details.
543              
544             =cut
545              
546             has 'timer' => (
547             is => 'rw',
548             #lazy => 1,
549             default => sub{
550             Nile::Timer->new;
551             }
552             );
553             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
554             # page load timer, run time
555              
556             =head2 run_time()
557            
558             # get time elapsed since app started
559             say $app->run_time->lap;
560              
561             # do some other operations...
562              
563             # get time elapsed since last lap called
564             say $app->run_time->lap;
565              
566             Returns L<Nile::Timer> object. Timer automatically starts with the application.
567              
568             =cut
569              
570             has 'run_time' => (
571             is => 'rw',
572             #lazy => 1,
573             default => sub{
574             Nile::Timer->new;
575             }
576             );
577             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
578             =head2 var()
579            
580             See L<Nile::Var>.
581              
582             =cut
583              
584             has 'var' => (
585             is => 'rw',
586             lazy => 1,
587             default => sub {
588             shift->object("Nile::Var", @_);
589             }
590             );
591             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
592             =head2 env()
593            
594             $request_uri = $app->env->{REQUEST_URI};
595              
596             Application env object for CGI and Plack/PSGI.
597              
598             =cut
599              
600             has 'env' => (
601             is => 'rw',
602             isa => 'HashRef',
603             default => sub { \%ENV }
604             );
605             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
606             =head2 browser()
607            
608             $browser = $app->browser;
609             say $browser->version;
610             say $browser->browser_string;
611             say $browser->os_string;
612             if ($browser->mobile) { say "Mobile device"; }
613              
614             Determine Web browser, version, and platform. Returns L<HTTP::BrowserDetect> object.
615              
616             =cut
617              
618             has 'browsers' => (
619             is => 'rw',
620             lazy => 1,
621             default => sub {
622             load HTTP::BrowserDetect;
623             HTTP::BrowserDetect->new(shift->env->{HTTP_USER_AGENT})
624             }
625             );
626             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
627             =head2 request()
628            
629             See L<Nile::Request>.
630              
631             =cut
632              
633             has 'request' => (
634             is => 'rw',
635             lazy => 1,
636             default => sub {},
637             );
638             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
639             =head2 response()
640            
641             See L<Nile::Response>.
642              
643             =cut
644              
645             has 'response' => (
646             is => 'rw',
647             isa => 'Nile::HTTP::Response',
648             lazy => 1,
649             default => sub {
650             shift->object("Nile::HTTP::Response", @_);
651             }
652             );
653             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
654             =head2 plugin()
655            
656             See L<Nile::Plugin>.
657              
658             =cut
659              
660             has 'plugin_object' => (
661             is => 'rw',
662             lazy => 1,
663             default => sub {
664             shift->object("Nile::Plugin::Object", @_);
665             }
666             );
667              
668             has 'plugin_loaded' => (
669             is => 'rw',
670             lazy => 1,
671             isa => 'HashRef',
672             default => sub { +{} }
673             );
674              
675             sub plugin {
676              
677 0     0 0   my ($self, $plugin) = @_;
678              
679 0 0         if (!$plugin) {
680 0           return $self->plugin_object;
681             }
682              
683 0 0         if ($plugin !~ /::/) {
684 0           return $self->plugin_object->$plugin;
685             }
686              
687 0           my $name = "Nile::Plugin::" . ucfirst($plugin);
688              
689            
690 0 0         return $self->plugin_loaded->{$plugin} if ($self->plugin_loaded->{$plugin});
691              
692 0           eval "use $name";
693            
694 0 0         if ($@) {
695 0           $self->abort("Plugin Error: $name. $@");
696             }
697              
698 0           $self->plugin_loaded->{$plugin}= $self->object($name, @_);
699              
700 0           return $self->plugin_loaded->{$plugin};
701             }
702              
703             sub plugins {
704 0     0 0   my ($self, $plugin) = @_;
705 0 0         if ($plugin !~ /::/) {
706 0           return $self->plugin->$plugin;
707             }
708              
709 0           my $name = "Nile::Plugin::" . ucfirst($plugin);
710              
711            
712 0 0         return $self->plugin_loaded->{$plugin} if ($self->plugin_loaded->{$plugin});
713              
714 0           eval "use $name";
715            
716 0 0         if ($@) {
717 0           $self->abort("Plugins Error: $name. $@");
718             }
719              
720 0           $self->plugin_loaded->{$plugin}= $self->object($name, @_);
721              
722 0           return $self->plugin_loaded->{$plugin};
723              
724             #$self->object("Nile::Plugin::Object", $plugin);
725             }
726             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
727             =head2 helper()
728            
729             # add helper method to the framework
730            
731             $app->helper($method => $coderef);
732            
733             # add method "echo"
734             $app->helper("echo" => sub{shift; say @_;});
735              
736             # access the helper method normal from plugins and modules
737             $app->echo("Helper echo example.");
738              
739             =cut
740              
741             sub helper {
742 0     0 0   my ($self, %arg) = @_;
743 0           while (my($name, $code) = each %arg) {
744 0 0         if (ref($code) ne "CODE") {
745 0           $self->abort("Helper setup error: helper '$name' code should be a code ref. $code");
746             }
747              
748 0 0         if (!$self->can($name)) {
749 0           $self->meta->add_method($name => $code);
750             }
751             else {
752 0           $self->abort("Helper setup error: helper '$name' method already exists. $code");
753             }
754              
755             }
756             }
757             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
758             =head2 attr()
759            
760             # add attr to the framework
761            
762             $app->attr($name => $default);
763            
764             # add attribute "PI"
765             $app->attr("PI" => 4 * atan2(1, 1));
766            
767             # or
768             $app->attr("PI" => sub{4 * atan2(1, 1)});
769              
770             # get the attribute value
771             say $app->PI;
772              
773             # set the the attribute value to new value
774             $app->PI(3.14159265358979);
775              
776             =cut
777              
778             sub attr {
779 0     0 0   my ($self, %arg) = @_;
780 0           while (my($name, $code) = each %arg) {
781 0 0         if (!$self->can($name)) {
782 0           $self->meta->add_attribute($name => (is => 'rw', lazy=>1, default => $code));
783             }
784             else {
785 0           $self->abort("Attr setup error: attr '$name' already exists. $code");
786             }
787             }
788             }
789             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
790             =head2 ua()
791            
792             my $response = $app->ua->get('http://example.com/');
793             say $response->{content} if length $response->{content};
794            
795             $response = $app->ua->get($url, \%options);
796             $response = $app->ua->head($url);
797            
798             $response = $app->ua->post_form($url, $form_data);
799             $response = $app->ua->post_form($url, $form_data, \%options);
800              
801             Simple HTTP client. This is a L<HTTP::Tiny> object.
802              
803             =cut
804              
805             has 'ua' => (
806             is => 'rw',
807             isa => 'HTTP::Tiny',
808             lazy => 1,
809             #trigger => sub {shift->clearer},
810             default => sub {
811             load HTTP::Tiny;
812             HTTP::Tiny->new;
813             }
814             );
815             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
816             =head2 uri()
817            
818             my $uri = $app->uri('http://mewsoft.com/');
819              
820             Returns L<URI> object.
821              
822             =cut
823              
824             has 'uri' => (
825             is => 'rw',
826             lazy => 1,
827             default => sub {
828             load URI;
829             URI->new;
830             }
831             );
832             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
833             =head2 charset()
834            
835             $app->charset('utf8');
836             $charset = $app->charset;
837              
838             Set or return the charset for encoding and decoding. Default is C<utf8>.
839              
840             =cut
841              
842             has 'charset' => (
843             is => 'rw',
844             lazy => 1,
845             default => sub {shift->var->get("charset")}
846             );
847             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
848             =head2 freeze()
849            
850             See L<Nile::Serializer>.
851              
852             =cut
853              
854             has 'freeze' => (
855             is => 'rw',
856             isa => 'Nile::Serializer',
857             lazy => 1,
858             default => sub {
859             load Nile::Serializer;
860             Nile::Serializer->new;
861             }
862             );
863 0     0 0   sub serialize {shift->freeze(@_);}
864             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
865             =head2 thaw()
866            
867             See L<Nile::Deserializer>.
868              
869             =cut
870              
871             has 'thaw' => (
872             is => 'rw',
873             isa => 'Nile::Deserializer',
874             lazy => 1,
875             default => sub {
876             load Nile::Deserializer;
877             Nile::Deserializer->new;
878             }
879             );
880 0     0 0   sub deserialize {shift->thaw(@_);}
881             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
882             =head2 module()
883            
884             # load module Nile::Module::Home::Contact and create a new object
885             $contact = $me->module("Home::Contact");
886              
887             # to get another new instance
888             $contact1 = $me->module("Home::MyModule")->new();
889             # or
890             $contact2 = $contact->new();
891              
892             # if you are calling from inside the Home module, you can just use
893             $contact = $me->module("Contact");
894              
895             # of course you can load sub classes
896             $send = $me->module("Home::Contact::Send");
897              
898             # if you are calling from inside the Home module, you can just use
899             $send = $me->module("Contact::Send");
900              
901             # all the above is the same as
902             use Nile::Module::Home::Contact;
903             $contact = Nile::Module::Home::Contact->new();
904             $contact->main() if ($contact->can("main"));
905              
906             Load modules classes.
907              
908             =cut
909              
910             sub module {
911            
912 0     0 0   my ($self, $module) = @_;
913            
914 0           my ($package, $script) = caller;
915 0           my ($class, $method) = $package =~ /^(.*)::(\w+)$/;
916            
917 0           $module = ucfirst($module);
918 0           my $name;
919              
920 0 0         if ($module =~ /::/) {
921             # module("Home::Contact") called from any module
922 0           $name = "Nile::Module::" . $module;
923             }
924             else {
925             # module("Contact") called from Home module
926 0           $name = $class . "::" . $module;
927             }
928              
929 0 0         return $self->{module}->{$name} if ($self->{module}->{$name});
930              
931 0           eval "use $name";
932            
933 0 0         if ($@) {
934 0           $self->abort("Module Load Error: $name . $@");
935             }
936              
937 0           $self->{module}->{$name} = $self->object($name, @_);
938              
939 0           return $self->{module}->{$name};
940             }
941             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
942             =head2 hook()
943            
944             See L<Nile::Hook>.
945              
946             =cut
947              
948             has 'hook' => (
949             is => 'rw',
950             lazy => 1,
951             default => sub {
952             load Nile::Hook;
953             shift->object("Nile::Hook", @_);
954             }
955             );
956             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
957             =head2 filter()
958            
959             See L<Nile::Filter>.
960              
961             =cut
962              
963             has 'filter' => (
964             is => 'rw',
965             isa => 'Nile::Filter',
966             lazy => 1,
967             default => sub {
968             load Nile::Filter;
969             shift->object("Nile::Filter", @_);
970             }
971             );
972             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
973             =head2 session()
974            
975             See session plugin L<Nile::Plugin::Session>.
976              
977             =cut
978              
979             has 'session' => (
980             is => 'rw',
981             lazy => 1,
982             isa => 'HashRef',
983             default => sub { +{} }
984             );
985             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
986             =head2 date()
987              
988             # get date object with time set to from epoch time
989             my $dt = $app->date(time());
990            
991             # the same
992             my $dt = $app->date(epoch => time());
993            
994             # object with time component
995             my $dt = $app->date(
996             year => 2014,
997             month => 9,
998             day => 3,
999             hour => 22,
1000             minute => 12,
1001             second => 24,
1002             nanosecond => 500000000,
1003             time_zone => 'Africa/Cairo',
1004             );
1005            
1006             # get date object with time set to now
1007             my $dt = $app->date;
1008              
1009             # then all methods of DateTime module is available
1010             $dt->set_time_zone('America/Chicago');
1011             $dt->strftime("%a, %d %b %Y %H:%M:%S");
1012             $ymd = $dt->ymd('/');
1013              
1014             Date and time object wrapper around L<DateTime> module.
1015              
1016             =cut
1017              
1018             sub date {
1019 0     0 0   my ($self) = shift;
1020 0 0         if (scalar @_ == 1) {
    0          
1021 0           return DateTime->from_epoch(epoch => shift);
1022             }
1023             elsif (scalar @_ > 1) {
1024 0           my %arg = @_;
1025 0 0         if (exists $arg{epoch}) {
1026 0           return DateTime->from_epoch(epoch => $arg{epoch});
1027             }
1028 0           return DateTime->new(%arg);
1029            
1030             }
1031             else {
1032 0           return DateTime->now;
1033             }
1034             }
1035             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1036             has 'dbh' => (
1037             is => 'rw',
1038             );
1039              
1040             has 'db' => (
1041             is => 'rw',
1042             );
1043              
1044             sub connect {
1045 0     0 0   my $self = shift;
1046 0           $self->db($self->object("Nile::DBI"));
1047 0           $self->dbh($self->db->connect(@_));
1048 0           $self->db;
1049             }
1050             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1051             sub new_request {
1052            
1053 0     0 0   my ($self, $env) = @_;
1054              
1055 0 0 0       if (defined($env) && ref ($env) eq "HASH") {
1056 0           $self->mode("psgi");
1057             #load Nile::HTTP::PSGI;
1058 0           $self->request($self->object("Nile::HTTP::Request::PSGI", $env));
1059             }
1060             else {
1061 0           $self->request($self->object("Nile::HTTP::Request"));
1062             }
1063            
1064 0           $self->request();
1065             }
1066             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1067             =head2 detect_user_language()
1068            
1069             $user_lang = $app->detect_user_language;
1070              
1071             Detects and retuns the user langauge.
1072              
1073             =cut
1074              
1075             sub detect_user_language {
1076 0     0 0   my ($self, $default) = @_;
1077              
1078 0 0         if ($self->request->param($self->config->get("app/lang_param_key"))) {
1079 0           return $self->request->param($self->config->get("app/lang_param_key"));
1080             }
1081            
1082 0 0         if ($self->session->{$self->config->get("app/lang_session_key")}) {
1083 0           return $self->session->{$self->config->get("app/lang_session_key")};
1084             }
1085              
1086 0 0         if ($self->request->cookie($self->config->get("app/lang_cookie_key"))) {
1087 0           return $self->request->cookie($self->config->get("app/lang_cookie_key"));
1088             }
1089              
1090             # detect user browser language settings
1091 0           my @langs = $self->lang_list();
1092 0           my $lang = HTTP::AcceptLanguage->new($ENV{HTTP_ACCEPT_LANGUAGE})->match(@langs);
1093              
1094 0   0       $lang ||= $default ||= $langs[0] ||= "en-US";
      0        
      0        
1095              
1096 0           return $lang;
1097             }
1098             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1099             =head2 view()
1100            
1101             Returns L<Nile::View> object.
1102              
1103             =cut
1104              
1105             sub view {
1106 0     0 0   my ($self) = shift;
1107 0           return $self->object("Nile::View", @_);
1108             }
1109             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1110             =head2 dbi()
1111            
1112             Returns L<Nile::DBI> object.
1113              
1114             =cut
1115              
1116             sub dbi {
1117 0     0 0   my ($self) = shift;
1118 0           return $self->object("Nile::DBI", @_);
1119             }
1120             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1121             =head2 theme_list()
1122            
1123             @themes = $app->theme_list;
1124              
1125             Returns themes names installed.
1126              
1127             =cut
1128              
1129             sub theme_list {
1130 0     0 0   my ($self) = @_;
1131 0           my @folders = ($self->file->folders($self->var->get("themes_dir"), "", 1));
1132 0           return grep (/^[^_]/, @folders);
1133             }
1134             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1135             =head2 lang_list()
1136            
1137             @langs = $app->lang_list;
1138              
1139             Returns languages names installed.
1140              
1141             =cut
1142              
1143             sub lang_list {
1144 0     0 0   my ($self) = @_;
1145 0           my @folders = ($self->file->folders($self->var->get("langs_dir"), "", 1));
1146 0           return grep (/^[^_]/, @folders);
1147             }
1148             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1149             =head2 dump()
1150            
1151             $app->dump({...});
1152              
1153             Print object to the STDOUT. Same as C<say Dumper (@_);>.
1154              
1155             =cut
1156              
1157             sub dump {
1158 0     0 1   return shift->app->dump(@_);
1159             }
1160             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1161             =head2 is_loaded()
1162            
1163             if ($app->is_loaded("Nile::SomeModule")) {
1164             #...
1165             }
1166            
1167             if ($app->is_loaded("Nile/SomeModule.pm")) {
1168             #...
1169             }
1170              
1171             Returns true if module is loaded, false otherwise.
1172              
1173             =cut
1174              
1175             sub is_loaded {
1176 0     0 0   shift->app->is_loaded(@_);
1177             }
1178             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1179             sub load_once {
1180 0     0 0   shift->app->load_once(@_);
1181             }
1182             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1183             =head2 cli_mode()
1184            
1185             if ($app->cli_mode) {
1186             say "Running from the command line";
1187             }
1188             else {
1189             say "Running from web server";
1190             }
1191              
1192             Returns true if running from the command line interface, false if called from web server.
1193              
1194             =cut
1195              
1196             sub cli_mode {
1197 0     0 0   shift->app->cli_mode(@_);
1198             }
1199             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1200             =head2 utf8_safe()
1201            
1202             $str_utf8 = $app->utf8_safe($str);
1203              
1204             Encode data in C<utf8> safely.
1205              
1206             =cut
1207              
1208             sub utf8_safe {
1209 0     0 0   my ($self, $str) = @_;
1210 0 0         if (utf8::is_utf8($str)) {
1211 0           utf8::encode($str);
1212             }
1213 0           $str;
1214             }
1215             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1216             =head2 encode()
1217            
1218             $encoded = $app->encode($data);
1219              
1220             Encode data using the current L</charset>.
1221              
1222             =cut
1223              
1224             sub encode {
1225 0     0 0   my ($self, $data) = @_;
1226 0           return Encode::encode($self->charset, $data);
1227             }
1228             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1229             =head2 decode()
1230            
1231             $data = $app->decode($encoded);
1232              
1233             Decode data using the current L</charset>.
1234              
1235             =cut
1236              
1237             sub decode {
1238 0     0 0   my ($self, $data) = @_;
1239 0           return Encode::decode($self->charset, $data);
1240             }
1241             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1242             =head2 instance_isa()
1243            
1244             $app->instance_isa($object, $class);
1245              
1246             Test for an object of a particular class in a strictly correct manner.
1247              
1248             Returns the object itself or C<undef> if the value provided is not an object of that type.
1249              
1250             =cut
1251              
1252             sub instance_isa ($$) {
1253             #my ($self, $object, $class) = @_;
1254 0 0 0 0 0   (Scalar::Util::blessed($_[1]) and $_[1]->isa($_[2])) ? $_[1] : undef;
1255             }
1256             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1257             sub content_type_text {
1258 0     0 0   my ($self, $content_type) = @_;
1259 0           return $content_type =~ /(\bx(?:ht)?ml\b|text|json|javascript)/;
1260             }
1261             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1262             sub result {
1263 0     0 0   my ($self, @data) = @_;
1264 1     1   6567 use Nile::Result;
  1         2  
  1         8  
1265 0           Nile::Result->new(@data);
1266             }
1267             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1268             sub is_result {
1269 0     0 0   my ($self, $result) = @_;
1270 0           ref($result) eq "Nile::Result";
1271             }
1272             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1273             =head2 abort()
1274            
1275             $app->abort("error message");
1276              
1277             $app->abort("error title", "error message");
1278              
1279             Stop and quit the application and display message to the user. See L<Nile::Abort> module.
1280              
1281             =cut
1282              
1283             sub abort {
1284 0     0 0   shift->app->abort(@_);
1285             }
1286             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1287              
1288             #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1289              
1290             =pod
1291              
1292             =head1 Bugs
1293              
1294             This project is available on github at L<https://github.com/mewsoft/Nile>.
1295              
1296             =head1 HOMEPAGE
1297              
1298             Please visit the project's homepage at L<https://metacpan.org/release/Nile>.
1299              
1300             =head1 SOURCE
1301              
1302             Source repository is at L<https://github.com/mewsoft/Nile>.
1303              
1304             =head1 SEE ALSO
1305              
1306             See L<Nile> for details about the complete framework.
1307              
1308             =head1 AUTHOR
1309              
1310             Ahmed Amin Elsheshtawy, احمد امين الششتاوى <mewsoft@cpan.org>
1311             Website: http://www.mewsoft.com
1312              
1313             =head1 COPYRIGHT AND LICENSE
1314              
1315             Copyright (C) 2014-2015 by Dr. Ahmed Amin Elsheshtawy احمد امين الششتاوى mewsoft@cpan.org, support@mewsoft.com,
1316             L<https://github.com/mewsoft/Nile>, L<http://www.mewsoft.com>
1317              
1318             This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
1319              
1320             =cut
1321              
1322             1;