Load XML-Feed-0.12 into trunk. v0.12
Simon Wistow [Tue, 22 Apr 2008 18:01:00 +0000 (18:01 +0000)]
Changes
MANIFEST
META.yml
lib/XML/Feed.pm
lib/XML/Feed/Atom.pm
t/04-splice.t
t/06-atom10.t [new file with mode: 0644]
t/07-atom10-create.t [new file with mode: 0644]
t/samples/atom-full.xml [new file with mode: 0644]

diff --git a/Changes b/Changes
index 1ee7ede..f3114f2 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,7 +1,11 @@
-# $Id: Changes 1956 2006-08-08 04:34:54Z btrott $
+# $Id: Changes 1958 2006-08-14 05:31:27Z btrott $
 
 Revision history for XML::Feed
 
+0.12  2006.08.13
+    - Generate Atom 1.0 feeds by default. Thanks to Tatsuhiko Miyagawa for
+      the patch.
+
 0.11  2006.08.07
     - Fixed a bug in XML::Feed::Atom where entry->link and feed->link didn't
       return the proper link element if the "rel" attribute wasn't defined for
index 71baa1d..b89f42d 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -30,7 +30,10 @@ t/01-parse.t
 t/02-create.t
 t/04-splice.t
 t/05-atom10-link.t
+t/06-atom10.t
+t/07-atom10-create.t
 t/samples/atom-10-example.xml
+t/samples/atom-full.xml
 t/samples/atom.xml
 t/samples/rss10-invalid-date.xml
 t/samples/rss10.xml
index 5cdbf06..8c1946c 100644 (file)
--- a/META.yml
+++ b/META.yml
@@ -23,4 +23,4 @@ requires:
   URI::Fetch: 0
   XML::Atom: 0.08
   XML::RSS: 1.01
-version: 0.11
+version: 0.12
index a84ca92..359730e 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Feed.pm 1956 2006-08-08 04:34:54Z btrott $
+# $Id: Feed.pm 1958 2006-08-14 05:31:27Z btrott $
 
 package XML::Feed;
 use strict;
@@ -8,7 +8,7 @@ use Feed::Find;
 use URI::Fetch;
 use Carp;
 
-our $VERSION = '0.11';
+our $VERSION = '0.12';
 
 sub new {
     my $class = shift;
index 29fc2b0..135e367 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Atom.pm 1955 2006-08-02 05:59:58Z btrott $
+# $Id: Atom.pm 1958 2006-08-14 05:31:27Z btrott $
 
 package XML::Feed::Atom;
 use strict;
@@ -11,7 +11,7 @@ use DateTime::Format::W3CDTF;
 
 sub init_empty {
     my $feed = shift;
-    $feed->{atom} = XML::Atom::Feed->new;
+    $feed->{atom} = XML::Atom::Feed->new(Version => 1.0);
     $feed;
 }
 
@@ -46,7 +46,7 @@ sub generator   { shift->{atom}->generator(@_) }
 sub author {
     my $feed = shift;
     if (@_ && $_[0]) {
-        my $person = XML::Atom::Person->new;
+        my $person = XML::Atom::Person->new(Version => 1.0);
         $person->name($_[0]);
         $feed->{atom}->author($person);
     } else {
@@ -59,15 +59,16 @@ sub modified {
     if (@_) {
         $feed->{atom}->modified(DateTime::Format::W3CDTF->format_datetime($_[0]));
     } else {
-        iso2dt($feed->{atom}->modified);
+        $feed->{atom}->modified ? iso2dt($feed->{atom}->modified) : undef;
     }
 }
 
-sub entries { 
+sub entries {
     my @entries;
     for my $entry ($_[0]->{atom}->entries) {
         push @entries, XML::Feed::Entry::Atom->wrap($entry);
     }
+
     @entries;
 }
 
@@ -90,7 +91,7 @@ use List::Util qw( first );
 
 sub init_empty {
     my $entry = shift;
-    $entry->{entry} = XML::Atom::Entry->new;
+    $entry->{entry} = XML::Atom::Entry->new(Version => 1.0);
     1;
 }
 
@@ -112,7 +113,7 @@ sub summary {
         $entry->{entry}->summary(ref($_[0]) eq 'XML::Feed::Content' ?
             $_[0]->body : $_[0]);
     } else {
-        XML::Feed::Content->wrap({ type => 'text/html',
+        XML::Feed::Content->wrap({ type => 'html',
                                    body => $entry->{entry}->summary });
     }
 }
@@ -122,14 +123,22 @@ sub content {
     if (@_) {
         my %param;
         if (ref($_[0]) eq 'XML::Feed::Content') {
-            %param = (Body => $_[0]->body, Type => $_[0]->type || 'text/html');
+            %param = (Body => $_[0]->body);
         } else {
-            %param = (Body => $_[0], Type => 'text/html');
+            %param = (Body => $_[0]);
         }
-        $entry->{entry}->content(XML::Atom::Content->new(%param));
+        $entry->{entry}->content(XML::Atom::Content->new(%param, Version => 1.0));
     } else {
         my $c = $entry->{entry}->content;
-        XML::Feed::Content->wrap({ type => $c ? $c->type : undef,
+
+        # map Atom types to MIME types
+        my $type = $c ? $c->type : undef;
+        if ($type) {
+            $type = 'text/html'  if $type eq 'xhtml' || $type eq 'html';
+            $type = 'text/plain' if $type eq 'text';
+        }
+
+        XML::Feed::Content->wrap({ type => $type,
                                    body => $c ? $c->body : undef });
     }
 }
@@ -138,16 +147,17 @@ sub category {
     my $entry = shift;
     my $ns = XML::Atom::Namespace->new(dc => 'http://purl.org/dc/elements/1.1/');
     if (@_) {
-        $entry->{entry}->set($ns, 'subject', $_[0]);
+        $entry->{entry}->add_category({ term => $_[0] });
     } else {
-        $entry->{entry}->get($ns, 'subject');
+        my $category = $entry->{entry}->category;
+        $category ? ($category->label || $category->term) : $entry->{entry}->get($ns, 'subject');
     }
 }
 
 sub author {
     my $entry = shift;
     if (@_ && $_[0]) {
-        my $person = XML::Atom::Person->new;
+        my $person = XML::Atom::Person->new(Version => 1.0);
         $person->name($_[0]);
         $entry->{entry}->author($person);
     } else {
index f980d57..21f7a5e 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: 04-splice.t 1872 2005-08-12 04:28:42Z btrott $
+# $Id: 04-splice.t 1958 2006-08-14 05:31:27Z btrott $
 
 use strict;
 use Test::More tests => 3;
@@ -6,7 +6,7 @@ use XML::Feed;
 
 my $feed = XML::Feed->new('Atom');
 
-my $other = XML::Feed->parse('t/samples/atom.xml');
+my $other = XML::Feed->parse('t/samples/atom.xml')->convert('Atom');
 $feed->splice($other);
 is(scalar $feed->entries, 2, '2 entries in the feed after splicing');
 
diff --git a/t/06-atom10.t b/t/06-atom10.t
new file mode 100644 (file)
index 0000000..a509c57
--- /dev/null
@@ -0,0 +1,19 @@
+use strict;
+use XML::Feed;
+
+use Test::More;
+plan tests => 7;
+
+my $feed = XML::Feed->parse("t/samples/atom-full.xml");
+is $feed->title, 'Content Considered Harmful Atom Feed';
+is $feed->link, 'http://blog.jrock.us/', "link without rel";
+
+my $e = ($feed->entries)[0];
+ok $e->link, 'entry link without rel';
+is $e->category, "Catalyst", "atom:category support";
+is $e->modified, "2006-08-09T19:07:58", "atom:updated";
+is $e->content->type, 'text/html';
+like $e->content->body, qr/^<div class="pod">/;
+
+
+
diff --git a/t/07-atom10-create.t b/t/07-atom10-create.t
new file mode 100644 (file)
index 0000000..e5e4d57
--- /dev/null
@@ -0,0 +1,44 @@
+use strict;
+use Test::More;
+
+plan 'no_plan';
+
+use XML::Feed;
+
+my $feed = XML::Feed->new('Atom');
+$feed->title("foo");
+$feed->description("Atom 1.0 feed");
+$feed->link("http://example.org/");
+
+my $entry = XML::Feed::Entry->new('Atom');
+$entry->title("1st Entry");
+$entry->link("http://example.org/");
+$entry->category("blah");
+$entry->content("<p>Hello world.</p>");
+
+$feed->add_entry($entry);
+
+my $xml = $feed->as_xml;
+like $xml, qr!<feed xmlns="http://www.w3.org/2005/Atom"!;
+like $xml, qr!<content .*type="xhtml">!;
+like $xml, qr!<div xmlns="http://www.w3.org/1999/xhtml">!;
+
+# roundtrip
+$feed = XML::Feed->parse(\$xml);
+is $feed->format, 'Atom';
+is $feed->title, "foo";
+is $feed->description, "Atom 1.0 feed";
+is $feed->link, "http://example.org/";
+
+my @entries = $feed->entries;
+is @entries, 1;
+$entry = $entries[0];
+
+is $entry->title, '1st Entry';
+is $entry->link, 'http://example.org/';
+is $entry->category, 'blah';
+is $entry->content->type, 'text/html';
+like $entry->content->body, qr!\s*<p>Hello world.</p>\s*!s;
+
+
+
diff --git a/t/samples/atom-full.xml b/t/samples/atom-full.xml
new file mode 100644 (file)
index 0000000..c7fe4e7
--- /dev/null
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="us-ascii"?>
+<feed xmlns="http://www.w3.org/2005/Atom"><title>Content Considered Harmful Atom Feed</title><id>http://blog.jrock.us/</id><link href="http://blog.jrock.us/feeds/category/Catalyst/xml" rel="self"/><link href="http://blog.jrock.us/"/><subtitle type="html">This is Jonathan Rockway&#39;s Blog, quite possibily the best blog ever.
+Or something.
+</subtitle><generator uri="http://www.jrock.us/" version="0.01_01">AngerWhale</generator><updated>2006-08-10T02:43:00Z</updated><entry><title>Catalyst + Cache</title><author><name>Jonathan T. Rockway</name><email>jon@jrock.us</email></author><id>urn:guid:8D9B9CBE-27DB-11DB-B6C2-F007B8516AA5</id><link href="http://blog.jrock.us/articles/Catalyst%20+%20Cache.pod"/><category term="Catalyst" scheme="http://blog.jrock.us/categories/"/><updated>2006-08-09T19:07:58Z</updated><content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><div class="pod">
+<p>I recently posted this to the <cite>Template::Toolkit</cite> mailing list, but
+the moderator rejected it for some reason.  (Probably because <code>&lt;jon-perl-list-templates AT jrock.us&gt;</code> is the address that's
+subscribed, not <code>&lt;jon AT jrock.us&gt;</code>.)</p>
+<p>Anyway, here it is.  I will expand on this further with actual
+measurements, but this will have to do for now.</p>
+<h4 id="Original_Message">Original Message</h4>
+<div id="Original_Message_CONTENT">
+<p><i>Thank you, you raise a good point that I had not fully considered.  My
+goal is to display a dynamically generated page, but where most of the
+&quot;dynamic&quot; content is actually static for a period amount of time.
+(Take a news page, for example, where the list of news stories updates
+once an hour.)</i></p>
+
+</div>
+<h4 id="My_Reply">My Reply</h4>
+<div id="My_Reply_CONTENT">
+<p>I have a similar problem with my blogging software.  Most of the content
+is static, and it's kind of a waste to regenerate everything every time
+someone views the page.  My solution to this problem is to use a
+<cite>Cache::FastMmap</cite> object to store the formatted HTML content of each post,
+keyed on the source material's MD5sum (and filetype, for reasons not
+relevant to this discussion  :) </p>
+<p>This results in a nice speedup, since certain HTML filters are slow
+(OO.org document -&gt; HTML, for example).</p>
+<p>I also cache full pages, after they've been assembled by TT, keyed on
+the md5sum of each included article and some metadata (comment count,
+tags, etc.)  The end result is a 5-20x speed up.  With Catalyst's
+embedded server, I can do about 5 requests per second without cache, but
+it goes up to about 40-50 requests/second with the cache.  So obviously
+a speedup.  (And I'm still not doing a very good job, this was just a 20
+minute hack!)</p>
+<p>For the gory details, check out the code here:</p>
+<p><a href="http://www.jrock.us/trac/blog_software/browser/lib/Blog/Controller/Root.pm#L105">http://www.jrock.us/trac/blog_software/browser/lib/Blog/Controller/Root.pm#L105</a>
+(page cache)</p>
+<p>and:
+<a href="http://www.jrock.us/trac/blog_software/browser/lib/Blog/Model/Filesystem/Item.pm#L355">http://www.jrock.us/trac/blog_software/browser/lib/Blog/Model/Filesystem/Item.pm#L355</a>
+(object cache)</p>
+
+
+
+
+<p>Another caching strategy is to set dynamic pages to be cachable for say,
+10 seconds, and then letting Apache's mod_cache (experimental in 2.2.3,
+but it works for me) do the hard work.  Your application gets hit once
+every ten seconds to refresh Apache's cache, but all the end-user
+requests are handled by serving from Apache's memory cache.  With
+mpm_worker, it's *super fast*, and a 10 second update delay isn't bad.</p>
+<p>If your application is really slow, this will let you increase your
+slashdot resistance factor (as I call it) enormously.  A quick ab
+against some cached content gave me a requests/per second rate of
+1638... much better than whatever your app would do by itself.</p>
+<p>And you don't really lose much by taking this approach, other than a 10
+second delay with your articles going live... but 10 seconds is nothing
+if you're getting 1500 requests per second and handling it with an old
+PIII  :) </p>
+<p>If this info is useful to anyone else, let me know (off-list) and I'll
+write up a more detailed article about it  :) </p>
+
+</div>
+</div></div></content></entry><entry><title>Quantum Physics and the Template Toolkit</title><author><name>Jonathan T. Rockway</name><email>jon@jrock.us</email></author><id>urn:guid:BB054AF0-2601-11DB-9738-946FBD312859</id><link href="http://blog.jrock.us/articles/Quantum%20Physics%20and%20the%20Template%20Toolkit.pod"/><category term="Catalyst" scheme="http://blog.jrock.us/categories/"/><category term="Programming" scheme="http://blog.jrock.us/categories/"/><updated>2006-08-07T10:44:20Z</updated><content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><div class="pod">
+<p>As a programmer, you probably don't spend a lot of time thinking about
+the similarities between programming and quantum physics.  Fortunately
+for us Perl users, some people <i>do</i> spend a lot of time thinking
+about physics, and they even wrap up the results in
+<a href="http://search.cpan.org">CPAN</a> modules for us!</p>
+<p>One such module is <cite>Quantum::Superpositions</cite>, which let me easily add
+some nice functionality to my <a href="http://www.jrock.us/trac/blog_software">blog software</a> the other day.  </p>
+<p>As you can see (if you're looking at this article on my blog, not in
+an RSS reader), I have a list of tags to the left of my main content.
+If you click one, it shows you a list of articles that have been
+tagged with that tag.  If you select more than one tag, you get this
+intersection of the two sets (tag1 AND tag2).</p>
+<p>That's nice, but I like to use the left navigation bar to show the
+user where he is <i>in addition to</i> letting him move somewhere else.
+To do this, I bold the current location, and remove the link.  That
+way, the user won't try to visit the page he's already looking at.
+This is pretty simple to implement for things like the &quot;home page&quot; or
+the &quot;archives&quot;.  You just check the current page, and if the link
+you're about to print out matches, make it bold instead.  That logic
+looks something like this:</p>
+<pre>     [% FOREACH category = categories %]
+        [% IF category == current_category %]
+          &lt;b&gt;[% category %]&lt;/b&gt;
+        [% ELSE %]
+              [% category %]
+        [% END %]
+     [% END %]
+
+</pre>
+<p>Simple, and it provides excellent visual cues as to what the user is
+looking at.</p>
+<p>The problem with tags, though, is that an article can have lots of
+them.  The technique above doesn't work there; you need to do a search
+for each tag.  Not a show stopper, but do you really want to do array
+searches inside the Template Toolkit?  No!</p>
+<p>And this is where <cite>Quantum::Superpositions</cite> comes to the rescue.  In
+quantum physics, almost nothing is &quot;certain&quot; -- you can't tell with
+100% certainty both where a particle is and what its velocity is.
+The state of an individual particle is in sort of a flux until you
+observe, and when you observe, a tangible state comes into existence.</p>
+<p>How does this help with tags?  By thinking of the set of all tags as a
+cloud of particles, we can apply the same principle.  We don't care
+what all the tags are until we look at them.</p>
+<p>So how do we do this in perl?  Let's see an example:</p>
+<p>In my
+<a href="http://www.jrock.us/trac/blog_software/browser/lib/Blog/Controller/Tags.pm#L96">Tags.pm</a>
+Controller, I use the <code>any</code> method from <code>Quantum::Superpositions</code> to
+collapse the list of tags into a scalar:</p>
+<pre>   $c-&gt;stash-&gt;{article_tags} = any(@tags);
+
+</pre>
+<p>Then inside my <a href="http://www.jrock.us/trac/blog_software/browser/root/navbox.tt#L40">Template Toolkit View</a>, I &quot;observe&quot; the state as
+necessary (with the <code>==</code> operator):</p>
+<pre>     [% FOREACH tag = all_tags %]
+        [% IF tag == article_tags %]
+          &lt;b&gt;[% tag %]&lt;/b&gt;
+        [% ELSE %]
+              [% tag %]
+        [% END %]
+     [% END %]
+
+</pre>
+<p>As you can see, this is exactly the same as what we did when we only
+had one possible value.  If you think about it, it's really the same
+thing.  You just needed to think more about physics :)</p>
+<p>Anyway, take a look at this in action:</p>
+<p><a href="http://blog.jrock.us/tags/%E3%83%A2%E3%83%BC%E5%A8%98%E3%80%82/music">http://blog.jrock.us/tags/%E3%83%A2%E3%83%BC%E5%A8%98%E3%80%82/music</a></p>
+<p>And then add some cool navigation features to your Catalyst app!
+</p>
+
+
+</div></div></content></entry></feed>
\ No newline at end of file