File Coverage

blib/lib/App/AutoCRUD/Context.pm
Criterion Covered Total %
statement 66 68 97.0
branch 14 18 77.7
condition 4 6 66.6
subroutine 17 17 100.0
pod 0 2 0.0
total 101 111 90.9


line stmt bran cond sub pod time code
1             package App::AutoCRUD::Context;
2              
3 1     1   396 use 5.010;
  1         2  
  1         28  
4 1     1   3 use strict;
  1         1  
  1         30  
5 1     1   4 use warnings;
  1         1  
  1         22  
6              
7 1     1   3 use Moose;
  1         1  
  1         7  
8 1     1   6331 use MooseX::SemiAffordanceAccessor; # writer methods as "set_*"
  1         5993  
  1         4  
9 1     1   5335 use Carp;
  1         1  
  1         56  
10 1     1   5 use Scalar::Does qw/does/;
  1         1  
  1         7  
11 1     1   283 use Encode ();
  1         2  
  1         20  
12              
13 1     1   3 use namespace::clean -except => 'meta';
  1         1  
  1         3  
14              
15              
16             has 'app' => (is => 'ro', isa => 'App::AutoCRUD', required => 1,
17             handles => [qw/config dir/]);
18             has 'req' => (is => 'ro', isa => 'Plack::Request', required => 1,
19             handles => [qw/logger/]);
20             has 'req_data' => (is => 'ro', isa => 'HashRef',
21             builder => '_req_data', lazy => 1, init_arg => undef);
22             has 'base' => (is => 'ro', isa => 'Str',
23             builder => '_base', lazy => 1, init_arg => undef);
24             has 'path' => (is => 'rw', isa => 'Str',
25             builder => '_path', lazy => 1);
26             has 'template' => (is => 'rw', isa => 'Str');
27             has 'view' => (is => 'rw', isa => 'App::AutoCRUD::View',
28             builder => '_view', lazy => 1);
29             has 'process_time' => (is => 'rw', isa => 'Num');
30              
31             has 'datasource' => (is => 'rw', isa => 'App::AutoCRUD::DataSource',
32             handles => [qw/dbh schema/]);
33             has 'title' => (is => 'rw', isa => 'Str',
34             builder => '_title', lazy => 1);
35              
36              
37             sub _view {
38 8     8   10 my $self = shift;
39              
40             # default view, if no specific view was required from the URL
41 8         179 return $self->app->find_class("View::TT")->new;
42             }
43              
44              
45             sub _req_data {
46 11     11   23 my $self = shift;
47              
48 11         637 require CGI::Expand;
49 11         1298 my $req_data = CGI::Expand->expand_cgi($self->req);
50 11         4378 _decode_utf8($req_data);
51 11         455 return $req_data;
52             }
53              
54             sub _base {
55 8     8   12 my $self = shift;
56              
57 8         200 my $base = $self->req->base->as_string;
58 8 50       1670 $base .= "/" unless $base =~ m[/$]; # force trailing slash
59 8         251 return $base
60             }
61              
62             sub _path {
63 17     17   25 my $self = shift;
64              
65 17         413 return $self->req->path;
66             }
67              
68             sub _title {
69 17     17   26 my $self = shift;
70              
71 17         389 my $title = $self->app->name;
72 17         420 my $datasource = $self->datasource;
73 17 100       436 $title .= "-" . $datasource->name if $datasource;
74              
75 17         379 return $title;
76             }
77              
78              
79             sub extract_path_segments {
80 54     54 0 76 my ($self, $n_segments) = @_;
81              
82             # check argument
83 54 50       116 $n_segments >= 0 or croak "illegal n_segments: $n_segments";
84 54 50 66     218 $n_segments < 2 or wantarray or croak "n_segments too big for scalar context";
85              
86             # extract segments
87 54         1231 my $path = $self->path;
88 54         81 my @segments;
89 54   66     414 while ($n_segments-- && $path =~ s[^/([^/]*)][]) {
90 69         220 push @segments, $1;
91             }
92              
93             # inject remaining path (without segments) back into context
94 54         1356 $self->set_path($path);
95              
96             # contextual return
97 54 100       314 return wantarray ? @segments : $segments[0];
98             }
99              
100              
101              
102             sub maybe_set_view_from_path {
103 17     17 0 30 my $self = shift;
104              
105 17         426 my $path = $self->path;
106 17 100       79 if ($path =~ s/\.(\w+)$//) { # e.g. /TABLE/foo/list.yaml?...
107 4         11 my $requested_view = $1;
108 4         93 my $view_class = $self->app->find_class("View::".ucfirst $requested_view);
109 4 100       19 if ($view_class) {
110 3         29 $self->set_view($view_class->new);
111 3         82 $self->set_path($path);
112             };
113             }
114             }
115              
116             #======================================================================
117             # UTILITY FUNCTIONS
118             #======================================================================
119              
120              
121             sub _decode_utf8 {
122 24 50   24   119 if (does($_[0], 'ARRAY')) {
    100          
123 0         0 _decode_utf8($_) foreach @{$_[0]};
  0         0  
124             }
125             elsif (does($_[0], 'HASH')) {
126 17         590 _decode_utf8($_) foreach values %{$_[0]};
  17         77  
127             }
128             else {
129 7         193 $_[0] = Encode::decode_utf8($_[0], Encode::FB_CROAK);
130             }
131             }
132              
133              
134             1;
135              
136             __END__
137              
138             =head1 NAME
139              
140             App::AutoCRUD::Context - Context information for handling a single request
141              
142             =head1 DESCRIPTION
143              
144             An instance of this class holds a bag of information for serving a
145             single request. It is passed around for sharing information between
146             controllers and view; its lifetime ends when the response is sent.