File Coverage

blib/lib/Mojolicious/Plugin/AutoRoutePm.pm
Criterion Covered Total %
statement 60 65 92.3
branch 8 16 50.0
condition 4 8 50.0
subroutine 6 6 100.0
pod 1 3 33.3
total 79 98 80.6


line stmt bran cond sub pod time code
1             package Mojolicious::Plugin::AutoRoutePm;
2             $Mojolicious::Plugin::AutoRoutePm::VERSION = '0.21';
3 1     1   1124 use Mojo::Base 'Mojolicious::Plugin';
  1         2  
  1         8  
4              
5 1     1   699 use File::Find::Rule;
  1         7402  
  1         12  
6 1     1   70 use Mojo::Loader qw(load_class);
  1         2  
  1         942  
7              
8             sub register {
9 1     1 1 63 my ( $self, $app, $conf ) = @_;
10              
11             # default index
12 1   50     8 my $dindex = $conf->{default_index} || 'index';
13              
14             # Parent route
15 1   50     6 my $r = $conf->{route} || [ $app->routes ];
16              
17             # Excluded routes
18 1   50     5 my $exclude = $conf->{exclude} || [];
19              
20             # my %exclude = map {$_ => 1} @$exclude;
21              
22             # Template Base
23 1         7 my $system_template_base_dirs = $app->renderer->paths;
24              
25             # by default renderer->paths appends templates to base_app_path
26             # removing it we got the base path
27 1         11 my $template_base_dirs = [];
28 1         3 foreach (@$system_template_base_dirs) {
29 2         4 my $tmpl_base_dir = $_; # so next replace doesn't affect origianl path
30 2         8 $tmpl_base_dir =~ s/templates$//;
31 2         4 push @$template_base_dirs, $tmpl_base_dir;
32             }
33              
34             # Top directory
35 1   50     5 my $top_dir = $conf->{top_dir} || '.';
36 1         2 $top_dir =~ s#^/##;
37 1         2 $top_dir =~ s#/$##;
38              
39             # Search templates
40 1         2 my @templates;
41 1         2 for my $template_base_dir (@$template_base_dirs) {
42 2         17 $template_base_dir =~ s#/$##;
43 2         5 my $template_dir = "$template_base_dir/$top_dir";
44              
45 2 100       65 if ( -d $template_dir ) {
46              
47             # Find templates
48 1         28 my $rules = File::Find::Rule->file()->name('*.pm')->relative(0)
49             ->start($template_dir);
50 1         1144 while ( defined( my $file = $rules->match ) ) {
51 2         28 $file =~ s/\.pm$//;
52 2         4 my $excluded = 0;
53 2         6 foreach (@$exclude) {
54 0 0       0 $excluded = 1 if ( $file =~ /$_/ );
55             }
56 2 50       9 push @templates, $file unless ($excluded);
57             }
58              
59             }
60             }
61              
62             # Register routes
63 1         4 for my $template (@templates) {
64              
65             # Route
66 2         9 my $ctl = $self->path_to_controller($template);
67 2         13 load_class $ctl;
68 2 50       1803 if ( $ctl->isa('Mojolicious::Controller') ) {
69 2         6 $template = "/$template";
70 2         8 my $route = $self->get_best_matched_route( $template, $r );
71 2         5 my $routep = $route->to_string;
72 2         44 $template =~ s/^$routep//;
73              
74             # support for /url_component/index
75 2         12 my $tr = $route->any( $template => [ format => 1 ] )
76             ->to( app => $ctl, action => 'route', format => undef );
77 2         754 $tr->any('');
78              
79             # and for /url_component/index/a/b/x
80 2         352 $tr->any('/*query');
81 2 100       507 if ( $template =~ s/$dindex$// ) {
82              
83             # support for /url_component
84 1         4 my $tr = $route->any( $template => [ format => 1 ] )
85             ->to( app => $ctl, action => 'route', format => undef );
86 1         266 $tr->any('/');
87             }
88             }
89             }
90             }
91              
92             sub get_best_matched_route {
93 2     2 0 4 my $s = shift;
94 2         3 my $url = shift;
95              
96 2         4 my $routes = shift;
97              
98 2         5 my @ret;
99              
100 2         6 foreach my $r (@$routes) {
101 2 50       19 push @ret, $r
102             if ( substr( $url, 0, length( $r->to_string ) ) eq $r->to_string );
103             }
104              
105 2 50       129 return $ret[0] if ( scalar(@ret) == 1 ); # only one
106              
107             # more than one
108 0         0 my $ret = $ret[0];
109 0         0 foreach my $r (@ret) {
110 0 0       0 $ret = $r if ( length( $r->name ) > length( $ret->name ) );
111             }
112 0         0 return $ret;
113             }
114              
115             sub path_to_controller {
116 2     2 0 15 my $s = shift;
117 2         4 my $url = shift;
118              
119 2         4 $url =~ s{^/}{};
120 2         9 $url =~ s{/}{::}g;
121 2         4 $url =~ s{\.(.*?)$}{};
122              
123 2         4 return $url;
124             }
125              
126             1;
127              
128             =pod
129              
130             =head1 NAME
131              
132             Mojolicious::Plugin::AutoRoutePm - Mojolicious plugin to create routes by *.pm modules which are a controller
133              
134             =for html

135            
136             github workflow tests
137            
138             Top language:
139             github last commit
140            

141              
142             =head1 VERSION
143              
144             version 0.21
145              
146             =head1 SYNOPSIS
147              
148             use Mojolicious::Lite;
149             plugin 'AutoRoutePm', {
150             route => [ app->routes ],
151             top_dir => 'site',
152             };
153              
154             =head1 DESCRIPTION
155              
156             This module recursive passes through template_base_dir to find perl modules
157             (*.pm) that are a subclass of Mojolicious::Controller and adds routes for them.
158              
159             =encoding UTF-8
160              
161             =head1 USAGE
162              
163             For module X::Y::Z it adds the decamelize version
164              
165             x/y/z
166             x/y/z/index
167             x/y/z/index/*query
168              
169             all redirect to action route inside module.
170              
171             If Z is default_index it adds also
172              
173             x/y
174             x/y/*query
175              
176             The last structure is useful for routing seach. But be careful to correct
177             relative urls of other items in html page.
178              
179             This can be done in many ways. One is, as an example, to add to the layout
180             a base_url like this
181              
182             % my $base_url = url_for(undef, {query => undef}); $base_url =~ s|/$||;
183            
184              
185             =head2 register
186              
187             plugin->register($app);
188              
189             Register plugin in L application.
190              
191             =head1 BUGS/CONTRIBUTING
192              
193             Please report any bugs through the web interface at L
194             If you want to contribute changes or otherwise involve yourself in development, feel free to fork the Git repository from
195             L.
196              
197             =head1 SUPPORT
198              
199             You can find this documentation with the perldoc command too.
200              
201             perldoc Mojo::WebSocket::PubSub
202              
203             =head1 SEE ALSO
204              
205             L, L, L.
206              
207             =head1 AUTHOR
208              
209             Emiliano Bruni
210              
211             =head1 COPYRIGHT AND LICENSE
212              
213             This software is copyright (c) 2021 by Emiliano Bruni.
214              
215             This is free software; you can redistribute it and/or modify it under
216             the same terms as the Perl 5 programming language system itself.
217              
218             =cut
219              
220             __END__