[Catalyst-dev] Re: fixes to Advent calendar RSS and 3.pod

A. Pagaltzis pagaltzis at gmx.de
Fri Dec 8 22:37:12 GMT 2006


* Jonathan Rockway <jon at jrock.us> [2006-12-08 19:15]:
> A. Pagaltzis wrote:
> >* Jonathan Rockway <jon at jrock.us> [2006-12-03 12:40]:
> >>first revision converts RSS2 -> Atom,
> >
> >Uhm, why are you generating the long-deprecated Atom 0.3
> >format?
> 
> Because XML::Feed only lets you specify "Atom" or "RSS".

Hmm, are you using an old version? According to the changelog,
the latest emits Atom 1.0 by default.

> In the latest svn version of the calendar, I switched to
> XML::Atom::SimpleFeed like I should have done originally :)

That’s another option. ;-)

> One irritation, though, is that you can't set the feed updated
> time after new(). Unfortunately, I don't know what time to use
> for updated until I iterate over the items and add them to the
> feed. (So for now, updated is set to the default.)

The API is kinda crappy; don’t blame me, wasn’t my design. ;-)

Noted.

Looking at your code and the revision log I also see another
issue: API clients shouldn’t be forced to format timestamps on
their own. There should be shortcuts for just passing in
a timestamp and leaving formatting to the module.

/me scribbles notes

> >Further critique: right now, what I see is a completely
> >useless title (“Calendar entry for day $d.”) with the article
> >title being sent as the entry’s full content. What’s in
> >atom:content *isn’t* the entry content. It should be in
> >atom:summary at minimum. In fact, it should be in the title.
> 
> Fixed. The title is the first paragraph, and the content is the
> full XHTML body of the POD. Also, the first author's name is
> extracted from an AUTHOR section. (I could parse out more
> metadata [e-mail and other authors], but I'm lazy so I didn't.
> Patches welcome.)

Attached. This version uses the first =HEAD1 as the title and the
first paragraph as the summary, and pulls out the email.

> >Who requested not to send fulltext and why? (If it’s
> >bandwidth: you can easily avoid 95% of the traffic if you add
> >support for conditional GET.
> 
> Dunno, but I like fulltext and nobody on IRC objected this
> time. The svn version does fulltext; hopefully someone will
> push that to the site Real Soon Now.

OK, but without conditional GET, that’s going to be a bit of
a drain on bandwidth. I added support; see patch. This is the
first time I actually write such code myself; I hope it works.
:-)

> >Right now, the feed is pretty useless to me.
> 
> Agreed, so now it's fixed :)

Much better already – thanks!

Regards,
-- 
Aristotle Pagaltzis // <http://plasmasturm.org/>
-------------- next part --------------
Index: lib/CatalystAdvent/Controller/Calendar.pm
===================================================================
--- lib/CatalystAdvent/Controller/Calendar.pm	(revision 5730)
+++ lib/CatalystAdvent/Controller/Calendar.pm	(working copy)
@@ -10,6 +10,7 @@
 use File::stat;
 use XML::Atom::SimpleFeed;
 use POSIX qw(strftime);
+use List::Util qw(max);
 use CatalystAdvent::Pod;
 
 =head1 NAME
@@ -108,52 +109,72 @@
     $c->res->redirect( $c->uri_for('/') )
         unless ( -e $c->path_to( 'root', $year ) );
 
-    my $feed = XML::Atom::SimpleFeed->new( title => "Catalyst Advent Calendar $year Feed",
-					   link  => $c->req->base,
-					   link  => {rel => 'self',
-						     href => $c->uri_for("/rss/$year")
-						    },
-					   id    => $c->uri_for("/rss/$year"),
-					 );
     $c->stash->{year} = $year;
-    my ( $day, $entries ) = ( 24, 0 );
-    my $feed_mtime = 0;
 
-    while ( $day > 0 && $entries < 5 ) {
-        if ( -e ( my $file = $c->path_to( 'root', $year, "$day.pod" ) ) ) {
-            my $stat   = stat $file;
-            my $mtime  = $stat->mtime;
-            my $ctime  = $stat->ctime;
-	    $feed_mtime= $mtime > $feed_mtime ? $mtime : $feed_mtime;
-	    my $parser = CatalystAdvent::Pod->new(
-						  StringMode   => 1,
-						  FragmentOnly => 1,
-						  MakeIndex    => 0,
-						  TopLinks     => 0
-						 );
-			      
-	    $parser->parse_from_file("$file");
-	    
-	    $feed->add_entry( title    => $parser->first_paragraph,
-			      author   => $parser->author,
-			      content  => {type => 'xhtml', content => $parser->asString},
-			      link     => $c->uri_for("/$year/$day"),
-			      id       => $c->uri_for("/$year/$day"),
-			      published=> format_date( $ctime ),
-			      updated  => format_date( $mtime ),
-			    );
-            $entries++;
+    my $feed;
+
+    my @entry = reverse 1 .. 24;
+    shift @entry until -e $c->path_to( 'root', $year, "$entry[ 0 ].pod" );
+    pop @entry while @entry > 5;
+
+    my %path = map +{ $_ => $c->path_to( 'root', $year, "$_.pod" ) }, @entry;
+    my %stat = map +{ $_ => stat $path{ $_ } }, @entry;
+    my $latest_mtime = max map $_->mtime, values %stat;
+    my $last_mod = format_date_rfc822( $latest_mtime );
+
+    $c->res->header( 'Last-Modified' => $last_mod );
+    $c->res->header( 'ETag' => qq'"$last_mod"' );
+    $c->res->content_type( 'application/atom+xml' );
+
+    my $cond_date = $c->req->header( 'If-Modified-Since' );
+    my $cond_etag = $c->req->header( 'If-None-Match' );
+    if( $cond_date or $cond_etag ) {
+        # if both headers are present, both must match
+        my $do_send_304 = 1;
+        if( $cond_date ) { $do_send_304 = $cond_date eq $last_mod }
+        if( $cond_etag ) { $do_send_304 &&= $cond_etag eq qq'"$last_mod"' }
+        if( $do_send_304 ) {
+            $c->res->status( 304 );
+            return;
         }
-        $day--;
     }
-    $c->res->body( $feed->as_string);
-    $c->res->content_type('application/atom+xml');
-}
 
-sub format_date {
-    return strftime('%Y-%m-%dT%H:%M:%SZ', gmtime($_[0]));
+    my $feed = XML::Atom::SimpleFeed->new(
+        title   => "Catalyst Advent Calendar $year",
+        link    => $c->req->base,
+        link    => { rel => 'self', href => $c->uri_for("/rss/$year") },
+        id      => $c->uri_for("/rss/$year"),
+        updated => format_date_w3cdtf( $latest_mtime ),
+    );
+
+    for my $day ( @entry ) {
+        my $parser = CatalystAdvent::Pod->new(
+            StringMode   => 1,
+            FragmentOnly => 1,
+            MakeIndex    => 0,
+            TopLinks     => 0
+        );
+
+        $parser->parse_from_file( $path{ $day } );
+
+        $feed->add_entry(
+            title    => { type => 'text', content => $parser->title },
+            summary  => { type => 'text', content => $parser->summary },
+            content  => { type => 'xhtml', content => $parser->asString },
+            author   => { name => $parser->author, email => $parser->email },
+            link     => $c->uri_for( "/$year/$day" ),
+            id       => $c->uri_for( "/$year/$day" ),
+            published=> format_date_w3cdtf( $stat{ $day }->ctime ),
+            updated  => format_date_w3cdtf( $stat{ $day }->mtime ),
+        );
+    }
+
+    $c->res->body( $feed->as_string );
 }
 
+sub format_date_w3cdtf { strftime '%Y-%m-%dT%H:%M:%SZ', gmtime $_[0] }
+sub format_date_rfc822 { strftime '%a, %d %b  %Y %H:%M:%S +0000', gmtime $_[0] }
+
 =head1 AUTHORS
 
 Brian Cassidy, <bricas at cpan.org>
Index: lib/CatalystAdvent/Pod.pm
===================================================================
--- lib/CatalystAdvent/Pod.pm	(revision 5730)
+++ lib/CatalystAdvent/Pod.pm	(working copy)
@@ -18,8 +18,8 @@
     $self->{_first_paragraph} ||= $text;
 
     if($self->{_in_author_block}){
-	$text =~ /((?:[\w.]+\s+)+)/;
-	$self->{_author} = $1;
+	$text =~ /((?:[\w.]+\s+)+)/ and $self->{_author} = $1;
+	$text =~ /<([^<>@\s]+@[^<>\s]+)>/ and $self->{_email} = $1;
 	$self->{_in_author_block} = 0; # not anymore
     }
 
@@ -29,14 +29,19 @@
 sub command {
     my $self = shift;
     my ($command, $paragraph, $pod_para) = @_;
+
+    $self->{_title} = $paragraph
+        if $command eq 'head1' and not defined $self->{_title};
     
     $self->{_in_author_block} = 1
-      if $paragraph =~ /AUTHOR/ && $command =~ /^head/;
+        if $command =~ /^head/ and $paragraph =~ /AUTHOR/;
 
     return $self->SUPER::command(@_);
 }
 
-sub first_paragraph { return $_[0]->{_first_paragraph} }
-sub author { return $_[0]->{_author} };
+sub title   { $_[0]->{_title} }
+sub summary { $_[0]->{_first_paragraph} }
+sub author  { $_[0]->{_author} }
+sub email   { $_[0]->{_email} }
 1;
 


More information about the Catalyst-dev mailing list