My markdown to HTML script

2019-05-04

In this post I mentioned I have a script tot convert my markdown articles into html. I'm planning on adding a nicer index page to the site. To make that easier, mainly the date ordering, I'm going to want to refactor this HTML script. But before that, lets go over what we have so far to see how it works.

It's a simple Ruby script. It uses the redcarpet library to handle the markdown conversion and bundler/inline to avoid the need for a separate gem file.

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

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

  require 'redcarpet'

There's a constant string that acts as the HTML template, requiring the css and adding the footer that's on each page. The template string has and easy to identify placeholder BODY, which will be replaced with the content of our, converted markdown file.

  TEMPLATE = <<-HTML
  <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>
      <article>
        BODY
      </article>
      <footer>
        <p>
          <a href="http://200words.rjldev.com/">back</a>
        </p>
        <p>
          You can follow me on twitter <a href="https://twitter.com/rjldev">@rjldev</a>
        </p>
      </footer>
    </body>
  </html>
  HTML

Now we come to the actual conversion. First we build a renderer, passing in our settings. Then we loop through the names of all the markdown files in the done directory. I'm making the assumption that I'll be running the script from the project root. For each file name we build a name for the output HTML file which will place it in the public directory. Then we read the content of the input file, convert it to markdown and substitute it into our template. Finally we write final html to the output file.

renderer = Redcarpet::Markdown.new(Redcarpet::Render::HTML, autolink: true, tables: true, fenced_code_blocks: true)
Dir["#{Dir.pwd}/done/*.md"].each do |file_path|
  basename = File.basename file_path
  outname = 'public/' + basename.sub('.md', '.html')
  markdown = File.read file_path
  body = renderer.render markdown
  html = TEMPLATE.sub 'BODY', body
  File.write outname, html
end

Note that this script overwrites any existing files with the same name as the output file. That's intentional as I want any layout changes to propagate to all files.

Hopefully all that will provide context for any future articles I write on refactoring this script.

200 words done.