return to $self by following the upgrade instructions in the docs
[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 sub map {
32   my ($self, $code) = @_;
33   map $code->($_), $self->all;
34 }
35
36 package Bloggery::Post;
37
38 sub from_file {
39   my ($class, $file) = @_;
40   bless({ file => $file }, $class);
41 }
42
43 sub name {
44   my $name = shift->{file};
45   $name =~ s/.*\///;
46   $name =~ s/\.html$//;
47   $name;
48 }
49
50 sub title {
51   my $title = shift->name;
52   $title =~ s/-/ /g;
53   $title;
54 }
55
56 sub html {
57   \do { local (@ARGV, $/) = shift->{file}; <> };
58 }
59
60 sub summary_html {
61   my $file = shift->{file};
62   $file =~ s/\.html$/.summary.html/;
63   return \'<p>No summary</p>' unless -f $file;
64   \do { local (@ARGV, $/) = $file; <> };
65 }
66
67 package Bloggery;
68
69 default_config(
70   title => 'Bloggery',
71   posts_dir => $FindBin::Bin.'/posts',
72 );
73
74 sub post_list {
75   my ($self) = @_;
76   $self->{post_list}
77     ||= Bloggery::PostList->from_dir(
78           $self->config->{posts_dir}
79         );
80 }
81
82 sub post {
83   my ($self, $post) = @_;
84   $self->post_list->post($post);
85 }
86
87 sub dispatch_request {
88   my $self = shift;
89   sub (GET + /) {
90     redispatch_to '/index.html';
91   },
92   sub (.html) {
93     response_filter { $self->render_html($_[1]) },
94   },
95   sub (GET + /index) {
96     $self->post_list
97   },
98   sub (GET + /*) {
99     $self->post($_[1])
100   },
101   sub (GET) {
102     [ 404, [ 'Content-type', 'text/plain' ], [ 'Not found' ] ]
103   },
104   sub {
105     [ 405, [ 'Content-type', 'text/plain' ], [ 'Method not allowed' ] ]
106   },
107 };
108
109 sub render_html {
110   my ($self, $data) = @_;
111   use HTML::Tags;
112   return $data if ref($data) eq 'ARRAY';
113   return [
114     200,
115     [ 'Content-type', 'text/html' ],
116     [
117       HTML::Tags::to_html_string(
118         <html>,
119           <head>,
120             <title>, $self->title_for($data), </title>,
121           </head>,
122           <body>,
123             <h1>, $self->title_for($data), </h1>,
124             <div id="main">,
125               $self->main_html_for($data),
126             </div>,
127           </body>,
128         </html>
129       )
130     ]
131   ];
132 }
133
134 sub title_for {
135   my ($self, $data) = @_;
136   if ($data->isa('Bloggery::Post')) {
137     return $data->title;
138   }
139   return $self->config->{title};
140 }
141
142 sub main_html_for {
143   my ($self, $data) = @_;
144   use HTML::Tags;
145   if ($data->isa('Bloggery::Post')) {
146     $data->html
147   } elsif ($data->isa('Bloggery::PostList')) {
148     <ul>,
149       $data->map(sub {
150         my $path = $_->name.'.html';
151         <li>,
152           <h4>, <a href="$path">, $_->title, </a>, </h4>,
153           <span class="summary">, $_->summary_html, </span>,
154         </li>;
155       }),
156     </ul>;
157   } else {
158     <h2>, "Don't know how to render $data", </h2>;
159   }
160 }
161
162 Bloggery->run_if_script;