read

I use a Ruby script to generate the feed XML for this website. After running my feed through the W3C validation service I was getting errors regarding the format of my dates & times for when posts were last updated.

Feed validation errors

It turns out that ATOM date/time specs are more strict than typical W3 dates, as well as those generated by default in Ruby.

Luckily, it turns out that there is an easy fix for this! Ruby provides a method xmlschema on Time objects that correctly formats for ATOM feeds.

File.mtime('./' + post_id).xmlschema

Interested in generating your own feed via Ruby script for a Ruhoh blog?

My script generates a file feed.xml in the /pages directory of your site. Set up Feedburner to pull from this feed. It also generates an RSS-specific footer at the bottom of each page linking back to your blog - can't hurt to have a link back while people are consuming your content in Google Reader. (Also helps in case someone starts stealing your feed....)


require 'nokogiri'
require 'fileutils'

require 'ruhoh'
require 'ruhoh/compiler'
require 'ruhoh/client/console_methods'
require 'ruhoh/db'

require 'redcarpet'
require 'cgi'

FileUtils.cd('../')
Ruhoh.setup
Ruhoh.setup_paths
Ruhoh.setup_urls
Ruhoh.config.env = 'production'
Ruhoh::DB.update_all

posts = Ruhoh::DB.posts['chronological'].first(20)
last_update = File.mtime('./' + Ruhoh::DB.posts['chronological'].first).xmlschema#.strftime("%Y-%m-%d")
rights = <<-END
  <div xmlns="http://www.w3.org/1999/xhtml">
    Copyright &#169; #{Time.now.year}
  <a href="http://brandonparsons.me/">Brandon Parsons</a>.
  </div>
  END

rss = Nokogiri::XML::Builder.new do |xml|
  xml.feed('xml:lang' => 'en-US', 'xmlns' => 'http://www.w3.org/2005/Atom') do
    xml.title "<![CDATA[Brandon Parsons' Feed]]>"
    xml.updated last_update
    xml.link('rel' => 'alternate', 'type' => 'text/html', 'href' => 'http://brandonparsons.me/')
    xml.link('rel' => 'self', 'type' => 'application/atom+xml', 'href' => 'http://feeds.feedburner.com/brandonparsons')
    xml.id "tag:brandonparsons.me,2005:/rss"
    # <icon>http://viatropos.com/images/icons/viatropos-favicon.png</icon>
    # <logo>http://viatropos.com/images/icons/viatropos-site-icon.png</logo>
    markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML.new(:filter_html => false), :autolink => true, :fenced_code_blocks => true)
    xml.author do
      xml.name "Brandon Parsons"
      xml.email "[email protected]"
      xml.uri "http://brandonparsons.me"
    end
    xml.rights("type" => "xhtml") do
      xml << rights
    end

    posts.each do |post_id|
      post = Ruhoh::DB.posts['dictionary'][post_id]
      content = File.read("./#{post["id"]}")
      link = "http://brandonparsons.me" + post["url"]

      html = markdown.render(content)
      cut = html.split("\n").delete_if do |line|
        /<hr>/.match(line) || /date:/.match(line) || /description:/.match(line) || /tags:/.match(line) || /title:/.match(line) || /categories:/.match(line) || /type:/.match(line)
      end
      html = cut.join("\n")

      html += "\n\n<hr>\n\n<p>This post originally appeared on Brandon Parsons' blog <a href=\"#{link + '?utm_source=rss&amp;utm_medium=rss-body-link&amp;utm_campaign=website'}\">here</a>.  Looking for more?  Visit my <a href=\"http://brandonparsons.me/?utm_source=rss&amp;utm_medium=rss-footer-link&amp;utm_campaign=website\">home page</a>!</p>\n"
      html = CGI.escapeHTML(html)

      xml.entry do
        xml.title post["title"]
        xml.link('href' => link, 'rel' => 'alternate', 'type' => 'text/html')
        xml.updated File.mtime('./' + post_id).xmlschema#.strftime("%Y-%m-%d")
        # xml.updated post['date']
        xml.id "tag:brandonparsons.me,2005:Post/#{post_id}"
        xml.author do
          xml.name "Brandon Parsons"
          xml.email "[email protected]"
        end
        xml.content(:type => "html") do
          xml << html # Have to do it this way to prevent autoescaping
        end
      end
    end
  end
end


# Write the no layout header
output = <<'EOS'
---
layout: false
---

EOS
file_loc = File.expand_path("../pages/feed.xml", __FILE__)
File.open(file_loc, 'w') {|f| f.write(output) }

# Write the xml content
File.open(File.join("./pages", 'feed.xml'), 'a'){ |p| p.puts rss.to_xml }


Blog Logo

Brandon Parsons


Published

Image

Brandon Parsons

My Personal Blog

Head back to the main page