initial import of App::SCS code
[scpubgit/App-SCS.git] / lib / App / SCS / Page.pm
1 package App::SCS::Page;
2
3 use IO::All;
4 use Time::Local qw(timelocal);
5 use Data::Pond qw(pond_read_datum pond_write_datum);
6 use List::Util qw(reduce);
7 use Moo;
8
9 with 'App::SCS::Role::PageChildren';
10
11 has $_ => (is => 'ro') for qw(
12   title subtitle description keywords plugins html created path
13 );
14
15 has plugin_config => (is => 'lazy');
16
17 sub _build_plugin_config {
18   my ($self) = @_;
19   $self->plugins
20     ? pond_read_datum('[ '.$self->plugins.' ]')
21     : []
22 }
23
24 sub has_plugin_config { exists $_[0]->plugin_config->{$_[1]} }
25
26 sub with_plugin_config {
27   my ($self, $with_name, $with_config) = @_;
28   my @orig = @{$self->plugin_config};
29   my @new;
30   while (my ($name, $config) = splice @orig, 0, 2) {
31     push @new, (
32       $name eq $with_name
33         ? ($name, { %$config, %$with_config })
34         : ($name, $config)
35     );
36   }
37   return $self->with(plugins => pond_write_datum(\@new));
38 }
39
40 has _page_plugins => (is => 'lazy');
41
42 sub _build__page_plugins {
43   my ($self) = @_;
44   my $plugin_config = $self->plugin_config;
45   my ($plugin_map, $defaults) = @{$self->_page_set}{qw(plugin_map defaults)};
46
47   my @spec = (@$defaults, @$plugin_config);
48   my @plugins;
49   while (my ($name, $config) = splice @spec, 0, 2) {
50     my $info = $plugin_map->{$name};
51     push @plugins,
52       use_module($info->{class})->new(
53         %{$info->{config}||{}}, %$config, page => $self
54       );
55   }
56   return \@plugins;
57 }
58
59 sub published_at {
60   $_[0]->created
61     ? scalar localtime timelocal
62         map +(@{$_}[0..3], $_->[4]-1, $_->[5]-1900),
63           [ reverse split '\D+', $_[0]->created ]
64     : ''
65 }
66
67 has "_$_" => (is => 'ro', init_arg => $_) for qw(page_set);
68
69 sub _page_set_class { ref($_[0]->_page_set) }
70 sub _top_dir { $_[0]->_page_set->top_dir }
71 sub _my_path { io->dir($_[0]->_top_dir)->catdir($_[0]->path) }
72
73 sub to_app {
74   my ($self) = @_;
75   return sub { $self->to_psgi_response(@_) };
76 }
77
78 sub to_psgi_response {
79   my ($self, $env) = @_;
80
81   if (my $cb = $env->{'App::SCS::Command::Generate.extra_pages'}) {
82     $cb->($_->extra_pages) for @{$self->page_plugins};
83   }
84
85   $self->_psgi_response;
86 }
87
88 has _psgi_response => (is => 'lazy');
89
90 sub _build__psgi_response {
91   my ($self) = @_;
92
93   my @plugins = @{$self->page_plugins};
94
95   my $html_zoom = reduce {
96     $b->filter_html_zoom($a)
97   } HTML::Zoom->from_html($self->html), @plugins;
98
99   my $content_zoom = reduce {
100     $b->filter_content_zoom($a)
101   } $html_zoom, @plugins;
102
103   my $psgi_res = [
104     200, [ 'Content-type' => 'text/html' ], $content_zoom->to_fh
105   ];
106
107   return reduce {
108     $b->filter_psgi_response($a)
109   } $psgi_res, @plugins;
110 }
111
112 no Moo;
113
114 sub with {
115   my $self = shift;
116   return ref($self)->new(%$self, @_);
117 }
118
119 1;