Building a custom site generator for my computer science coursework

For my computer science coursework (which will have a writeup later), I need to write a report. This report is important as it is the main factor in influencing how many marks I get.

I have a few requirements for how I'd like to edit this report:

  • Seperate files for seperate topics
  • A way to include parts from the specification at the top of each file (so I don't have to swap to the specification all the time)
  • Written in markdown format
  • Can edit using Vim (the only real editor)

I know, I'm picky :)

Normally, I would use Jekyll for this. Sadly, there isn't a good way to bring together multiple pages into one using Jekyll. Also, it has much more functionality than I need.

I couldn't really find anything online that covered all of my requirements, so, always happy to waste an afternoon, I decided to build my own solution.

The solution

For each topic in the spec, I made a file. The file includes a header that looks like this:

STARTSPEC
The specification goes here
ENDSPEC

Content that goes to the report

This way, I can include a part of the specification inside my file.

Now that the files are there. I wrote a compiler which takes all the files, puts them into one big file, then parses it using markdown.

I had to reduce the header level of the headers in the files so that it would fit in the master document, so I overrided the method of RedCarpet (the markdown compiler) which renders headers.

Further, I added a table of contents, and numbered the headers (which I later realised I could have done using CSS... oh well)

Finally, I added some styles which made the whole report look like an old RFC document. Here's a screenshot:

Screenshot

The full code is on Github

here is the main part:

require 'redcarpet'
require 'rouge'
require 'rouge/plugins/redcarpet'

# HTML Markdown renderer with SmartyPants
class Renderer < Redcarpet::Render::HTML
  include Redcarpet::Render::SmartyPants
  include Rouge::Plugins::Redcarpet

  @@header_counter = Array.new(6).fill(0)

  def header(text, header_level)
    # Everything after header level goes to 0
    @@header_counter.fill(0, (header_level)..)

    # Increment counter
    @@header_counter[header_level - 1] += 1

    # The list of numbers
    numbers = @@header_counter[0...header_level].join('.') + ' '

    # Create id for TOC
    id = text.downcase.gsub(/ /, '-').gsub(/[^A-Z|a-z|-]/, '')

    %Q(<h#{header_level + 1} id="#{id}">#{numbers + text}</h#{header_level + 1}>)
  end

  def footnote_ref(number)
    %Q([<a href="#fn#{number}">#{number}</a>])
  end
end

markdown = Redcarpet::Markdown.new(Renderer.new(:with_toc_data => true), {
  :no_intra_emphasis => true, # dont italic this_and_this
  :tables => true,
  :fenced_code_blocks => true,
  :autolink => true, # autolink links in <>
  :space_after_headers => true, # can't do #header
  :superscript => true, # 2^(nd)
  :footnotes => true, # blah blah [^1] ... [^1]: Footnote
  :with_toc_data => true
})

toc = Redcarpet::Markdown.new(Redcarpet::Render::HTML_TOC.new)

# All the documentation files
doc_files = Dir["*.md"]

# Sort the files by their title
doc_files.sort!

# Surround each element with ''
doc_files.map! { |f| "'#{f}'" }

# Append all files to .temp using ">"
`cat #{doc_files.join(' ')} > .temp`

# Delete specification lines using "sed"
`sed '/STARTSPEC/,/ENDSPEC/d' .temp -i` 

# Read the temp file
content = File.read(".temp")

# Read the CSS file
head = File.read("compile/head.html")

# Add the css, table of contents, and content to an HTML file
File.open('index.html', 'w') do |file|
  file << head
  file << %q(
    <h1 style="text-align: center; text-decoration: underline">
      Building a project-based learning management system
    </h1>
    <div style="display: flex; justify-content: space-between;">
      <p>
        Ori Marash [3024]
      </p>
      <p>
        King Alfred School [12254]<br/>
      </p>
    </div>
  ) 
  file << toc.render(content)
  file << markdown.render(content)
end

# Remove the temporary file
`trash .temp`

# Brag about it
puts "Created report with #{doc_files.length} files."

Subscribe to Ori Marash

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe