File Coverage

blib/lib/Yeb/Application.pm
Criterion Covered Total %
statement 148 221 66.9
branch 28 54 51.8
condition 3 5 60.0
subroutine 48 74 64.8
pod 0 18 0.0
total 227 372 61.0


line stmt bran cond sub pod time code
1             package Yeb::Application;
2             BEGIN {
3 2     2   65 $Yeb::Application::AUTHORITY = 'cpan:GETTY';
4             }
5             # ABSTRACT: Main Meta Class for a Yeb Application
6             $Yeb::Application::VERSION = '0.103';
7 2     2   1882 use Moo;
  2         36643  
  2         16  
8 2     2   5356 use Package::Stash;
  2         33179  
  2         77  
9 2     2   25 use Import::Into;
  2         4  
  2         48  
10 2     2   12350 use Yeb::Context;
  2         8  
  2         79  
11 2     2   2045 use Yeb::Class;
  2         7  
  2         87  
12 2     2   50 use Class::Load ':all';
  2         4  
  2         535  
13 2     2   14 use Path::Tiny qw( path );
  2         4  
  2         103  
14 2     2   11580 use Plack::Middleware::Debug;
  2         211222  
  2         84  
15 2     2   28 use List::Util qw( reduce );
  2         4  
  2         226  
16 2     2   7630 use Hash::Merge qw( merge );
  2         8647  
  2         343  
17 2     2   5528 use URL::Encode qw( url_encode_utf8 );
  2         15211  
  2         148  
18 2     2   12831 use List::MoreUtils qw(any);
  2         3192  
  2         247  
19 2     2   1838 use Sys::Hostname;
  2         2683  
  2         120  
20              
21 2     2   14 use Carp;
  2         5  
  2         108  
22              
23 2     2   5309 use Web::Simple ();
  2         10007  
  2         20803  
24              
25             my $first_yep_application;
26              
27             has class => (
28             is => 'ro',
29             required => 1,
30             );
31              
32             has app => (
33             is => 'rw',
34             );
35              
36             has first => (
37             is => 'ro',
38             lazy => 1,
39             builder => sub {
40 3     3   990 my ( $self ) = @_;
41 3 100       41 $first_yep_application->class eq $self->class ? 1 : 0;
42             },
43             );
44              
45             has args => (
46             is => 'ro',
47             predicate => 1,
48             );
49              
50 0     0   0 has config => (
51             is => 'ro',
52             lazy => 1,
53             builder => sub {{}},
54             );
55              
56             has root => (
57             is => 'ro',
58             lazy => 1,
59             builder => sub {
60 3 100   3   1014 defined $ENV{YEB_ROOT}
61             ? path($ENV{YEB_ROOT})
62             : path(".")
63             },
64             );
65              
66             has current_dir => (
67             is => 'ro',
68             lazy => 1,
69 3     3   956 builder => sub { path(".") },
70             );
71              
72             has debug => (
73             is => 'ro',
74             lazy => 1,
75             builder => sub {
76 3     3   878 my ( $self ) = @_;
77 3 100       31 return 0 unless $self->first;
78 2 50 33     31 return $ENV{YEB_TRACE} || $ENV{YEB_DEBUG} ? 1 : 0;
79             },
80             );
81              
82             has package_stash => (
83             is => 'ro',
84             lazy => 1,
85 3     3   959 builder => sub { Package::Stash->new(shift->class) },
86             );
87              
88 3     3   1305 has yebs => (
89             is => 'ro',
90             lazy => 1,
91             builder => sub {{}},
92             );
93             sub y {
94 14     14 0 25 my ( $self, $yeb ) = @_;
95 14         392 $self->yebs->{$yeb};
96             }
97             sub y_main {
98 17     17 0 42 my ( $self ) = @_;
99 17         448 $self->yebs->{$self->class};
100             }
101              
102 3     3   832 has functions => (
103             is => 'ro',
104             lazy => 1,
105             builder => sub {{}},
106             );
107              
108 1     1   481 has plugins => (
109             is => 'ro',
110             lazy => 1,
111             builder => sub {[]},
112             );
113              
114             has yeb_functions => (
115             is => 'ro',
116             lazy => 1,
117             builder => sub {
118 3     3   970 my ( $self ) = @_;
119             {
120 5     5   24 yeb => sub { $self },
121              
122 0     0   0 app => sub { $self->app },
123              
124             chain => sub {
125 5     5   36 my $class = $self->class_loader(shift);
126 5         73 return $class->yeb->y($class)->chain;
127             },
128             load => sub {
129 1     1   323 my $class = $self->class_loader(shift);
130 1         5 return;
131             },
132              
133 0     0   0 cfg => sub { $self->config },
134 2     2   268 root => sub { path($self->root,@_) },
135 0     0   0 cur => sub { path($self->current_dir,@_) },
136 0     0   0 hostname => sub { hostname() },
137              
138 0     0   0 cc => sub { $self->cc },
139 0     0   0 env => sub { $self->hash_accessor($self->cc->env,@_) },
140 0     0   0 req => sub { $self->cc->request },
141 0     0   0 uri_for => sub { $self->cc->uri_for(@_) },
142 21     21   5021 st => sub { $self->hash_accessor_empty($self->cc->stash,@_) },
143 0     0   0 st_has => sub { $self->hash_accessor_has($self->cc->stash,@_) },
144 8     8   13978 ex => sub { $self->hash_accessor_empty($self->cc->export,@_) },
145 0     0   0 ex_has => sub { $self->hash_accessor_has($self->cc->export,@_) },
146 0     0   0 pa => sub { $self->hash_accessor_empty($self->cc->request->parameters,@_) },
147 0     0   0 pa_has => sub { $self->hash_accessor_has($self->cc->request->parameters,@_) },
148              
149             url => sub {
150 0     0   0 my @parts = $self->flat([@_]);
151 0         0 my ( @path_parts, @hashs );
152 0         0 for (@parts) {
153 0 0       0 if (ref $_ eq 'HASH') {
154 0         0 push @hashs, $_;
155             } else {
156 0         0 push @path_parts, $_;
157             }
158             }
159 0         0 my $url = $self->cc->uri_base;
160 0 0       0 if (@path_parts) {
161 0         0 $url .= join("/",map { url_encode_utf8($_) } @path_parts);
  0         0  
162             }
163 0 0       0 if (@hashs) {
164 0         0 $url .= '?';
165 0         0 my $gets = $self->merge_hashs(reverse @hashs);
166 0         0 $url .= join("&",map { $_.'='.url_encode_utf8($gets->{$_}) } keys %{$gets});
  0         0  
  0         0  
167             }
168 0         0 return $url;
169             },
170              
171             text => sub {
172 9     9   2626 $self->cc->content_type('text/plain');
173 9         804 $self->cc->body(join("\n",@_));
174 9         527 $self->cc->response;
175             },
176              
177             redirect => sub {
178 0     0   0 my ( $target, $code ) = shift;
179 0 0       0 $code = 307 unless $code;
180 0         0 $self->cc->content_type('text/html');
181 0         0 $self->cc->header->{location} = $target;
182 0         0 $self->cc->body(<<"__REDIRECT__");
183             Moved
184            

Moved

This page has moved to $target.

185             __REDIRECT__
186 0         0 $self->cc->response;
187             },
188              
189             html_body => sub {
190 0     0   0 $self->cc->content_type('text/html');
191 0         0 $self->cc->body(''.join(" ",@_).'');
192 0         0 $self->cc->response;
193             },
194             }
195 3         243 },
196             );
197              
198             sub call {
199 0     0 0 0 my ( $self, $func, @args ) = @_;
200 0 0       0 return $self->functions->{$func}->(@_) if defined $self->functions->{$func};
201 0 0       0 return $self->yeb_functions->{$func}->(@_) if defined $self->yeb_functions->{$func};
202 0         0 croak "Unknown function ".$func." inside ".(ref $self)." application";
203             }
204              
205             sub class_loader {
206 6     6 0 15 my ( $self, $class ) = @_;
207 6 100       24 if ($class =~ m/^\+/) {
208 2         12 $class =~ s/^(\+)//;
209             } else {
210 4         19 $class = $self->class.'::'.$class;
211             }
212 6 100       37 load_class($class) unless is_class_loaded($class);
213 6         477 return $class;
214             }
215              
216             sub hash_accessor_empty {
217 29     29 0 190 my ( $self, @hash_and_args ) = @_;
218 29         76 my $value = $self->hash_accessor(@hash_and_args);
219 29 100       169 return defined $value ? $value : "";
220             }
221              
222             sub hash_accessor_has {
223 0     0 0 0 my ( $self, @hash_and_args ) = @_;
224 0         0 my $value = $self->hash_accessor(@hash_and_args);
225 0 0       0 return defined $value ? 1 : "";
226             }
227              
228             sub hash_accessor {
229 29     29 0 67 my ( $self, $hash, $key, $value ) = @_;
230 29 50       103 return $hash unless defined $key;
231 29 100       90 my @args = ref $key eq 'ARRAY' ? @{$key} : ($key);
  15         34  
232 29         87 my $last_key = shift @args;
233 29         45 my $last;
234 29 100       64 if (@args) {
235 10   100 10   77 $last = reduce { $a->{$b}||={} } ($hash, @args);
  10         69  
236             } else {
237 19         39 $last = $hash;
238             }
239 29 100       97 if (defined $value) {
240 16         139 return $last->{$last_key} = $value;
241             } else {
242 13         36 return $last->{$last_key};
243             }
244             }
245              
246             sub add_plugin {
247 1     1 0 3 my ( $self, $source, $plugin, %args ) = @_;
248 1         1 my $class;
249 1 50       17 if ($plugin =~ m/^\+(.+)/) {
250 0         0 $class = $1;
251             } else {
252 1         3 $class = 'Yeb::Plugin::'.$plugin;
253             }
254 1         6 load_class($class);
255 1         33 my $obj = $class->new( app => $self, class => $self->y($source) , %args );
256 1         6 push @{$self->plugins}, $obj;
  1         5  
257             }
258              
259             sub add_middleware {
260 0     0 0 0 my ( $self, $middleware ) = @_;
261 0     0   0 $self->y_main->prepend_to_chain( "" => sub { $middleware } );
  0         0  
262             }
263              
264             sub BUILD {
265 3     3 0 17931 my ( $self ) = @_;
266              
267 3 100       18 $first_yep_application = $self unless defined $first_yep_application;
268              
269 3         33 $self->root;
270 3         150 $self->current_dir;
271              
272 3         102 $self->package_stash->add_symbol('$yeb',\$self);
273            
274 3         41 Web::Simple->import::into($self->class);
275              
276             $self->package_stash->add_symbol('®ister_has',sub {
277 0     0   0 my ( $attr, @args ) = @_;
278 0 0       0 my @attrs = ref $attr eq 'ARRAY' ? @{$attr} : ($attr);
  0         0  
279 0         0 $self->register_function($_, $self->class->can($_)) for @attrs;
280 0         0 $self->class->can('has')->($attr, @args);
281 3         18172 });
282              
283             $self->package_stash->add_symbol('®ister_function',sub {
284 0     0   0 $self->register_function(@_);
285 3         158 });
286            
287             $self->package_stash->add_symbol('&dispatch_request',sub {
288 16     16   155642 my ( $app, $env ) = @_;
289 16         99 $self->app($app);
290 16         65 $self->reset_context;
291 16         1188 $self->set_cc(Yeb::Context->new( env => $env ));
292             return $self->y_main->chain,
293             '/...' => sub {
294 2     2   4225 $self->cc->status(500);
295 2         19 $self->cc->response;
296 16         73 };
297 3         7820 });
298              
299 3         70 $self->yeb_import($self->class);
300              
301             $self->package_stash->add_symbol('&import',sub {
302 3     3   3269 my ( $class ) = @_;
303 3         12 my $target = caller;
304 3         14 $self->yeb_import($target);
305 3         348 });
306              
307 3 50       95 if ($self->debug) {
308 0         0 $self->add_middleware(Plack::Middleware::Debug->new);
309             }
310              
311 3 100       18 my @args = $self->has_args ? ( @{$self->args} ) : ();
  1         5  
312              
313 3         63 while (@args) {
314 1         2 my $plugin = shift @args;
315 1 50       5 my $plugin_args = ref $args[0] eq 'HASH'
316             ? shift @args : {};
317 1         4 $self->add_plugin($self->class,$plugin,%{$plugin_args});
  1         5  
318             }
319             }
320              
321             my $cc;
322 16     16 0 2519 sub set_cc { shift; $cc = shift; }
  16         41  
323 60     60 0 1504 sub cc { $cc }
324 16     16 0 38 sub reset_context { $cc = undef }
325 0     0 0 0 sub current_context { shift->cc }
326              
327             sub yeb_import {
328 6     6 0 16 my ( $self, $target ) = @_;
329 6         130 $self->yebs->{$target} = Yeb::Class->new(
330             app => $self,
331             class => $target,
332             );
333 6         187 for (keys %{$self->functions}) {
  6         92  
334 6         73 $self->y($target)->add_function($_,$self->functions->{$_});
335             }
336             }
337              
338             sub register_function {
339 2     2 0 3 my ( $self, $func, $coderef ) = @_;
340 2 50       43 die "Function ".$func." already defined" if defined $self->functions->{$func};
341 2         55 $self->functions->{$func} = $coderef;
342 2         13 for (keys %{$self->yebs}) {
  2         38  
343 2         19 $self->y($_)->add_function($func,$coderef);
344             }
345             }
346              
347             sub flat {
348 0     0 0   my ( $self, $list, @seen_lists ) = @_;
349 0 0         if (ref $list ne 'ARRAY') {
    0          
350 0           return $list;
351 0     0     } elsif (any { $_ == $list } @seen_lists) {
352 0           return;
353             } else {
354 0           push @seen_lists, $list;
355 0           return map { $self->flat($_, @seen_lists) } @{$list};
  0            
  0            
356             }
357             }
358              
359             sub merge_hashs {
360 0     0 0   my ( $self, @hashs ) = @_;
361 0           my $first = pop @hashs;
362 0           while (@hashs) {
363 0           my $next = pop @hashs;
364 0           $first = merge($first,$next);
365             }
366 0           return $first;
367             }
368              
369             1;
370              
371             __END__