File Coverage

blib/lib/Mojolicious/Che.pm
Criterion Covered Total %
statement 12 115 10.4
branch 0 40 0.0
condition 0 54 0.0
subroutine 4 15 26.6
pod 2 9 22.2
total 18 233 7.7


line stmt bran cond sub pod time code
1             package Mojolicious::Che;
2 1     1   71992 use Mojo::Base::Che;
  1         3  
  1         40  
3 1     1   8 use Mojo::Base 'Mojolicious';
  1         2  
  1         4  
4 1     1   678 use Mojo::Log::Che;
  1         39  
  1         19  
5 1     1   47 use Mojo::Loader qw(load_class);
  1         3  
  1         3391  
6             #~ use Mojo::Util qw(url_unescape);
7             #~ use Scalar::Util 'weaken';
8              
9             sub new {
10 0     0 1   my ($class, %args) = @_;
11 0   0       my $config = delete($args{config}) || 'Config.pm';
12 0           my $app = $class->SUPER::new(%args);
13            
14 0           $app->plugin(Config =>{file => $config});
15            
16             #~ return $app # остановка или двойной перезапуск kill -USR2
17             #~ if $ENV{HYPNOTOAD_PID} || $ENV{HYPNOTOAD_STOP};
18            
19 0           my $conf = $app->config;
20 0   0       $conf->{mojo} ||= {};
21            
22 0   0       my $defaults = $conf->{'mojo_defaults'} || $conf->{'mojo'}{'defaults'} || $conf->{'mojo.defaults'};
23 0 0         $app->defaults($defaults)
24             if $defaults;
25            
26 0   0       my $secret = $conf->{'mojo_secret'} || $conf->{'mojo_secrets'} || $conf->{'mojo'}{'secret'} || $conf->{'mojo'}{'secrets'} || $conf->{'mojo.secret'} || $conf->{'mojo.secrets'} || $conf->{'шифры'} || [rand];
27 0           $app->secrets($secret);
28            
29 0   0       my $mode = $conf->{'mojo_mode'} || $conf->{'mojo'}{'mode'} || $conf->{'mojo.mode'};
30 0 0         $app->mode($mode) # Файл лога уже не переключишь
31             if $mode;
32             #~ $app->log->level( $conf->{'mojo_log_level'} || $conf->{'mojo'}{'log_level'} || 'debug');
33 0   0       my $log = $conf->{'mojo_log'} || $conf->{'mojo.log'} || $conf->{'mojo'}{'log'};
34 0 0         $app->log(Mojo::Log::Che->new(%$log))
35             if $log;
36             #~ warn "Mode: ", $app->mode, "; log level: ", $app->log->level;
37            
38 0           my $home = $app->home;
39 0   0       my $statics = $conf->{'mojo_static_paths'} || $conf->{'mojo.static.paths'} || $conf->{'mojo'}{'static'}{'paths'} || [];
40             #~ push @{$app->static->paths}, @{$paths} if $paths;
41 0           push @{$app->static->paths}, $home->rel_file($_) for @$statics;
  0            
42            
43 0   0       my $templates_paths = $conf->{'mojo_renderer_paths'} || $conf->{'mojo.renderer.paths'} || $conf->{'mojo'}{'renderer'}{'paths'} || [];
44 0           push @{$app->renderer->paths}, $home->rel_dir($_) for @$templates_paths;
  0            
45            
46 0   0       my $renderer_classes = $conf->{'mojo_renderer_classes'} || $conf->{'mojo.renderer.classes'} || $conf->{'mojo'}{'renderer'}{'classes'} || [];
47 0           push @{$app->renderer->classes}, $_ for grep ! load_class($_), @$renderer_classes;
  0            
48            
49 0           $app->сессия();
50 0           $app->хазы();
51 0           $app->плугины();
52 0           $app->хуки();
53 0           $app->спейсы();
54 0           $app->маршруты();
55 0           $app->задачи();
56 0           $app->типы();
57             #~ $app->minion_worker();
58              
59 0           return $app;
60              
61             }
62              
63             sub хазы { # Хазы из конфига
64 0     0 0   my $app = shift;
65 0           my $conf = $app->config;
66 0   0       my $h = $conf->{'mojo_has'} || $conf->{'mojo.has'} || $conf->{'mojo'}{'has'} || $conf->{'хазы'};
67             map {
68 0           $app->log->debug("Make the app->has('$_')");
  0            
69 0           has $_ => $h->{$_};
70             } keys %$h;
71             }
72              
73             #~ sub плугины {# Плугины из конфига
74             has плугины => sub {
75             my $app = shift;
76             my $conf = $app->config;
77             my $плугины = {};
78             my $plugins = $conf->{'mojo_plugins'} || $conf->{'mojo.plugins'} || $conf->{'mojo'}{'plugins'} || $conf->{'плугины'}
79             || return;
80             map {
81             push @{ $плугины->{$_->[0]} ||= [] }, [ref $_->[1] eq 'CODE' ? $app->plugin($_->[0] => $app->${ \$_->[1] }) : $app->plugin(@$_)];
82             $app->log->debug("Enable plugin [$_->[0]]");
83             } @$plugins;
84             return $плугины;
85             };
86              
87             has dbh => sub {
88             #~ sub базы {# обрабатывает dbh конфига
89             my $app = shift;
90             my $conf = $app->config;
91             my $c_dbh = $conf->{dbh} || $conf->{'базы'};
92             return unless $c_dbh && ref($c_dbh) eq 'HASH' && keys %$c_dbh;
93             #~ has dbh => sub {{};}
94             #~ unless $app->can('dbh');
95            
96             my $dbh = {};
97            
98             my $req_dbi;
99             while (my ($db, $opt) = each %$c_dbh) {
100             if ($opt->{dbh}) {# && ref $opt eq 'DBI::db'
101             $dbh->{$db} ||= $opt->{dbh};
102             } else {
103             ++$req_dbi
104             and require DBI
105             unless $req_dbi;
106             $dbh->{$db} ||= DBI->connect(@{$opt->{connect}});
107             $app->log->debug("Соединился с базой $opt->{connect}[0] app->dbh->{'$db'}");
108             }
109            
110             map {
111             $dbh->{$db}->do($_);
112             } @{$opt->{do}} if $opt->{do};
113            
114              
115             }
116             return $dbh;
117            
118             };
119              
120             has sth => sub {
121              
122             #~ sub запросы {# обрабатывает sth конфига
123             my $app = shift;
124             my $dbh = eval { $app->dbh }
125             or return;
126             #~ my %arg = @_;
127             my $conf = $app->config;
128            
129             my $c_dbh = $conf->{dbh} || $conf->{'базы'};
130             my $c_sth = $conf->{sth} || $conf->{'запросы'} || {};
131             #~ my $c_pos = $conf->{pos} || $conf->{'посы'} || {};
132            
133             return
134             unless ($c_sth && ref($c_sth) eq 'HASH' && keys %$c_sth);
135             #~ || ($c_pos && ref($c_pos) eq 'HASH' && keys %$c_pos);
136              
137             my $sth = {};
138            
139             while (my ($db, $opt) = each %$c_dbh) {
140             while (my ($st, $sql) = each %{$opt->{sth}}) {
141             $sth->{$db}{$st} = $dbh->{$db}->prepare($sql);# $app->sth->{main}{...}
142             $app->log->debug("Подготовился запрос [app->sth->{$db}{$st}]");
143             }
144             }
145            
146             while (my ($db, $h) = each %$c_sth) {
147             while (my ($st, $sql) = each %$h) {
148             $sth->{$db}{$st} = $dbh->{$db}->prepare($sql);# $app->sth->{main}{...}
149             $app->log->debug("Подготовился запрос [app->sth->{$db}{$st}]");
150             }
151             }
152            
153             $sth;
154             };
155              
156            
157             sub хуки {# Хуки из конфига
158 0     0 0   my $app = shift;
159 0           my $conf = $app->config;
160 0   0       my $hooks = $conf->{'mojo_hooks'} || $conf->{'mojo.hooks'} || $conf->{'mojo'}{'hooks'} || $conf->{'хуки'}
161             || return;
162 0           while (my ($name, $sub) = each %$hooks) {
163 0 0         if (ref $sub eq 'ARRAY') {
164             $app->hook($name => $_)
165 0           for @$sub;
166             } else {
167 0           $app->hook($name => $sub);
168             }
169            
170 0 0         $app->log->debug(sprintf("Applied hook%s [%s] from config", ref $sub eq 'ARRAY' ? "s (@{[ scalar @$sub]})" : '', $name));
  0            
171             }
172              
173             }
174              
175             sub сессия {
176 0     0 0   my $app = shift;
177 0           my $conf = $app->config;
178 0   0       my $session = $conf->{'mojo_session'} || $conf->{'mojo_sessions'} || $conf->{'mojo.session'} || $conf->{'mojo.sessions'} || $conf->{'mojo'}{'session'} || $conf->{'mojo'}{'sessions'} || $conf->{'сессии'} || $conf->{'сессия'}
179             || return;
180            
181             #~ $app->sessions->cookie_name($session->{'cookie_name'})
182             #~ if $session->{'cookie_name'};
183            
184             #~ $app->sessions->default_expiration($session->{'default_expiration'}) # set expiry
185             #~ if defined $session->{'default_expiration'};
186            
187 0           while (my ($meth, $val) = each %$session) {
188             next
189 0 0         unless $app->sessions->can($meth);
190 0           $app->sessions->$meth($val);
191             }
192             }
193              
194             sub маршруты {
195 0     0 0   my $app = shift;
196 0           my $conf = $app->config;
197 0 0 0       my $routes = $conf->{'mojo_routes'} || $conf->{'mojo.routes'} || $conf->{'mojo'}{'routes'} || $conf->{'routes'} || $conf->{'маршруты'}
198             or return;
199 0           my $app_routes = $app->routes;
200             my $apply_route = sub {
201 0   0 0     my $r = shift || $app_routes;
202 0           my ($meth, $arg) = @_;
203 0           my $nr;
204 0 0         if (my $m = $r->can($meth)) {
205 0 0         $nr = $r->$m($arg) unless ref($arg);
206 0 0         $nr = $r->$m(cb => $arg) if ref($arg) eq 'CODE';
207 0 0         $nr = $r->$m(@$arg) if ref($arg) eq 'ARRAY';
208 0 0         $nr = $r->$m(%$arg) if ref($arg) eq 'HASH';
209            
210             } else {
211 0           $app->log->warn("Can't method [$meth] for route",);
212             }
213 0           return $nr;
214 0           };
215            
216 0           for my $r (@$routes) {
217 0 0         my $nr = $apply_route->($app_routes, @$r[0,1])
218             or next;
219 0           $app->log->debug("Apply route [$r->[0] $r->[1]]");
220 0           for( my $i = 2; $i < @$r; $i += 2 ) {
221 0 0         $nr = $apply_route->($nr, @$r[$i, $i+1])
222             or next;
223             }
224             }
225             }
226              
227             sub спейсы {
228 0     0 0   my $app = shift;
229 0           my $conf = $app->config;
230 0   0       my $ns = $conf->{'mojo_namespaces'} || $conf->{'mojo.namespaces'} || $conf->{'mojo'}{'namespaces'} || $conf->{'namespaces'} || $conf->{'ns'} || $conf->{'спейсы'}
231             || return;
232 0           push @{$app->routes->namespaces}, @$ns;
  0            
233             }
234              
235             sub задачи {
236 0     0 0   my $app = shift;
237 0           my $conf = $app->config;
238 0 0 0       my $tasks = $conf->{'jobs'} || $conf->{'tasks'} || $conf->{'задачи'}
239             or return;
240            
241 0 0         die "You have jobs and first enable plugin Minion"
242             unless $app->renderer->get_helper('minion');
243            
244 0           while (my ($name, $sub) = each %$tasks) {
245 0           $app->log->debug(sprintf("Applied task [%s] in [%s] from config", $name, $app->minion->add_task($name => $sub)));
246             }
247             #~ $app->minion->reset;
248             }
249              
250              
251             sub типы {#MIME
252 0     0 0   my $app = shift;
253 0           my $conf = $app->config;
254 0 0 0       my $types = $conf->{'mojo_types'} || $conf->{'mojo.types'} || $conf->{'mojo'}{'types'} || $conf->{'types'} || $conf->{'типы'}
255             or return;
256 0           while (my ($name, $val) = each %$types) {
257 0           $app->types->type($name => $val);
258 0           $app->log->debug(sprintf("Applied type [%s] from config", $name));
259             }
260             }
261              
262             # overide only on my $path = $req->url->path->to_abs_string;
263             sub Mojolicious::dispatch {
264 0     0 1   my ($self, $c) = @_;
265              
266 0           my $plugins = $self->plugins->emit_hook(before_dispatch => $c);
267              
268             # Try to find a static file
269 0           my $tx = $c->tx;
270 0 0 0       $self->static->dispatch($c) and $plugins->emit_hook(after_static => $c)
271             unless $tx->res->code;
272              
273             # Start timer (ignore static files)
274 0           my $stash = $c->stash;
275             $c->helpers->log->debug(sub {
276 0     0     my $req = $c->req;
277 0           my $url = $req->url->to_abs;
278 0           $c->helpers->timing->begin('mojo.timer');
279             #~ return sprintf qq{[%s] %s "%s://%s%s%s"},
280             #~ $req->request_id, $req->method, $url->scheme, $url->host, $url->port ? ":".$url->port : '', $url->path->to_route;
281 0           return sprintf qq{%s "%s"}, $req->method, Mojo::Util::decode('UTF-8', Mojo::Util::url_unescape($url));
282 0 0         }) unless $stash->{'mojo.static'};
283              
284             # Routes
285 0           $plugins->emit_hook(before_routes => $c);
286             $c->helpers->reply->not_found
287 0 0 0       unless $tx->res->code || $self->routes->dispatch($c) || $tx->res->code || $stash->{'mojo.rendered'};
      0        
      0        
288             }
289              
290              
291             our $VERSION = '0.0902';# as to Mojolicious/100+0.000
292              
293             =pod
294              
295             =encoding utf8
296              
297             =head1 Mojolicious::Che
298              
299             Доброго всем
300              
301             ¡ ¡ ¡ ALL GLORY TO GLORIA ! ! !
302              
303             =head1 VERSION
304              
305             0.0902
306              
307             =head1 NAME
308              
309             Mojolicious::Che - Мой базовый модуль для приложений Mojolicious. Нужен только развернутый конфиг.
310              
311             =head1 SYNOPSIS
312              
313             # app.pl
314             use lib 'lib';
315             use Mojo::Base 'Mojolicious::Che';
316             __PACKAGE__->new(config => 'lib/Config.pm')->start();
317              
318              
319             =head1 Config file
320              
321             Порядок строк в этом конфиге соответствует исполнению в модуле!
322              
323             {
324             'Проект'=>'Тест-проект',
325             # mojo => {
326             # defaults =>
327             # secrets =>
328             # mode=>
329             # log => {level=>...}
330             # static => {paths => [...]},
331             # renderer => {paths => [...], classes => [...], },
332             # session[s] =>
333             # has =>
334             # plugins =>
335             # hooks =>
336             # namespaces =>
337             # routes =>
338             # jobs =>
339             # types =>
340             # },
341             # or with prefix mojo_
342             # Default values for "stash" in Mojolicious::Controller, assigned for every new request.
343             mojo_defaults => {layout=>'default',},
344             # 'шифры' => [
345             mojo_secrets => ['true 123 my app',],
346             mojo_mode=> 'development',
347             mojo_log=>{level => 'error'},
348             mojo_static_paths => ["static"],
349             mojo_renderer_classes => ["Mojolicious::Foo::Fun"],
350             # 'сессия'(или сессии) =>
351             mojo_session[s] => {cookie_name => 'EXX', default_expiration => 86400},
352            
353             # 'хазы' => 'Лет 500-700 назад был такой дикий степной торговый жадный народ ХАЗАРЫ. Столицей их "государства" был город Тьмутаракань, где-то на берегу моря Каспия. Потомки этих людей рассыпаны по странам России, Средней Азии, Европы. Есть мнение, что хазары присвоили себе название ЕВРЕИ, но это не те библейские кроткие евреи, а жадные потомки кроманьонцев'
354             mojo_has => {
355             foo => sub {my $app = shift; return 'is a bar';},
356             },
357            
358             # 'базы' =>
359             # will be as has!
360             dbh=>{
361             'main' => {
362             # DBI->connect(dsn, user, passwd, $attrs)
363             connect => ["DBI:Pg:dbname=test;", "postgres", undef, {
364             ShowErrorStatement => 1,
365             AutoCommit => 1,
366             RaiseError => 1,
367             PrintError => 1,
368             pg_enable_utf8 => 1,
369             #mysql_enable_utf8 => 1,
370             #mysql_auto_reconnect=>1,
371             }],
372             # or use Foo::Dbh; external defined dbh
373             # dbh => Dbh->dbh,
374             # will do on connect
375             do => ['set datestyle to "ISO, DMY";',],
376             # prepared sth will be as has $app->sth->{}{}
377             sth => {
378             foo => <
379             select *
380             from foo
381             where
382             bar = ?;
383             SQL
384             },
385             }
386             },
387             # 'запросы' =>
388             # prepared sth will be as has $app->sth->{}{}
389             sth => {
390             main => {
391             now => "select now();"
392             },
393             },
394            
395             # 'плугины'=> [
396             mojo_plugins=>[
397             ['Foo::Bar'],
398             [Foo::Bar::Plugin => opt1 => ..., opt2 => ...],
399             ['Foo::Plugin' => sub {<...returns config data list...>}],
400             ],
401             # 'хуки' =>
402             mojo_hooks=>{
403             #~ before_dispatch => sub {1;},
404             },
405             # 'спейсы' => [...]
406             namespaces => ['Space::Shattle'],
407             # 'маршруты' => [...]
408             routes => [
409             [get=>'/', to=> {cb=>sub{shift->render(format=>'txt', text=>'Hello friend!');},}],
410             ]
411             #~ 'задачи'=> {#first enable plugin Minion
412             jobs => {
413             slow_log => sub {
414             my ($job, $msg) = @_;
415             sleep 5;
416             $job->app->log->error(qq{slow_log "$msg"});
417             },
418             },
419             # или 'типы'=>{...}
420             types => {
421             docx => ['application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
422             ...
423             },
424             };
425              
426             =head1 ATTRIBUTES
427              
428             B inherits all attributes from L and implements the
429             following new ones.
430              
431             =head2 dbh
432              
433             Set DBI handlers from config B (или B<базы>)
434              
435             my $dbh = $app->dbh->{main};
436              
437             =head2 sth
438              
439             Set prepared stattements from config B (или B<запросы>).
440              
441             my $sth = $app->sth->{main}{foo};
442              
443             =head2 плугины
444              
445             Apply the plugins. See L, L.
446              
447             =head1 METHODS
448              
449             B inherits all methods from L and implements the following new ones.
450              
451             =head2 сессия()
452              
453             Session object config apply. See L, L.
454              
455             =head2 хазы()
456              
457             Apply the has's. UTF names allow.
458              
459             =head2 хуки()
460              
461             Apply the hooks. See L.
462              
463             =head2 спейсы()
464              
465             Apply the namespaces. Push @{$app->routes->namespaces} your namespaces. See L.
466              
467             namespaces => ['Space::Shattle'],
468              
469             =head2 маршруты()
470              
471             Apply the routes. See L, L.
472              
473             #~ 'маршруты' => [
474             'routes'=>[
475             [get=>'/', to=> {cb=>sub{shift->render(format=>'txt', text=>'Welcome!');},}],
476             ],
477              
478             =head2 задачи()
479              
480             Apply the jobs. See L.
481              
482             #~ 'задачи'=> {#first enable plugin Minion
483             'jobs'=> { # or tasks
484             slow_log => sub {
485             my ($job, $msg) = @_;
486             sleep 5;
487             $job->app->log->error(qq{slow_log "$msg"});
488             },
489            
490             },
491              
492             =head типы()
493              
494             Apply the new types. See L, L.
495              
496             =head1 SEE ALSO
497              
498             L
499              
500             L
501              
502             =head1 AUTHOR
503              
504             Михаил Че (Mikhail Che), C<< >>
505              
506             =head1 BUGS / CONTRIBUTING
507              
508             Please report any bugs or feature requests at L.
509             Pull requests also welcome.
510              
511             =head1 COPYRIGHT
512              
513             Copyright 2016+ Mikhail Che.
514              
515             This library is free software; you can redistribute it and/or modify
516             it under the same terms as Perl itself.
517              
518             =cut
519              
520             1;