Refactoring

2019-05-05

In the previous post we discussed wanting to refactor our article page builder script to support a date ordered index page. We want to end up with something like this:

index.html.erb

  <html>
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <link rel="stylesheet" type="text/css" href="sakura.min.css">
    </head>
    <body>
      <h1>200 Words.</h1>
      <article>
        <header>
          <h2>Articles</h2>
        </header>
        <ol>
          <%= articles.sort_by(&:date).each do |article| %>
            <li><%= article.title %></li>
          <% end %>
        </ol>
      </article>
      <footer>
        <p>
          You can follow me on twitter <a href="https://twitter.com/rjldev">@rjldev</a>
        </p>
      </footer>
  </body>
  </html>

It's a good approache to start writing the high level code you want to end up with first then worry about making it work.
Looking at how we want our index page to work we can see our next set of requirements. We'll need an itterable collection of articles, and each article needs to be sortable by date, and respond to the method title. These are all things we can write simple unit tests for.

Now we know what the index.html.erb template requires, We'll rewrite our script to pass in a colelction of objects with the appropriate interface. we'll do this at a high level, writing the code we want to end up with and worrying about the details later. After trying a couple of ideas, I stuck on the following:

index = Index.new template: 'src/index.html.erb'

FILE_PATHS.each do |file_path|
  article = Article.new file_path: file_path
  index << article
end

index.write! directory: OUTPUT_DIR

Build an index collection object, passing in the erb template. Build an article object for each file and pass it into the collection. Finally write the index html file to some output directory. We'll hide all the details of passing the article to the erb template and writing to disk behing the index object. All the top level script file is concerned with is which articles get built, not how.
As we have an article object we can abstract the step of building and writing the article into that and call it as we build the index.
Filling in a bit more detail we end up with.

html.rb

#! /usr/bin/env ruby
require 'bundler/inline'

gemfile do
  source 'https://rubygems.org'
  gem 'redcarpet'
end

require 'redcarpet'

INDEX_TEMPLATE = File.read 'src/index.html.erb'
ARTICLE_TEMPLATE = File.read 'src/article.html.erb'
OUTPUT_DIR = 'public'
FILE_PATHS = Dir["#{Dir.pwd}/done/*.md"]

index = Index.new template: INDEX_TEMPLATE

FILE_PATHS.each do |file_path|
  article = Article.new file_path: file_path, template: ARTICLE_TEMPLATE
  article.write! directory: OUTPUT_DIR
  index << article
end

index.write! directory: OUTPUT_DIR

Now we have our high level requirements we can start writing some unit tests against them.

That's 200 words for today.