Commit | Line | Data |
5cc6d9e2 |
1 | package SCSite; |
2 | |
3 | use IO::All; |
4 | use SCSite::PageSet; |
5 | use Web::Simple; |
6 | |
5cc6d9e2 |
7 | has pages => (is => 'lazy'); |
8 | |
ebd4c292 |
9 | has filters => (is => 'lazy'); |
10 | |
5cc6d9e2 |
11 | has _layout_zoom => (is => 'lazy'); |
12 | |
13 | sub default_config { |
14 | ( |
15 | pages_dir => 'share/content', |
16 | template_dir => 'share/skin', |
17 | ) |
18 | } |
19 | |
20 | sub _build_pages { |
21 | my ($self) = @_; |
ebd4c292 |
22 | SCSite::PageSet->new(base_dir => io->dir($self->config->{pages_dir})) |
23 | } |
24 | |
25 | sub _build_filters { |
26 | my ($self) = @_; |
27 | require SCSite::SubListFilter; |
28 | +{ SubList => SCSite::SubListFilter->new } |
5cc6d9e2 |
29 | } |
30 | |
31 | sub dispatch_request { |
32 | my $self = shift; |
33 | sub (/feed/**/) { |
34 | $self->_http_response(500 => 'text/plain' => 'Not implemented'); |
35 | }, |
36 | sub (/) { |
37 | $self->_page_http_response(200 => $self->_find_page('index')); |
38 | }, |
39 | sub (/**) { |
40 | [ 302, [ 'Location' => "/$_[1]/" ], [] ] |
41 | }, |
42 | sub (/**/) { |
43 | my ($code, $page) = map { |
44 | $_ ? (200, $_) : (404, $self->_error_page(404)) |
45 | } $self->_find_page($_[1]); |
46 | $self->_page_http_response($code => $page); |
47 | } |
48 | } |
49 | |
50 | sub _error_page { |
51 | my ($self, $code) = @_; |
52 | $self->_find_page("error_${code}"); |
53 | } |
54 | |
55 | sub _find_page { |
56 | my ($self, $path) = @_; |
57 | $self->pages->get({ path => $path }); |
58 | } |
59 | |
60 | sub _http_response { |
61 | my ($self, $code, $type, $content) = @_; |
62 | [ $code, [ 'Content-type' => $type ], [ $content ] ]; |
63 | } |
64 | |
65 | sub _page_http_response { |
66 | my ($self, $code, $page) = @_; |
67 | [ $code, [ 'Content-type' => 'text/html' ], $self->_render_page($page) ]; |
68 | } |
69 | |
70 | sub _render_page { |
71 | my ($self, $page) = @_; |
72 | my $zoom = $self->_layout_zoom; |
73 | $zoom->select('.title')->replace_content($page->title) |
74 | ->select('meta[name=description]')->replace_content($page->description) |
75 | ->select('meta[name=keywords]')->replace_content($page->keywords) |
5cc6d9e2 |
76 | ->select('.main')->replace_content(\$page->body) |
ebd4c292 |
77 | ->select('.SubList')->collect({ |
78 | filter => $self->filters->{SubList}->callback_for($page), |
79 | passthrough => 1, |
80 | }) |
5cc6d9e2 |
81 | ->to_fh |
82 | } |
83 | |
84 | sub _build__layout_zoom { |
85 | my ($self) = @_; |
86 | HTML::Zoom->from_file( |
87 | io->dir($self->config->{template_dir})->catfile('layout.html') |
88 | )->memoize; |
89 | } |
90 | |
91 | sub run_if_script { |
92 | return $_[0]->to_psgi_app if caller(1); |
93 | my $class = shift; |
94 | my @config_keys = keys %{{$class->default_config}}; |
95 | require Getopt::Long; |
96 | my %config; |
97 | Getopt::Long::GetOptions( |
98 | map +("$_=s" => \$config{$_}), @config_keys |
99 | ); |
100 | delete $config{$_} for grep !defined($config{$_}), keys %config; |
101 | my $new = $class->new(config => \%config); |
102 | $new->run(@_) |
103 | } |
104 | |
105 | __PACKAGE__->run_if_script; |