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