File Coverage

blib/lib/Mojolicious/Plugin/RoutesConfig.pm
Criterion Covered Total %
statement 45 47 95.7
branch 20 22 90.9
condition 2 4 50.0
subroutine 6 6 100.0
pod 1 1 100.0
total 74 80 92.5


line stmt bran cond sub pod time code
1             package Mojolicious::Plugin::RoutesConfig;
2 2     2   148733 use Mojo::Base 'Mojolicious::Plugin::Config', -signatures;
  2         195243  
  2         18  
3 2     2   44402 use List::Util qw(first);
  2         5  
  2         1774  
4              
5             our $VERSION = 0.06;
6             our $AUTHORITY = 'cpan:BEROV';
7              
8             sub register {
9 12     12 1 39970 my ($self, $app, $conf) = @_;
10 12         29 my $file = $conf->{file};
11 12 100       39 my $file_msg = ($file ? ' in file ' . $file : '');
12 12         121 $conf = $self->SUPER::register($app, $conf);
13             $app->log->warn('No routes definitions found' . $file_msg . '...')
14             && return $conf
15 12 100 50     9173 unless exists $conf->{routes};
16             $app->log->warn( '"routes" key must point to an ARRAY reference '
17             . 'of routes descriptions'
18             . $file_msg . '...')
19             && return $conf
20 10 100 50     47 unless ref $conf->{routes} eq 'ARRAY';
21              
22 4         16 $self->_generate_routes($app, $app->routes, $conf->{routes}, $file_msg);
23 4         29 return $conf;
24             }
25              
26             # generates routes (recursively for under)
27             sub _generate_routes {
28 8     8   45 my ($self, $app, $routes, $routes_conf, $file_msg) = @_;
29 8         18 my $init_rx = '^(?:any|route|get|post|patch|put|delete|options|under)$';
30 8         19 for my $rconf (@$routes_conf) {
31 36     56   533 my $init_method = first(sub { $_ =~ /$init_rx/; }, keys %$rconf);
  56         259  
32 36 100       156 unless ($init_method) {
33 4         16 $app->log->warn( "Malformed route description$file_msg!!!$/"
34             . " Could not find route initialisation method, matching$/"
35             . " /$init_rx/$/"
36             . " in definition$/"
37             . $app->dumper($rconf)
38             . ". Skipping...");
39 4         1097 next;
40             }
41 32         67 my $init_params = $rconf->{$init_method};
42 32         70 my $route = _call_method($routes, $init_method, $init_params);
43 32 100       8737 if ($init_method eq 'under') { # recourse
44 4         20 $self->_generate_routes($app, $route, $rconf->{routes}, $file_msg);
45             }
46 32         91 for my $method (keys %$rconf) {
47 78 100       1297 next if $method =~ /^(?:$init_method|routes)$/;
48 44         95 my $params = $rconf->{$method};
49 44 100       161 $route->can($method) || do {
50 4 50       52 $app->log->warn("Malformed route description$file_msg!!!$/"
51             . " for route definition$/"
52             . $app->dumper($rconf)
53 4         1170 . qq|Can't locate object method "$method" via package "${\ ref $route}"!$/|
54             . ' Removing route '
55             . (ref $init_params eq 'ARRAY' ? $init_params->[0] : $init_params));
56 4         495 $route->remove();
57 4         188 last;
58             };
59 40         662 _call_method($route, $method, $params);
60             }
61             }
62 8         97 return;
63             }
64              
65             # Returns a new or existing route
66 72     72   105 sub _call_method ($caller, $method, $params) {
  72         113  
  72         98  
  72         101  
  72         102  
67 72 100       196 if (ref $params eq 'ARRAY') {
    100          
    50          
68 28         88 return $caller->$method(@$params);
69             }
70             elsif (ref $params eq 'HASH') {
71 28         126 return $caller->$method(%$params);
72             }
73             elsif (ref $params eq 'CODE') {
74 0         0 return $caller->$method($params->());
75             }
76             else {
77 16         49 return $caller->$method($params);
78             }
79              
80 0           Carp::croak('This should never happen');
81             }
82              
83             =encoding utf8
84              
85             =head1 NAME
86              
87             Mojolicious::Plugin::RoutesConfig - Describe routes in configuration
88              
89             =head1 SYNOPSIS
90              
91             # Create $MOJO_HOME/etc/routes.conf and describe your routes
92             # or do it directly in $MOJO_HOME/${\ $app->moniker }.conf
93             {
94             routes => [
95             {get => '/groups', to => 'groups#list', name => 'list_groups'},
96             {post => '/groups', to => 'groups#create'},
97             {any => {[qw(GET POST)] => '/users'}, to => 'users#list_or_create'},
98              
99             {under => '/управление', to => 'auth#under_management',
100             routes => [
101             {any => '/', to => 'upravlenie#index', name => 'home_upravlenie'},
102             {get => '/groups', to => 'groups#index', name => 'home_groups'},
103             #...
104             ],
105             },
106             ],
107             }
108              
109             # Mojolicious
110             my $config = $app->plugin('Config');
111             # or even
112             my $config = $app->plugin('RoutesConfig');
113             # or
114             $app->plugin('RoutesConfig', $config);
115             $app->plugin('RoutesConfig', {file => $app->home->child('etc/routes_admin.conf')});
116             $app->plugin('RoutesConfig', {file => $app->home->child('etc/routes_site.conf')});
117              
118             # Mojolicious::Lite
119             my $config = plugin 'Config';
120             plugin 'RoutesConfig', $config;
121             plugin 'RoutesConfig', {file => app->home->child('etc/routes_admin.conf')};
122             plugin 'RoutesConfig', {file => app->home->child('etc/routes_site.conf')};
123              
124             =head1 DESCRIPTION
125              
126             L allows you to define your routes in
127             configuration file or in a separate file, for example
128             C<$MOJO_HOME/etc/plugins/routes.conf>. This way you can quickly enable and
129             disable parts of your application without editing its source code.
130              
131             The routes are described the same way as you would generate them imperatively,
132             just instead of methods you use method names as keys and suitable references as
133             values which will be dereferenced and passed as arguments to the respective
134             method. If C<$parameters> is a reference to CODE it will be executed and
135             whatever it returns will be the parameters for the respective method.For
136             allowed keys look at L. Look at
137             C for inspiration. You can have all your routes
138             defined in the configuration file as it is Perl and you have the C object
139             available.
140              
141             =head1 METHODS
142              
143             L inherits all methods from L and implements the following new ones.
144              
145             =head2 register
146              
147             my $config = $plugin->register(Mojolicious->new, $config);
148             my $config = $plugin->register($app, {file => '/etc/app_routes.conf'});
149              
150             Register the plugin in L application and generate routes.
151              
152             =head1 AUTHOR
153              
154             Красимир Беров
155             CPAN ID: BEROV
156             berov ат cpan точка org
157             http://i-can.eu
158              
159             =head1 COPYRIGHT
160              
161             This program is free software; you can redistribute
162             it and/or modify it under the terms of Artistic License 2.0.
163              
164             The full text of the license can be found in the
165             LICENSE file included with this module.
166              
167             =head1 SEE ALSO
168              
169             L, L,
170             L, L
171              
172             L has a pretty advanced routes configuration using
173             L. Please look at
174             Slovo/lib/Slovo/resources/etc/routes.conf.
175              
176             =cut
177              
178             #################### main pod documentation end ###################
179              
180              
181             1;
182