I’ve got my code filtering Markdown and now I want to stuff that filtered content into an HTML page. I could just use
maruku#to_html_document, but I need the ability to add details like a title and site-related links.
I could use a format similar to my Python blog files. I won’t really need PageTemplate if I do that, though. Not for the content file, anyways. That’s okay, though. The Maruku filter was more of a proof-of-concept, anyways. PageTemplate will be useful for fitting the generated content into an actual template, though.
That means I’m starting over on my content files.
Given a content file that looks like this:
title: A Simple Page--This page intentionally left blank.I want an object that makes the title available in some way (simple Hash style access is fine), and makes the HTML-formatted content available. After a few minutes of fiddling and poking around, I end up with tests and application code.
Article Test Code
#!/usr/local/bin/ruby
require 'test/unit'require 'SiteTemplate'
class TC_Article < Test::Unit::TestCase def test_article_file() article_file = 'simple.txt' assert(article = Article.new(article_file)) assert_equal(article_file, article.source_file) assert_equal('A Simple Page', article.metadata['title']) assert(article.content =~ %r{<p>This page intentionally left blank.</p>}) endendThe Application Code
#!/usr/local/bin/ruby
require 'rubygems'require 'maruku'
# A single HTML page generated by a content file## Content files usually look like this:## title: My Title# --# Article contentsclass Article attr_reader :source_file, :metadata, :content def initialize(filename) @metadata = {} parse!(filename) end
def parse!(filename) @source_file = filename content = '' in_content = false File.open(filename).each_line do |line| if in_content then content << line else if line =~ /^--$/ then in_content = true next end
if line =~ /^(\w+?):\s*(.+)$/ then key = $1 value = $2 @metadata[key] = value end end end
@content = Maruku.new(content).to_html endendIt’s a really simple, slow parser, but it works. I won’t try to optimize it before I’ve actually figured out what it’s supposed to be doing.
The Template
The next target is stuffing this content into a template. That’s easy. Here’s the template:
simple.html Template File
<html> <head> <title>[%var title%]</title> </head> <body> <h1>[%var title%]</h1> [%var content%] </body></html>I could assemble my page manually if I felt like it. As a matter of fact, let’s do that in one of the tests.
Manual Page Generation Test
require 'PageTemplate'
class TC_HTML_Page < Test::Unit::TestCase def test_manual_page_generation() article_file = 'simple.txt' template = PageTemplate.new() template.load('simple.html') article = Article.new(article_file) template['title'] = article.metadata['title'] template['content'] = article.content assert_match(%r{<title>A Simple Page</title>}, template.output) endendDo I really want to manually apply even that little bit of code, though? No, I don’t.
Automatic Page Generation Test
class TC_HTML_Page < Test::Unit::TestCase def test_standard_page_generation article_file = 'simple.txt' template_file = 'simple.html' assert(html_page = HTML_Page.new(:article => article_file, :template => template_file)) assert_match(%r{<title>A Simple Page</title>}, html_page.to_html) assert_match(%r{<p>This page}, html_page.to_html) endendAutomatic Page Generation Code
require 'PageTemplate'
class HTML_Page def initialize(opts = {}) @article = Article.new(opts[:article]) @template = PageTemplate.new() @template.load(opts[:template]) end
def to_html() @template['title'] = @article.metadata['title'] @template['content'] = @article.content return @template.output endendSaving a File
Okay, now I have article files with content and metadata being consumed, formatted, and handed off to PageTemplate for wrapping into a pretty HTML page. The only thing remaining at this stage is to actually write the file.
Test Writes
require 'fileutils'
class TC_HTML_Page < Test::Unit::TestCase
def test_standard_page_generation article_file = 'simple.txt' template_file = 'simple.html' output_file = 'test/out.simple.html' FileUtils::rm_rf(output_file) assert(html_page = HTML_Page.new( :article => article_file, :template => template_file, :output_file => output_file)) assert_match(%r{<title>A Simple Page</title>}, html_page.to_html) assert_match(%r{<p>This page}, html_page.to_html)
html_page.write_to_file assert(saved_html = File.open(output_file).read()) assert_match(%r{<title>A Simple Page</title>}, saved_html) assert_match(%r{<p>This page}, saved_html) FileUtils::rm_rf(output_file) endendCode to Make the Writes Happen
Oh heck, just take the whole thing. This is what my SiteTemplate.rb file looks like right now.
#!/usr/local/bin/ruby
require 'rubygems'require 'fileutils'require 'maruku'require 'PageTemplate'
# A single HTML page generated by a content file## Content files usually look like this:## title: My Title# --# Article contentsclass Article attr_reader :source_file, :metadata, :content def initialize(filename) @metadata = {} parse!(filename) end
def parse!(filename) @source_file = filename content = '' in_content = false File.open(filename).each_line do |line| if in_content then content << line else if line =~ /^--$/ then in_content = true next end
if line =~ /^(\w+?):\s*(.+)$/ then key = $1 value = $2 @metadata[key] = value end end end
@content = Maruku.new(content).to_html endend
# Takes an Article and a PageTemplate and mushes them together# Note: This version still assumes that needed metadata will# be available. This is not a safe assumption.class HTML_Page def initialize(opts = {}) @article = Article.new(opts[:article]) @template = PageTemplate.new() @template.load(opts[:template]) @output_file = opts[:output_file] end
def to_html() @template['title'] = @article.metadata['title'] @template['content'] = @article.content return @template.output end
def write_to_file() FileUtils::mkdir_p(File.dirname(@output_file)) File.open(@output_file, 'w') { |f| f.print to_html } endendWrapup
This stage is done. We’ve taken some article files that look a lot like my blog files and turned them into fully-fleshed HTML files. They will fit into a PageTemplate that’s been defined by the site maintainer, guaranteeing a standard look for the site.
My next post on this topic will deal with putting an HTML_Page into the context of a larger site.