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   128475 use Mojo::Base 'Mojolicious::Plugin::Config', -signatures;
  2         140138  
  2         15  
3 2     2   42387 use List::Util qw(first);
  2         5  
  2         1722  
4              
5             our $VERSION = 0.05;
6             our $AUTHORITY = 'cpan:BEROV';
7              
8             sub register {
9 12     12 1 31304 my ($self, $app, $conf) = @_;
10 12         28 my $file = $conf->{file};
11 12 100       42 my $file_msg = ($file ? ' in file ' . $file : '');
12 12         103 $conf = $self->SUPER::register($app, $conf);
13             $app->log->warn('No routes definitions found' . $file_msg . '...')
14             && return $conf
15 12 100 50     8552 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     48 unless ref $conf->{routes} eq 'ARRAY';
21              
22 4         14 $self->_generate_routes($app, $app->routes, $conf->{routes}, $file_msg);
23 4         31 return $conf;
24             }
25              
26             # generates routes (recursively for under)
27             sub _generate_routes {
28 8     8   36 my ($self, $app, $routes, $routes_conf, $file_msg) = @_;
29 8         16 my $init_rx = '^(?:any|route|get|post|patch|put|delete|options|under)$';
30 8         19 for my $rconf (@$routes_conf) {
31 36     57   559 my $init_method = first(sub { $_ =~ /$init_rx/; }, keys %$rconf);
  57         222  
32 36 100       140 unless ($init_method) {
33 4         14 $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         1243 next;
40             }
41 32         56 my $init_params = $rconf->{$init_method};
42 32         62 my $route = _call_method($routes, $init_method, $init_params);
43 32 100       7444 if ($init_method eq 'under') { # recourse
44 4         19 $self->_generate_routes($app, $route, $rconf->{routes}, $file_msg);
45             }
46 32         91 for my $method (keys %$rconf) {
47 80 100       1290 next if $method =~ /^(?:$init_method|routes)$/;
48 44         88 my $params = $rconf->{$method};
49 44 100       157 $route->can($method) || do {
50 4 50       14 $app->log->warn("Malformed route description$file_msg!!!$/"
51             . " for route definition$/"
52             . $app->dumper($rconf)
53 4         1011 . 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         404 $route->remove();
57 4         153 last;
58             };
59 40         114 _call_method($route, $method, $params);
60             }
61             }
62 8         22 return;
63             }
64              
65             # Returns a new or existing route
66 72     72   95 sub _call_method ($caller, $method, $params) {
  72         108  
  72         99  
  72         88  
  72         88  
67 72 100       187 if (ref $params eq 'ARRAY') {
    100          
    50          
68 28         99 return $caller->$method(@$params);
69             }
70             elsif (ref $params eq 'HASH') {
71 28         127 return $caller->$method(%$params);
72             }
73             elsif (ref $params eq 'CODE') {
74 0         0 return $caller->$method($params->());
75             }
76             else {
77 16         50 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, L
170              
171             =cut
172              
173             #################### main pod documentation end ###################
174              
175              
176             1;
177