File Coverage

blib/lib/Nephia/Core.pm
Criterion Covered Total %
statement 135 135 100.0
branch 22 26 84.6
condition 8 12 66.6
subroutine 31 31 100.0
pod 9 11 81.8
total 205 215 95.3


line stmt bran cond sub pod time code
1             package Nephia::Core;
2 11     11   442177 use strict;
  11         112  
  11         399  
3 11     11   60 use warnings;
  11         21  
  11         339  
4 11     11   9045 use Nephia::Request;
  11         58  
  11         332  
5 11     11   29901 use Nephia::Response;
  11         34  
  11         299  
6 11     11   5551 use Nephia::Context;
  11         26  
  11         290  
7 11     11   5975 use Nephia::Chain;
  11         29  
  11         286  
8 11     11   105 use Scalar::Util ();
  11         18  
  11         172  
9 11     11   13311 use Module::Load ();
  11         13434  
  11         3776  
10              
11             our $AUTOLOAD;
12              
13             sub AUTOLOAD {
14 3     3   32 my $self = shift;
15 3         23 my ($class, $method) = $AUTOLOAD =~ /^(.+)::(.+?)$/;
16 3 50       15 return if $method =~ /^[A-Z]/;
17 3         31 $self->{dsl}{$method}->(@_);
18             }
19              
20             sub new {
21 19     19 0 18225 my ($class, %opts) = @_;
22 19   66     131 $opts{caller} ||= caller();
23 19   100     246 $opts{plugins} ||= [];
24 19   50     123 $opts{config} ||= {};
25 19         139 $opts{action_chain} = Nephia::Chain->new(namespace => 'Nephia::Action');
26 19         83 $opts{filter_chain} = Nephia::Chain->new(namespace => 'Nephia::Filter');
27 19         79 $opts{builder_chain} = Nephia::Chain->new(namespace => 'Nephia::Builder');
28 19         81 $opts{loaded_plugins} = Nephia::Chain->new(namespace => 'Nephia::Plugin', name_normalize => 0);
29 19         59 $opts{dsl} = {};
30 19         48 $opts{external_classes} = {};
31 19         133 my $self = bless {%opts}, $class;
32 19         85 $self->action_chain->append(Core => $class->can('_action'));
33 19         76 $self->_load_plugins;
34 17         94 return $self;
35             }
36              
37             sub export_dsl {
38 7     7 1 721 my $self = shift;
39 7         55 my $dummy_context = Nephia::Context->new;
40 7         33 $self->_load_dsl($dummy_context);
41 7         29 my $class = $self->caller_class;
42 11     11   73 no strict qw/refs subs/;
  11         22  
  11         373  
43 11     11   55 no warnings qw/redefine/;
  11         21  
  11         9236  
44 7     1   29 *{$class.'::run'} = sub (;%) { my $subclass = shift; $self->run(@_) };
  7         52  
  1         10  
  1         5  
45 7         46 *{$class.'::app'} = sub (&) {
46 1     1   10 my $app = shift;
47 1         5 $self->{app} = $app;
48 7         53 };
49             }
50              
51             sub _load_plugins {
52 19     19   34 my $self = shift;
53 19         35 my @plugins = (qw/Basic Cookie/, @{$self->{plugins}});
  19         69  
54 19         62 while ($plugins[0]) {
55 45         103 my $plugin_class = 'Nephia::Plugin::'. shift(@plugins);
56 45         78 my $conf = {};
57 45 100       108 if ($plugins[0]) {
58 28 100       91 $conf = shift(@plugins) if ref($plugins[0]) eq 'HASH';
59             }
60 45         118 $self->loaded_plugins->append($self->_load_plugin($plugin_class, $conf));
61             }
62             }
63              
64             sub loaded_plugins {
65 121     121 1 1341 my $self = shift;
66 121 100       693 return wantarray ? $self->{loaded_plugins}->as_array : $self->{loaded_plugins};
67             }
68              
69             sub _load_plugin {
70 45     45   82 my ($self, $plugin, $opts) = @_;
71 45   50     116 $opts ||= {};
72 45 100       539 Module::Load::load($plugin) unless $plugin->isa('Nephia::Plugin');
73 45         519 my $obj = $plugin->new(app => $self, %$opts);
74 43         163 return $obj;
75             }
76              
77             sub app {
78 20     20 1 39 my ($self, $code) = @_;
79 20 100       66 $self->{app} = $code if defined $code;
80 20         99 return $self->{app};
81             }
82              
83             sub caller_class {
84 40     40 1 733 my $self = shift;
85 40         141 return $self->{caller};
86             }
87              
88             sub action_chain {
89 60     60 1 88 my $self = shift;
90 60         530 return $self->{action_chain};
91             }
92              
93             sub filter_chain {
94 3     3 1 7 my $self = shift;
95 3         20 return $self->{filter_chain};
96             }
97              
98             sub builder_chain {
99 16     16 1 29 my $self = shift;
100 16         81 return $self->{builder_chain};
101             }
102              
103             sub _action {
104 17     17   40 my ($self, $context) = @_;
105 17         83 $context->set(res => $self->app->($self, $context));
106 17         65 return $context;
107             }
108              
109             sub dsl {
110 3     3 1 11 my ($self, $key) = @_;
111 3 100       25 return $key ? $self->{dsl}{$key} : $self->{dsl};
112             }
113              
114             sub call {
115 3     3 0 13 my ($self, $codepath) = @_;
116 3         24 my ($class, $method) = $codepath =~ /^(.+)\#(.+)$/;
117 3 100       19 $class = sprintf('%s::%s', $self->caller_class, $class) unless $class =~ /^\+/;
118 3         10 $class =~ s/^\+//;
119 3 50       13 unless ($self->{external_classes}{$class}) {
120 3 50       42 Module::Load::load($class) unless $class->isa($class);
121 3         7 $self->{external_classes}{$class} = 1;
122             }
123 3         25 $class->can($method);
124             }
125              
126             sub _load_dsl {
127 24     24   53 my ($self, $context) = @_;
128 24         85 my $class = $self->caller_class;
129 11     11   67 no strict qw/refs subs/;
  11         19  
  11         379  
130 11     11   59 no warnings qw/redefine/;
  11         44  
  11         4758  
131 24         88 for my $plugin ( $self->loaded_plugins->as_array ) {
132 53         288 for my $dsl ($plugin->exports) {
133 98         359 *{$class.'::'.$dsl} = $plugin->$dsl($context);
  98         571  
134 98         309 $self->{dsl}{$dsl} = $plugin->$dsl($context);
135             }
136             }
137             }
138              
139             sub run {
140 15     15 1 3531 my ($self, %config) = @_;
141 15         28 $self->{config} = { %{$self->{config}}, %config };
  15         61  
142 15         42 my $class = $self->{caller};
143             my $app = sub {
144 17     17   406457 my $env = shift;
145 17         1326 my $req = Nephia::Request->new($env);
146 17         290 my $context = Nephia::Context->new(req => $req, config => $self->{config});
147 17         78 $self->_load_dsl($context);
148 17         120 my $res;
149 17         87 for my $action ($self->{action_chain}->as_array) {
150 55         170 ($context, $res) = $action->($self, $context);
151 55 100       255 last if $res;
152             }
153 17   66     103 $res ||= $context->get('res');
154 17 100       95 $res = Scalar::Util::blessed($res) ? $res : Nephia::Response->new(@$res);
155 17         126 for my $filter ($self->{filter_chain}->as_array) {
156 2 50       7 my $body = ref($res->body) eq 'ARRAY' ? $res->body->[0] : $res->body;
157 2         47 $res->body($filter->($self, $body));
158             }
159 17         147 return $res->finalize;
160 15         107 };
161 15         57 for my $builder ($self->builder_chain->as_array) {
162 1         4 $app = $builder->($self, $app);
163             }
164 15         2710 return $app;
165             }
166              
167             1;
168              
169             __END__