Skip to main content

A front Matter generator with ruby

Why I will no longer remember my front matter variables

After an Introduction to Java a few years ago in school I decided to leave the programming languages behind me. I think if we’d have gotten an introduction to Ruby, my opinion would have been different. I had studied ruby for one day, when I wrote the first version of this generator. After a year of Java I was not even able to program as much functionality as I can with just a few lines of JavaScript and CSS today. And the thing I wrote in ruby is definitely more useful. Because It means that I will never again write front matter declarations in a jekyll page.

I have written another front matter generator a while ago1, it worked pretty good, but for me too many steps were involved until the file was at the right place. I just wanted to enter my data and then - preferably - have the file opened in my favourite editor so I could just go on write the content.

I got inspired, when I had a look at some jekyll plugins, that did generate new files. So I thought Ruby is the way to go. I started the course at Codecademy and 60% into it, decided to give this generator a go and it basically wrote itself. How I wrote it, is what I want to show you today.

Collecting Variables

Collecting Variables

Okay, first step is pretty obvious. Before you can write a front matter generator, you need all of the relevant variables, to be included. In this tutorial I want to present a shorter generator than my personal one. Mine generates two files since I’m posting in two languages and certain variables share values.

The variables I use for this generator are as follows:

VariableDescriptionSome more to note
titlethe titleshould not be longer than 55 characters
url-titleThis is not a front matter variable, but important for the file namethis should not include empty spaces or special characters
subtitlethe subtitleoptional
descriptionMeta tag descriptionnot longer than 115 characters
tagstagsare in an array, and optional

I just want the subtitle and tags to be optional. All of the others are needed, especially for SEO purposes.

File

File

Okay, the file will be placed within a ruby folder. And since most jekyll sites use git, you will most probably have your terminal open at the root. So it is easy to navigate to the Posts folder. My script is within the ruby folder, so I can call it using ruby _ruby/createpost.rb

Okay, open your favourite editor. Mine is Brackets and then we can get started.

Since we need to create a new file, we will need a require. And then we start with the methods.

Since I like my output to be colorful, I googled and found the classes to create some color.

1
# encoding: utf-8
2
require 'fileutils'
3
4
# for colored output
5
class String
6
def red; "\033[31m#{self}\033[0m" end
7
def green; "\033[32m#{self}\033[0m" end
8
def brown; "\033[33m#{self}\033[0m" end
9
def gray; "\033[37m#{self}\033[0m" end
10
def bold; "\033[1m#{self}\033[22m" end
11
end

We need different methods so that the generator works a bit faster.

First we have createURl, which replaces all of the german umlaut characters with an equivalent representation and all of the spaces with a hyphen. It looks like this:

1
# create File name for URL
2
def createURL(string)
3
string.downcase!
4
string.gsub! " ", "-"
5
string.encode!("UTF-8")
6
string.gsub! "ä", "ae"
7
string.gsub! "ö", "oe"
8
string.gsub! "ü", "ue"
9
end

To remove the umlauts, we also create a method

1
# replace all ä,ö,ü with Unicode
2
def umlautify(string)
3
string.encode!("UTF-8")
4
string.gsub! "ä", "ä"
5
string.gsub! "Ä", "Ä"
6
string.gsub! "ö", "ö"
7
string.gsub! "Ö", "Ö"
8
string.gsub! "ü", "ü"
9
string.gsub! "Ü", "Ü"
10
end

And since any colon in yaml within the content can cause problems, we replace them with the unicode representation.

1
# replace every colon within yml, so that it still can get parsed correctly
2
def sanitizeYML(string)
3
string.gsub! ":", ":"
4
end

Since this is going to generate posts we need to work on the date. So first we’ll save some variables. First the time which exactly spits out what we need for the date variable and then we’ll get the year, day and month for the file name. And we’ll also make sure that the numbers below 10 will be prepended with a zero.

1
# date
2
#------
3
time = Time.new
4
year = time.year.to_s
5
6
#if day and month are below 10, add a 0 in front of it
7
if time.day <= 9
8
day = "0#{time.day}"
9
else
10
day = time.day.to_s
11
end
12
13
if time.month <= 9
14
month = "0#{time.month}"
15
else
16
month = time.month.to_s
17
end

Generator

Generator

As soon as that’s done, we can start the generator.

We start by inserting a initiation message \n tells it, to start a new line. And we’ll do that in bold and green

1
# Generator
2
#-----------
3
4
# starting msg
5
puts "Initating Front Matter Generator for Posts.\nPlease enter the following information as per instruction.\n".bold.green
6
puts ""

Then we’ll ask for the title and save the input in a variable. We then check the value. If it’s above 55 characters or empty, we will ask once again. If it is not inserted correctly a second time, we’ll abort the program and ask for a restart.

1
# Title
2
puts "Enter post title. It should not be longer than 55 characters".bold.gray
3
title = gets.chomp
4
5
if title.length > 55
6
puts "Your title is too long, please enter a shorter title".bold.brown
7
title = gets.chomp
8
if title == ''
9
abort("Program was aborted, because no valid title was entered. Please restart".bold.red)
10
elsif title.length > 55
11
abort('Program was aborted, because title was too long. Please restart'.bold.red)
12
end
13
elsif title == ''
14
puts "Please enter a title, shorter than 55 characters".bold.gray
15
title = gets.chomp
16
if title == ''
17
abort("Program was aborted, because no valid title was entered. Please restart".bold.red)
18
elsif title.length > 55
19
abort('Program was aborted, because title was too long. Please restart'.bold.red)
20
end
21
end

Then we ask if the title is equal to the URL part, so the file name. If it is, we’ll set the file name variable to title, else we ask for input. And also if somethings wrong we abort the program.

1
# URL Title
2
puts ""
3
puts "Is the title going to be equal to the URL Title?\n(yes/no)".bold.gray
4
url_title_yes_or_no = gets.chomp
5
6
case url_title_yes_or_no
7
when "yes", "y"
8
file_name = title
9
when "no", "n"
10
puts "Enter the URL title".bold.gray
11
file_name = gets.chomp
12
if file_name == ''
13
puts "Please enter a valid file name".bold.brown
14
file_name = gets.chomp
15
if file_name == ''
16
abort("Program was aborted. Please restart and follow instructions".bold.red)
17
end
18
end
19
else
20
puts "Please enter either 'yes' or 'no'".bold.brown
21
url_title_yes_or_no = gets.chomp
22
case url_title_yes_or_no
23
when "yes", "y"
24
file_name = title
25
when "no", "n"
26
puts "Enter the URL title".bold.gray
27
file_name = gets.chomp
28
if file_name == ''
29
puts "Please enter a valid file name".bold.brown
30
file_name = gets.chomp
31
if file_name == ''
32
abort("Program was aborted. Please restart and follow instructions".bold.red)
33
end
34
end
35
else
36
abort("Program was aborted. Please restart and follow instructions".bold.red)
37
end
38
end

Now that we have the URL title, we’ll transform it into the URL format. For that we use the method we defined before. And then we’ll set the file path. We define the folder and if it does not already exist, we’ll create it.

1
# create URL
2
createURL(file_name)
3
4
# if there is a folder specified, add it and create a new folder, if it does not already exist
5
folder = "_posts/"
6
7
file_format = "markdown"
8
case file_format
9
when "md", "markdown"
10
file_ending = ".md"
11
when "html", "HTML"
12
file_ending = ".html"
13
when "txt", "textile"
14
file_ending = ".txt"
15
else
16
file_ending = ""
17
end
18
19
# set path for file
20
if folder != nil
21
path = "#{folder}/#{year}-#{month}-#{day}-#{file_name}#{file_ending}"
22
23
dirname = File.dirname(path)
24
unless File.directory?(dirname)
25
FileUtils.mkdir_p(dirname)
26
end
27
else
28
path = "#{year}-#{month}-#{day}-#{file_name}#{file_ending}"
29
end

Subtitle and tags are both optional, so we just ask if there is any input, otherwise nothing happens.

1
#subtitle
2
puts ""
3
puts "Enter subtitle\n(press enter if you don't want to add a subtitle)".bold.gray
4
subtitle = gets.chomp
5
6
#tags
7
puts ""
8
puts "Enter tags, separate with commas\n(press enter if you don't want to add tags)".bold.gray
9
tags = gets.chomp

For the description we do the same we did for the title

1
# Description
2
puts ""
3
puts "Enter post description. It shouldn't be longer than 115 characters".bold.gray
4
desc = gets.chomp
5
6
if desc.length > 115
7
puts "Your description is too long, please enter a shorter description".bold.brown
8
desc = gets.chomp
9
if desc == ''
10
abort("Program was aborted, because no valid description was entered. Please restart".bold.red)
11
elsif desc.length > 115
12
abort('Program was aborted, because description was too long. Please restart'.bold.red)
13
end
14
elsif desc == ''
15
puts "Please enter a description, shorter than 55 characters".bold.gray
16
desc = gets.chomp
17
if desc == ''
18
abort("Program was aborted, because no valid desription was entered. Please restart".bold.red)
19
elsif desc.length > 115
20
abort('Program was aborted, because description was too long. Please restart'.bold.red)
21
end
22
end

And then we’re ready to create the file. We’ll execute the methods to clean up the content and then we’ll add it into the file content.

1
# create new file
2
p = File.open( path,"w" )
3
4
sanitizeYML(title)
5
sanitizeYML(subtitle)
6
sanitizeYML(desc)
7
8
umlautify(title)
9
umlautify(subtitle)
10
umlautify(tags)
11
umlautify(desc)
12
13
# file content
14
p.puts "---"
15
p.puts "date: #{time}"
16
p.puts "title: #{title}"
17
if subtitle != ""
18
p.puts "subtitle: #{subtitle}"
19
end
20
if tags != ""
21
p.puts "tags: [#{tags}]"
22
end
23
p.puts "description: #{desc}"
24
p.puts "---"
25
p.close

At the end we’ll put out the created path and open the file in brackets, executing the command brackets <path>.

And then the program is done.

1
# add notification that file was created
2
puts "file '#{path}' created".bold.green
3
puts ""
4
puts "opening file in brackets".bold.green
5
6
# add command to open file in brackets
7
value = `brackets #{path}`

And you can see the whole thing here.

Search

Results will appear as you type