File Coverage

blib/lib/Mojolicious/Command/generate/routes_restsful.pm
Criterion Covered Total %
statement 12 160 7.5
branch 0 86 0.0
condition 0 56 0.0
subroutine 4 10 40.0
pod 1 1 100.0
total 17 313 5.4


line stmt bran cond sub pod time code
1             package Mojolicious::Command::generate::routes_restsful;
2 1     1   1696 use Lingua::EN::Inflect 'PL';
  1         21984  
  1         163  
3 1     1   13 use Mojo::Base 'Mojolicious::Command';
  1         1  
  1         11  
4              
5 1     1   228 use Mojo::Util qw(class_to_file class_to_path camelize class_to_path);
  1         1  
  1         166  
6              
7             has description =>
8             'Generate Mojolicious App using a Mojolicious::Plugin::Routes::Restful hash';
9             has usage =>
10             "Usage: $0 generate Stub App with a Mojolicious::Plugin::Routes::Restful hash\n";
11              
12             our $VERSION = '0.0.1';
13             our $site = {};
14             our $site_api = {};
15             our @site_urls = ();
16             our %api_urls = ();
17 1     1   5 use Data::Dumper;
  1         1  
  1         2138  
18              
19             sub run {
20 0     0 1   my ( $self, $class, $in_routes ) = @_;
21              
22 0 0         die <
23             Your application name has to be a well formed (CamelCase) Perl module name
24             like "RoutesRestfulApp".
25             EOF
26              
27             # Script
28              
29 0           for my $sub_ref (qw/ PARENT CONFIG /) {
30             die __PACKAGE__, ": missing '$sub_ref' hash in parameters\n"
31 0 0         unless exists( $in_routes->{$sub_ref} );
32             }
33              
34 0           my $config = $in_routes->{CONFIG};
35              
36 0           my $routes = $in_routes->{PARENT};
37 0           my @namespaces = ( $class . "::Controller" );
38              
39 0           foreach my $key ( keys( %{$routes} ) ) {
  0            
40              
41             my $resource =
42 0           _make_site( "PARENT", $key, $routes->{$key}, $config, $key, $key );
43              
44 0           my $route = $routes->{$key};
45              
46 0           foreach my $inline_key ( keys( %{ $route->{INLINE} } ) ) {
  0            
47              
48             die __PACKAGE__, ": INLINE must be a Hash Ref\n"
49 0 0         if ( ref( $route->{INLINE} ) ne 'HASH' );
50              
51             _make_site( "INLINE", $inline_key, $route->{INLINE}->{$inline_key},
52 0           $config, $key, $resource, $routes->{$key}->{STASH} );
53              
54             }
55              
56 0           foreach my $sub_route_key ( keys( %{ $route->{CHILD} } ) ) {
  0            
57              
58             _make_site( "CHILD", $sub_route_key,
59             $route->{CHILD}->{$sub_route_key},
60 0           $config, $key, $resource, $routes->{$key}->{STASH} );
61              
62             }
63             }
64 0           my $name = class_to_file $class;
65 0           $self->render_to_rel_file( 'mojo', "$name/script/$name", $class, $routes );
66 0           $self->chmod_rel_file( "$name/script/$name", 0744 );
67              
68             # # content Controllers
69 0           foreach my $key ( keys( %{$site} ) ) {
  0            
70 0           my $controller = camelize($class) . "::Controller::" . camelize($key);
71 0           push( @namespaces, $controller );
72 0           my $path = class_to_path $controller;
73             $self->render_to_rel_file( 'controller', "$name/lib/$path", $controller,
74 0           $site->{$key} );
75              
76             # Templates
77 0           foreach my $action ( keys( %{ $site->{$key} } ) ) {
  0            
78 0           my $dir =
79             substr( class_to_path( camelize( lcfirst($key) ) ), 0, -3 );
80              
81 0           $self->render_to_rel_file(
82             'page',
83             "$name/templates/" . $dir . "/" . lcfirst($action) . ".html.ep",
84             $dir,
85             $action
86             );
87             }
88             }
89              
90             # API controllers
91              
92 0           foreach my $key ( keys( %{$site_api} ) ) {
  0            
93 0           my $controller = camelize($class) . "::Controller::" . camelize($key);
94 0           push( @namespaces, $controller );
95              
96 0           my $path = class_to_path $controller;
97             $self->render_to_rel_file(
98             'api_controller', "$name/lib/$path",
99 0           $controller, $site_api->{$key}
100             );
101              
102             }
103              
104 0           $in_routes->{CONFIG}->{NAMESPACES} = \@namespaces;
105 0           $Data::Dumper::Indent = 1;
106 0           $Data::Dumper::Terse = 1;
107 0           my $str_routes = Dumper($in_routes);
108              
109 0           my $app = class_to_path $class;
110 0           $self->render_to_rel_file( 'appclass', "$name/lib/$app", $class,
111             $str_routes );
112              
113 0           $self->render_to_rel_file( 'api_test', "$name/t/api_basic.t", $class,
114             \%api_urls );
115              
116             # Static file
117 0           $self->render_to_rel_file( 'static', "$name/public/index.html" );
118              
119             }
120              
121             sub _make_site {
122              
123 0     0     my ( $type, $key, $route, $config, $parent, $resource, $parent_stash ) = @_;
124              
125 0   0       my $route_stash = $route->{STASH} || {};
126 0 0         $route_stash = { %{$route_stash}, %{$parent_stash} }
  0            
  0            
127             if ($parent_stash);
128 0   0       my $action = $route->{ACTION} || "show";
129              
130 0   0       my $controller = $route->{CONTROLLER} || $key;
131              
132 0 0         if ( $type eq 'PARENT' ) {
133              
134             $resource = _api_site( $key, $route->{API}, $config->{API} )
135 0 0         if ( exists( $route->{API} ) );
136              
137             return $resource || $key
138 0 0 0       if ( exists( $route->{API_ONLY} ) );
139              
140             push( @site_urls, "/$key" )
141 0 0         unless ( exists( $route->{NO_ROOT} ) );
142              
143             push( @site_urls, "/$key/1" )
144 0 0         unless ( exists( $route->{NO_ID} ) );
145              
146 0           $site->{$controller}->{$action} = 1;
147              
148 0   0       return $resource || $key
149              
150             }
151 0   0       $controller = $route->{CONTROLLER} || $parent; #aways use parent on kids
152 0           $route_stash->{parent} = $resource;
153 0           $route_stash->{child} = $key;
154 0 0         if ( $type eq 'INLINE' ) {
    0          
155              
156 0   0       $action = $route->{ACTION} || $key;
157              
158             _sub_inline_api_site( $resource, $key, $route->{API}, $config->{API} )
159 0 0         if ( exists( $route->{API} ) );
160              
161             return
162 0 0         if ( exists( $route->{API_ONLY} ) );
163              
164 0 0         if ( exists( $route->{NO_ID} ) ) {
165 0           push( @site_urls, "/$parent/$key" );
166             }
167             else {
168 0           push( @site_urls, "/$parent/1/$key" );
169             }
170 0           $site->{$controller}->{$action} = $parent;
171             }
172             elsif ( $type eq 'CHILD' ) {
173              
174             _sub_api_site( $resource, $key, $route->{API}, $config->{API} )
175 0 0         if ( exists( $route->{API} ) );
176              
177             return
178 0 0         if ( exists( $route->{API_ONLY} ) );
179              
180 0   0       $action = $route->{ACTION} || $key;
181 0           push( @site_urls, "/$parent/1/$key" );
182 0           push( @site_urls, "/$parent/1/$key/1" );
183 0           $site->{$controller}->{$action} = $parent;
184              
185             }
186              
187             }
188              
189             sub _api_url {
190              
191 0     0     my ( $resource, $config ) = @_;
192 0   0       my $ver = $config->{VERSION} || "";
193 0   0       my $prefix = $config->{RESOURCE_PREFIX} || "";
194 0           my $url = join( "/", grep( $_ ne "", ( $ver, $prefix, $resource ) ) );
195 0           return $url;
196             }
197              
198             sub _api_site {
199              
200 0     0     my ( $key, $api, $config ) = @_;
201              
202 0   0       my $resource = $api->{resource} || PL($key);
203 0           my $verbs = $api->{VERBS};
204 0   0       my $stash = $api->{STASH} || {};
205 0   0       my $contoller = $api->{CONTROLLER} || $resource;
206 0   0       my $contoller_prefix = $config->{PRIFIX} || "api";
207 0           my $url = _api_url( $resource, $config );
208              
209             $site_api->{"$contoller_prefix-$contoller"}->{get} = 1
210 0 0         if ( $verbs->{RETREIVE} );
211              
212 0           push( @{ $api_urls{GET} }, "/" . $url )
213 0 0         if ( $verbs->{RETREIVE} );
214              
215 0           push( @{ $api_urls{GET} }, "/" . $url . "/1" )
216 0 0         if ( $verbs->{RETREIVE} );
217              
218             $site_api->{"$contoller_prefix-$contoller"}->{create} = 1
219 0 0         if ( $verbs->{CREATE} );
220              
221 0           push( @{ $api_urls{POST} }, ( "/" . $url ) )
222 0 0         if ( $verbs->{CREATE} );
223              
224             $site_api->{"$contoller_prefix-$contoller"}->{update} = 1
225 0 0         if ( $verbs->{UPDATE} );
226              
227 0           push( @{ $api_urls{PATCH} }, ( "/" . $url . "/1" ) )
228 0 0         if ( $verbs->{UPDATE} );
229              
230             $site_api->{"$contoller_prefix-$contoller"}->{replace} = 1
231 0 0         if ( $verbs->{REPLACE} );
232              
233 0           push( @{ $api_urls{PUT} }, ( "/" . $url . "/1" ) )
234 0 0         if ( $verbs->{REPLACE} );
235              
236             $site_api->{"$contoller_prefix-$contoller"}->{delete} = 1
237 0 0         if ( $verbs->{DELETE} );
238              
239 0           push( @{ $api_urls{POST} }, ( "/" . $url . "/1" ) )
240 0 0         if ( $verbs->{DELETE} );
241              
242 0           return $resource;
243              
244             }
245              
246             sub _sub_api_site {
247              
248 0     0     my ( $parent, $key, $api, $config ) = @_;
249              
250 0   0       my $child_resource = $api->{resource} || PL($key);
251 0           my $verbs = $api->{VERBS};
252 0   0       my $stash = $api->{STASH} || {};
253 0   0       my $child_controller = $api->{CONTROLLER} || $child_resource;
254 0   0       my $contoller_prefix = $config->{PRIFIX} || "api";
255 0           my $url = _api_url( $parent, $config );
256 0           $stash->{parent} = $parent;
257 0           $stash->{child} = $child_resource;
258              
259             $site_api->{"$contoller_prefix-$parent"}->{$child_resource} = 1
260 0 0         if ( $verbs->{RETREIVE} );
261              
262             $site_api->{"$contoller_prefix-$child_controller"}->{get} = 1
263 0 0         if ( $verbs->{RETREIVE} );
264              
265 0           push( @{ $api_urls{GET} }, "/" . $url . "/1/" . $child_resource )
266 0 0         if ( $verbs->{RETREIVE} );
267              
268 0           push( @{ $api_urls{GET} }, "/" . $url . "/1/" . $child_resource . "/1" )
269 0 0         if ( $verbs->{RETREIVE} );
270              
271             $site_api->{"$contoller_prefix-$child_controller"}->{create} = 1
272 0 0         if ( $verbs->{CREATE} );
273              
274 0           push( @{ $api_urls{POST} }, "/" . $url . "/1/" . $child_resource )
275 0 0         if ( $verbs->{CREATE} );
276              
277             $site_api->{"$contoller_prefix-$child_controller"}->{replace} = 1
278 0 0         if ( $verbs->{REPLACE} );
279              
280 0           push( @{ $api_urls{PUT} }, "/" . $url . "/1/" . $child_resource . "/1" )
281 0 0         if ( $verbs->{REPLACE} );
282              
283             $site_api->{"$contoller_prefix-$child_controller"}->{update} = 1
284 0 0         if ( $verbs->{UPDATE} );
285              
286 0           push( @{ $api_urls{PATCH} }, "/" . $url . "/1/" . $child_resource . "/1" )
287 0 0         if ( $verbs->{UPDATE} );
288              
289             $site_api->{"$contoller_prefix-$child_controller"}->{delete} = 1
290 0 0         if ( $verbs->{DELETE} );
291              
292 0           push( @{ $api_urls{DELETE} }, "/" . $url . "/1/" . $child_resource . "/1" )
293 0 0         if ( $verbs->{DELETE} );
294             }
295              
296             sub _sub_inline_api_site {
297              
298 0     0     my ( $parent, $key, $api, $config ) = @_;
299 0           my $verbs = $api->{VERBS};
300 0   0       my $child_resource = $api->{RESOURCE} || PL($key); #this should be action
301 0   0       my $stash = $api->{STASH} || {};
302 0   0       my $action = $api->{ACTION} || $child_resource;
303 0   0       my $contoller_prefix = $config->{PRIFIX} || "api";
304 0           my $url = _api_url( $parent, $config );
305 0           $stash->{parent} = $parent;
306 0           $stash->{child} = $child_resource;
307              
308             $site_api->{"$contoller_prefix-$parent"}->{$action} = 1
309 0 0         if ( $verbs->{RETREIVE} );
310              
311 0           push( @{ $api_urls{RETREIVE} }, "/" . $url . "/1/" . $child_resource )
312 0 0         if ( $verbs->{RETREIVE} );
313              
314 0           push( @{ $api_urls{UPDATE} }, "/" . $url . "/1/" . $child_resource )
315 0 0         if ( $verbs->{UPDATE} );
316              
317             $site_api->{"$contoller_prefix-$parent"}->{$action} = 1
318 0 0         if ( $verbs->{UPDATE} );
319              
320             }
321              
322             # Shut up friends.
323             # My internet browser heard us saying the word Fry and it found a movie about Philip J. Fry for us.
324             # It also opened my calendar to Friday and ordered me some french fries.
325             1;
326              
327             =pod
328              
329            
330             =head1 NAME
331            
332             Mojolicious::Command::generate::routes_restsful - Generate an App from a Mojolicious::Plugin::Routes::Restful HASH
333            
334             =head1 SYNOPSIS
335            
336             my $commands = Mojolicious::Commands->new;
337             my $gen = Mojolicious::Command::generate::routes_restsful->new;
338             $gen->run('RoutesRestfulApp',{
339             CONFIG => { Namespaces => ['RouteRestfulApp::Controller'] },
340             PARENT => {...
341            
342             =head1 DESCRIPTION
343            
344             Give L a hash that was created for L
345             and it will generate a stub site for you. You get a stub working in version of your app made up of
346              
347             An App Class
348             Content Contollers
349             API Controllers
350             A Startup Script
351             A Template set based on your content controlers
352             A basic test suite for your API
353            
354             Please note that this generator overwrites the NAMESPACE attribute of you hash. It is not intended to use this generator from the command line.
355             Best to use it in a script. See the script dir for an example.
356              
357             See L for details on how to make a Hash for this generator.
358            
359             =head1 ATTRIBUTES
360            
361             L inherits all attributes from
362             L and implements the following new ones.
363            
364             =head2 description
365            
366             my $description = $app->description;
367             $app = $app->description('Foo');
368            
369             Short description of this command, used for the command list.
370            
371             =head2 usage
372            
373             my $usage = $app->usage;
374             $app = $app->usage('Foo');
375            
376             Usage information for this command, used for the help screen.
377            
378             =head1 METHODS
379            
380             L inherits all methods from
381             L and implements the following new ones.
382            
383             =head2 run
384            
385             $app->run($class,$hash);
386            
387             Generates the App. Where $class is the name of the App you want to create, and $hash is a valid L hash.
388              
389            
390             =head1 SEE ALSO
391            
392             L, L, L, L.
393            
394             =cut
395              
396             __DATA__