File Coverage

blib/lib/Mojolicious/Plugin/AutoRoutePm.pm
Criterion Covered Total %
statement 64 69 92.7
branch 8 16 50.0
condition 4 8 50.0
subroutine 6 6 100.0
pod 1 3 33.3
total 83 102 81.3


line stmt bran cond sub pod time code
1             package Mojolicious::Plugin::AutoRoutePm;
2             $Mojolicious::Plugin::AutoRoutePm::VERSION = '0.22';
3 1     1   1241 use Mojo::Base 'Mojolicious::Plugin';
  1         2  
  1         8  
4              
5 1     1   747 use File::Find::Rule;
  1         8856  
  1         7  
6 1     1   57 use Mojo::Loader qw(load_class);
  1         2  
  1         1053  
7              
8             sub register {
9 1     1 1 49 my ( $self, $app, $conf ) = @_;
10              
11             # default index
12 1   50     9 my $dindex = $conf->{default_index} || 'index';
13              
14             # Parent route
15 1   50     3 my $r = $conf->{route} || [ $app->routes ];
16              
17             # Excluded routes
18 1   50     6 my $exclude = $conf->{exclude} || [];
19              
20             # my %exclude = map {$_ => 1} @$exclude;
21              
22             # Template Base
23 1         4 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         10 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         6 push @$template_base_dirs, $tmpl_base_dir;
32             }
33              
34             # Top directory
35 1   50     3 my $top_dir = $conf->{top_dir} || '.';
36 1         2 $top_dir =~ s#^/##;
37 1         2 $top_dir =~ s#/$##;
38              
39             # Search templates
40 1         3 my @templates;
41 1         3 for my $template_base_dir (@$template_base_dirs) {
42 2         18 $template_base_dir =~ s#/$##;
43 2         7 my $template_dir = "$template_base_dir/$top_dir";
44              
45 2 100       42 if ( -d $template_dir ) {
46              
47             # Find templates
48 1         30 my $rules = File::Find::Rule->file()->name('*.pm')->relative(0)
49             ->start($template_dir);
50 1         1310 while ( defined( my $file = $rules->match ) ) {
51 2         32 $file =~ s/\.pm$//;
52 2         5 my $excluded = 0;
53 2         5 foreach (@$exclude) {
54 0 0       0 $excluded = 1 if ( $file =~ /$_/ );
55             }
56 2 50       11 push @templates, $file unless ($excluded);
57             }
58              
59             }
60             }
61              
62             # sort routes so, first existing .pm module which aren't DocumentRoot
63 1         24 my @template_index = grep /$dindex$/, @templates;
64 1         11 my @template_nindex = grep !/$dindex$/, @templates;
65 1         14 @templates = ( @template_nindex, @template_index );
66              
67             # Register routes
68 1         3 for my $template (@templates) {
69              
70             # Route
71 2         7 my $ctl = $self->path_to_controller($template);
72 2         11 load_class $ctl;
73 2 50       1689 if ( $ctl->isa('Mojolicious::Controller') ) {
74 2         6 $template = "/$template";
75 2         7 my $route = $self->get_best_matched_route( $template, $r );
76 2         7 my $routep = $route->to_string;
77 2         52 $template =~ s/^$routep//;
78              
79             # support for /url_component/index
80 2         12 my $tr = $route->any( $template => [ format => 1 ] )
81             ->to( app => $ctl, action => 'route', format => undef );
82 2         892 $tr->any('');
83              
84             # and for /url_component/index/a/b/x
85 2         431 $tr->any('/*query');
86 2 100       616 if ( $template =~ s/$dindex$// ) {
87              
88             # support for /url_component
89 1         4 my $tr = $route->any( $template => [ format => 1 ] )
90             ->to( app => $ctl, action => 'route', format => undef );
91 1         300 $tr->any('/');
92              
93             # and for /url_component/a/b/x
94 1         179 $tr->any('/*query');
95             }
96             }
97             }
98             }
99              
100             sub get_best_matched_route {
101 2     2 0 6 my $s = shift;
102 2         3 my $url = shift;
103              
104 2         5 my $routes = shift;
105              
106 2         3 my @ret;
107              
108 2         5 foreach my $r (@$routes) {
109 2 50       16 push @ret, $r
110             if ( substr( $url, 0, length( $r->to_string ) ) eq $r->to_string );
111             }
112              
113 2 50       157 return $ret[0] if ( scalar(@ret) == 1 ); # only one
114              
115             # more than one
116 0         0 my $ret = $ret[0];
117 0         0 foreach my $r (@ret) {
118 0 0       0 $ret = $r if ( length( $r->name ) > length( $ret->name ) );
119             }
120 0         0 return $ret;
121             }
122              
123             sub path_to_controller {
124 2     2 0 4 my $s = shift;
125 2         4 my $url = shift;
126              
127 2         5 $url =~ s{^/}{};
128 2         6 $url =~ s{/}{::}g;
129 2         5 $url =~ s{\.(.*?)$}{};
130              
131 2         4 return $url;
132             }
133              
134             1;
135              
136             =pod
137              
138             =head1 NAME
139              
140             Mojolicious::Plugin::AutoRoutePm - Mojolicious plugin to create routes by *.pm modules which are a controller
141              
142             =for html

143            
144             github workflow tests
145            
146             Top language:
147             github last commit
148            

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