File Coverage

blib/lib/Tatsumaki/Application.pm
Criterion Covered Total %
statement 45 83 54.2
branch 5 16 31.2
condition 2 3 66.6
subroutine 14 22 63.6
pod 0 9 0.0
total 66 133 49.6


line stmt bran cond sub pod time code
1             package Tatsumaki::Application;
2 4     4   149499 use AnyEvent;
  4         11755  
  4         134  
3 4     4   2216 use Any::Moose;
  4         97826  
  4         34  
4 4     4   3618 use Tatsumaki::Handler;
  4         12  
  4         123  
5 4     4   2801 use Tatsumaki::Request;
  4         16  
  4         125  
6 4     4   36 use Try::Tiny;
  4         9  
  4         596  
7              
8 4     4   5300 use Plack::Middleware::Static;
  4         79243  
  4         238  
9              
10 4     4   38 use overload q(&{}) => sub { shift->psgi_app }, fallback => 1;
  4     6   9  
  4         47  
  6         45361  
11              
12             has _rules => (is => 'rw', isa => 'ArrayRef');
13             has template => (is => 'rw', isa => 'Tatsumaki::Template', lazy_build => 1, handles => [ 'render_file' ]);
14              
15             has static_path => (is => 'rw', isa => 'Str', default => 'static');
16             has _services => (is => 'rw', isa => 'HashRef', default => sub { +{} });
17              
18             around BUILDARGS => sub {
19             my $orig = shift;
20             my $class = shift;
21             if (ref $_[0] eq 'ARRAY') {
22             my $handlers = shift @_;
23             my @rules;
24             while (my($path, $handler) = splice @$handlers, 0, 2) {
25             $path = qr@^/$@ if $path eq '/';
26             $path = qr/^$path/ unless ref $path eq 'RegExp';
27             push @rules, { path => $path, handler => $handler };
28             }
29             $class->$orig(_rules => \@rules, @_);
30             } else {
31             $class->$orig(@_);
32             }
33             };
34              
35             sub add_handlers {
36 0     0 0 0 my $self = shift;
37 0         0 while (my($path, $handler) = splice @_, 0, 2) {
38 0         0 $self->route($path, $handler);
39             }
40             }
41              
42             sub route {
43 0     0 0 0 my($self, $path, $handler) = @_;
44 0 0       0 $path = qr/^$path/ unless ref $path eq 'RegExp';
45 0         0 push @{$self->_rules}, { path => $path, handler => $handler };
  0         0  
46             }
47              
48             sub dispatch {
49 6     6 0 49 my($self, $req) = @_;
50              
51 6         45 my $path = $req->path_info;
52 6         66 for my $rule (@{$self->_rules}) {
  6         35  
53 6 100       48 if ($path =~ $rule->{path}) {
54 4         31 my $args = [ $1, $2, $3, $4, $5, $6, $7, $8, $9 ];
55 4         119 return $rule->{handler}->new(application => $self, request => $req, args => $args);
56             }
57             }
58              
59 2         25 return;
60             }
61              
62             sub psgi_app {
63 6     6 0 12 my $self = shift;
64 6   66     44 return $self->{psgi_app} ||= $self->compile_psgi_app;
65             }
66              
67             sub compile_psgi_app {
68 2     2 0 5 my $self = shift;
69              
70             my $app = sub {
71 6     6   70 my $env = shift;
72 6         116 my $req = Tatsumaki::Request->new($env);
73              
74 6 100       76 my $handler = $self->dispatch($req)
75             or return [ 404, [ 'Content-Type' => 'text/html' ], [ "404 Not Found" ] ];
76              
77 4         592 my $res = $handler->run;
78 2         14 };
79              
80 2 50       20 if ($self->static_path) {
81 2 0   6   42 $app = Plack::Middleware::Static->wrap($app, path => sub { s/^\/(?:(favicon\.ico)|static\/)/$1||''/e }, root => $self->static_path);
  6         314  
  0         0  
82             }
83              
84 2         118 $app;
85             }
86              
87             sub _build_template {
88 0     0     my $self = shift;
89 0           require Tatsumaki::Template::Micro;
90 0           Tatsumaki::Template::Micro->new;
91             }
92              
93             sub template_path {
94 0     0 0   my $self = shift;
95 0 0         if (@_) {
96 0 0         my $path = ref $_[0] eq 'ARRAY' ? $_[0] : [ $_[0] ];
97 0           $self->template->include_path($path);
98             }
99 0           $self->template->include_path;
100             }
101              
102             sub add_service {
103 0     0 0   my $self = shift;
104              
105 0           my($name, $service);
106 0 0         if (@_ == 2) {
107 0           ($name, $service) = @_;
108             } else {
109 0           $service = shift;
110 0           $name = $self->_service_name_for($service);
111             }
112              
113 0           $service->application($self);
114 0           $service->start;
115 0           $self->_services->{$name} = $service;
116             }
117              
118             sub service {
119 0     0 0   my($self, $name) = @_;
120 0           $self->_services->{$name};
121             }
122              
123             sub services {
124 0     0 0   my $self = shift;
125 0           values %{$self->_services};
  0            
126             }
127              
128             sub _service_name_for {
129 0     0     my($self, $service) = @_;
130              
131 0           my $ref = ref $service;
132 0           $ref =~ s/^Tatsumaki::Service:://;
133              
134 0           my $name = $ref;
135              
136 0           my $i = 0;
137 0           while (exists $self->_services->{$name}) {
138 0           $name = $ref . $i++;
139             }
140              
141 0           return $name;
142             }
143              
144 4     4   4655 no Any::Moose;
  4         9  
  4         43  
145             __PACKAGE__->meta->make_immutable;
146              
147             1;
148              
149