Commit | Line | Data |
5c33dda5 |
1 | use FindBin; |
2 | use lib $FindBin::Bin.'/code'; |
3 | use Web::Simple 'Bloggery'; |
4 | |
5 | package Bloggery::PostList; |
6 | |
7 | use File::stat; |
8 | |
9 | sub from_dir { |
10 | my ($class, $dir) = @_; |
11 | bless ({ dir => $dir }, $class); |
12 | } |
13 | |
14 | sub all { |
15 | my ($self) = @_; |
16 | map { Bloggery::Post->from_file($_) } |
17 | sort { stat($a)->mtime <=> stat($b)->mtime } |
18 | grep { !/\.summary\.html$/ } |
19 | glob($self->{dir}.'/*.html'); |
20 | } |
21 | |
22 | sub post { |
23 | my ($self, $name) = @_; |
24 | my $file = $self->{dir}."/${name}.html"; |
25 | return unless $file && -f $file; |
26 | return Bloggery::Post->from_file($file); |
27 | } |
28 | |
d2a1d0c7 |
29 | sub map { |
30 | my ($self, $code) = @_; |
31 | map $code->($_), $self->all; |
32 | } |
33 | |
5c33dda5 |
34 | package Bloggery::Post; |
35 | |
36 | sub from_file { |
37 | my ($class, $file) = @_; |
38 | bless({ file => $file }, $class); |
39 | } |
40 | |
41 | sub name { |
42 | my $name = shift->{file}; |
43 | $name =~ s/.*\///; |
44 | $name =~ s/\.html$//; |
45 | $name; |
46 | } |
47 | |
48 | sub title { |
49 | my $title = shift->name; |
50 | $title =~ s/-/ /g; |
51 | $title; |
52 | } |
53 | |
54 | sub html { |
55 | \do { local (@ARGV, $/) = shift->{file}; <> }; |
56 | } |
57 | |
58 | sub summary_html { |
59 | my $file = shift->{file}; |
60 | $file =~ s/\.html$/.summary.html/; |
61 | return \'<p>No summary</p>' unless -f $file; |
62 | \do { local (@ARGV, $/) = $file; <> }; |
63 | } |
64 | |
65 | package Bloggery; |
66 | |
67 | default_config( |
68 | title => 'Bloggery', |
69 | posts_dir => $FindBin::Bin.'/posts', |
70 | ); |
71 | |
72 | sub post_list { |
73 | my ($self) = @_; |
74 | $self->{post_list} |
75 | ||= Bloggery::PostList->from_dir( |
76 | $self->config->{posts_dir} |
77 | ); |
78 | } |
79 | |
80 | sub post { |
81 | my ($self, $post) = @_; |
82 | $self->post_list->post($post); |
83 | } |
84 | |
85 | dispatch [ |
86 | sub (.html) { |
87 | filter_response { $self->render_html($_[1]) }, |
88 | }, |
89 | sub (GET + /) { |
90 | $self->redispatch('index.html') |
91 | }, |
92 | sub (GET + /index) { |
93 | $self->post_list |
94 | }, |
95 | sub (GET + /*) { |
96 | $self->post($_[1]); |
97 | }, |
98 | sub (GET) { |
99 | [ 404, [ 'Content-type', 'text/plain' ], [ 'Not found' ] ] |
100 | }, |
101 | sub { |
102 | [ 405, [ 'Content-type', 'text/plain' ], [ 'Method not allowed' ] ] |
103 | }, |
104 | ]; |
105 | |
106 | sub render_html { |
107 | my ($self, $data) = @_; |
108 | use HTML::Tags; |
109 | return $data if ref($data) eq 'ARRAY'; |
110 | return [ |
111 | 200, |
112 | [ 'Content-type', 'text/html' ], |
113 | [ |
114 | HTML::Tags::to_html_string( |
115 | <html>, |
116 | <head>, |
117 | <title>, $self->title_for($data), </title>, |
118 | </head>, |
119 | <body>, |
120 | <h1>, $self->title_for($data), </h1>, |
121 | <div id="main">, |
122 | $self->main_html_for($data), |
123 | </div>, |
124 | </body>, |
125 | </html> |
126 | ) |
127 | ] |
128 | ]; |
129 | } |
130 | |
131 | sub title_for { |
132 | my ($self, $data) = @_; |
133 | if ($data->isa('Bloggery::Post')) { |
134 | return $data->title; |
135 | } |
136 | return $self->config->{title}; |
137 | } |
138 | |
139 | sub main_html_for { |
140 | my ($self, $data) = @_; |
141 | use HTML::Tags; |
142 | if ($data->isa('Bloggery::Post')) { |
143 | $data->html |
144 | } elsif ($data->isa('Bloggery::PostList')) { |
145 | <ul>, |
d2a1d0c7 |
146 | $data->map(sub { |
5c33dda5 |
147 | my $path = '/'.$_->name.'.html'; |
148 | <li>, |
149 | <h4>, <a href="$path">, $_->title, </a>, </h4>, |
150 | <span class="summary">, $_->summary_html, </span>, |
151 | </li>; |
d2a1d0c7 |
152 | }), |
5c33dda5 |
153 | </ul>; |
154 | } else { |
155 | <h2>, "Don't know how to render $data", </h2>; |
156 | } |
157 | } |
158 | |
159 | Bloggery->run_if_script; |