File Coverage

blib/lib/App/AutoCRUD/Context.pm
Criterion Covered Total %
statement 65 67 97.0
branch 13 18 72.2
condition 4 6 66.6
subroutine 17 17 100.0
pod 0 2 0.0
total 99 110 90.0


line stmt bran cond sub pod time code
1             package App::AutoCRUD::Context;
2              
3 1     1   536 use 5.010;
  1         4  
4 1     1   7 use strict;
  1         2  
  1         22  
5 1     1   5 use warnings;
  1         2  
  1         24  
6              
7 1     1   5 use Moose;
  1         3  
  1         11  
8 1     1   8129 use MooseX::SemiAffordanceAccessor; # writer methods as "set_*"
  1         7582  
  1         4  
9 1     1   8513 use Carp;
  1         2  
  1         63  
10 1     1   7 use Scalar::Does qw/does/;
  1         2  
  1         10  
11 1     1   458 use Encode ();
  1         3  
  1         29  
12              
13 1     1   6 use namespace::clean -except => 'meta';
  1         2  
  1         5  
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 7     7   16 my $self = shift;
39              
40             # default view, if no specific view was required from the URL
41 7         186 return $self->app->find_class("View::TT")->new;
42             }
43              
44              
45             sub _req_data {
46 10     10   22 my $self = shift;
47              
48 10         715 require CGI::Expand;
49 10         1625 my $req_data = CGI::Expand->expand_cgi($self->req);
50 10         5093 _decode_utf8($req_data);
51 10         377 return $req_data;
52             }
53              
54             sub _base {
55 7     7   19 my $self = shift;
56              
57 7         211 my $base = $self->req->base->as_string;
58 7 50       2132 $base .= "/" unless $base =~ m[/$]; # force trailing slash
59 7         236 return $base
60             }
61              
62             sub _path {
63 17     17   36 my $self = shift;
64              
65 17         455 return $self->req->path;
66             }
67              
68             sub _title {
69 17     17   40 my $self = shift;
70              
71 17         459 my $title = $self->app->name;
72 17         505 my $datasource = $self->datasource;
73 17 100       486 $title .= "-" . $datasource->name if $datasource;
74              
75 17         465 return $title;
76             }
77              
78              
79             sub extract_path_segments {
80 54     54 0 127 my ($self, $n_segments) = @_;
81              
82             # check argument
83 54 50       139 $n_segments >= 0 or croak "illegal n_segments: $n_segments";
84 54 50 66     217 $n_segments < 2 or wantarray or croak "n_segments too big for scalar context";
85              
86             # extract segments
87 54         1447 my $path = $self->path;
88 54         126 my @segments;
89 54   66     420 while ($n_segments-- && $path =~ s[^/([^/]*)][]) {
90 69         299 push @segments, $1;
91             }
92              
93             # inject remaining path (without segments) back into context
94 54         1638 $self->set_path($path);
95              
96             # contextual return
97 54 100       365 return wantarray ? @segments : $segments[0];
98             }
99              
100              
101              
102             sub maybe_set_view_from_path {
103 17     17 0 37 my $self = shift;
104              
105 17         476 my $path = $self->path;
106 17 100       90 if ($path =~ s/\.(\w+)$//) { # e.g. /TABLE/foo/list.yaml?...
107 4         14 my $requested_view = $1;
108 4         114 my $view_class = $self->app->find_class("View::".ucfirst $requested_view);
109 4 50       23 if ($view_class) {
110 4         38 $self->set_view($view_class->new);
111 4         134 $self->set_path($path);
112             };
113             }
114             }
115              
116             #======================================================================
117             # UTILITY FUNCTIONS
118             #======================================================================
119              
120              
121             sub _decode_utf8 {
122 23 50   23   104 if (does($_[0], 'ARRAY')) {
    100          
123 0         0 _decode_utf8($_) foreach @{$_[0]};
  0         0  
124             }
125             elsif (does($_[0], 'HASH')) {
126 16         852 _decode_utf8($_) foreach values %{$_[0]};
  16         73  
127             }
128             else {
129 7         318 $_[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.