fix nascent bug in bloggery.cgi
[catagits/Web-Simple.git] / examples / bloggery / bloggery.cgi
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
29 sub map {
30   my ($self, $code) = @_;
31   map $code->($_), $self->all;
32 }
33
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>,
146       $data->map(sub {
147         my $path = '/'.$_->name.'.html';
148         <li>,
149           <h4>, <a href="$path">, $_->title, </a>, </h4>,
150           <span class="summary">, $_->summary_html, </span>,
151         </li>;
152       }),
153     </ul>;
154   } else {
155     <h2>, "Don't know how to render $data", </h2>;
156   }
157 }
158
159 Bloggery->run_if_script;