Creating a simple post generator in Bridgetown with the command line
I’ve always wanted to create posts via the command line in Bridgetown.
Something like how Rails does it, say:
rails new model Car
It’s easy to do the same in Bridgetown with rake
.
1. Create a task in your Rakefile
You can create a rake
task and run it with the bin/bridgetown
executable, as explained here in the docs.
For our post generator, we’ll add a create_post
task.
# Rakefile
task :create_post do
end
We also want to pass arguments to our task, so we can do something like:
create_post TITLE="Hello World"
I’ll use ENV
variables to capture arguments in this guide. Here’s a good article on passing arguments to rake
tasks if you want to try something different.
Going back to the example above, we want to pass in a title to our post generator, which is done as shown below:
# Rakefile
task :create_post do
title = ENV["TITLE"]
end
Now, we need to construct a filename that matches Bridgetown’s naming convention for posts, which is in the form of:
YEAR-MONTH-DAY-post-title.EXT
We’ll use Time.now
to generate the date:
# Rakefile
task :create_post do
title = ENV["TITLE"]
current_time = Time.now
# Returns a date with the format YYYY-MM-DD
date = current_time.strftime("%F")
end
Here’s a good cheatsheet for the different strftime
combinations in Ruby.
We also need to replace the spaces in our post title with dashes, which we do below:
# Rakefile
task :create_post do
title = ENV["TITLE"]
current_time = Time.now
# Returns a date with the format YYYY-MM-DD
date = current_time.strftime("%F")
# Replace spaces with dashes
formatted_title = title.downcase.tr(" ", "-")
end
String#tr
is a nifty method for replacing characters efficiently in Ruby. Rails also uses #tr
for dasherize
in the ActiveSupport
module.
We want to downcase
the title to keep the filename consistent with the naming convention.
Don’t forget the extension for the filename.
# Rakefile
task :create_post do
title = ENV["TITLE"]
current_time = Time.now
# Returns a date with the format YYYY-MM-DD
date = current_time.strftime("%F")
# Replace spaces with dashes
formatted_title = title.downcase.tr(" ", "-")
# Extension for post file
extension = ".md"
end
You can also accept a command line argument for the extension with something like ENV["EXTENSION"]
if you use multiple extensions for your posts.
Finally, combine them all together (don’t forget the extra dash that connects the date and the title):
# Rakefile
task :create_post do
title = ENV["TITLE"]
current_time = Time.now
# Returns a date with the format YYYY-MM-DD
date = current_time.strftime("%F")
# Replace spaces with dashes
formatted_title = title.downcase.tr(" ", "-")
# Extension for post file
extension = ".md"
filename = date + "-" + formatted_title + extension
puts filename
end
We also added a temporary puts
statement to test whether our task works so far.
Try running the command and check if the output adheres to Bridgetown’s conventions, for example:
bin/bridgetown create_post TITLE="Hello World"
=> 2022-04-02-hello-world.md
You may need to modify the script to cater for specific scenarios (e.g. stripping off commas, umlauts, extra whitespaces, etc.). That will not be covered in this guide for now.
2. Creating the file
Now that our filename generator is ready, it’s time to create the file.
Posts are stored in src/_posts/
by default, so we’re going to use that as our base directory when creating the post file. You may need to change this depending on your folder structure.
# Rakefile
task :create_post do
title = ENV["TITLE"]
current_time = Time.now
# Returns a date with the format YYYY-MM-DD
date = current_time.strftime("%F")
# Replace spaces with dashes
formatted_title = title.downcase.tr(" ", "-")
# Extension for post file
extension = ".md"
filename = date + "-" + formatted_title + extension
# Don't forget the trailing / in your posts directory
base_url = "src/_posts/"
end
Next, we’ll combine the base_url
and filename
to get the path for our generated post. We’ll also use File.open
to create the file.
# Rakefile
task :create_post do
title = ENV["TITLE"]
current_time = Time.now
# Returns a date with the format YYYY-MM-DD
date = current_time.strftime("%F")
# Replace spaces with dashes
formatted_title = title.downcase.tr(" ", "-")
# Extension for post file
extension = ".md"
filename = date + "-" + formatted_title + extension
# Don't forget the trailing / in your posts directory
base_url = "src/_posts/"
path = base_url + filename
File.open(path, "w+") do |file|
end
end
File.open
takes in a string which will be the path for the file you’re creating.
The second argument is the file mode, which means whether the file is read-only or writable or both. Passing in w+
here means the file we’re creating is open to reads and writes.
The man
page for fopen
goes in detail about the different modes and how they work during file creation.
When you pass a block to File.open
, you’ll receive an IO
object that lets you interact with the newly-created file. This lets us edit the file directly which leads us to the next and final section.
3. Adding front matter to the post
We want our post generator to automatically include front matter so we don’t have to do it ourselves.
We do this by using the puts
method of the IO
object we had earlier. puts
writes strings you pass to it to the file, which lets us generate front matter as shown below:
# Rakefile
task :create_post do
title = ENV["TITLE"]
current_time = Time.now
# Returns a date with the format YYYY-MM-DD
date = current_time.strftime("%F")
# Replace spaces with dashes
formatted_title = title.downcase.tr(" ", "-")
# Extension for post file
extension = ".md"
filename = date + "-" + formatted_title + extension
# Don't forget the trailing / in your posts directory
base_url = "src/_posts/"
path = base_url + filename
File.open(path, "w+") do |file|
file.puts "---"
file.puts "layout: post"
file.puts "title: #{title}"
file.puts "categories: updates"
file.puts "---"
end
end
This snippet:
File.open(path, "w+") do |file|
file.puts "---"
file.puts "layout: post"
file.puts "title: #{title}"
file.puts "categories: updates"
file.puts "---"
end
will generate our file, and write to it with the puts
calls above.
Open the file and you should see something like this:
---
layout: post
title: Your title here
categories: updates
---
For clarity, let’s add a post-create message to let us know if the post is created successfully.
# Rakefile
task :create_post do
title = ENV["TITLE"]
current_time = Time.now
# Returns a date with the format YYYY-MM-DD
date = current_time.strftime("%F")
# Replace spaces with dashes
formatted_title = title.downcase.tr(" ", "-")
# Extension for post file
extension = ".md"
filename = date + "-" + formatted_title + extension
# Don't forget the trailing / in your posts directory
base_url = "src/_posts/"
path = base_url + filename
File.open(path, "w+") do |file|
file.puts "---"
file.puts "layout: post"
file.puts "title: #{title}"
file.puts "categories: updates"
file.puts "---"
end
puts "Successfully created #{title} at #{path} 🎉"
end
…and you’re done!
Test it out by running:
bin/bridgetown create_post TITLE="Your title here"
and see if the post appears in your site, as well as checking whether the generated front matter appears in the Markdown file. Happy hacking!
Final script
# Rakefile
task :create_post do
title = ENV["TITLE"]
current_time = Time.now
date = current_time.strftime("%F")
formatted_title = title.downcase.tr(" ", "-")
extension = ".md"
filename = date + "-" + formatted_title + extension
base_url = "src/_posts/"
path = base_url + filename
File.open(path, "w+") do |file|
file.puts "---"
file.puts "layout: post"
file.puts "title: #{title}"
file.puts "categories: updates"
file.puts "---"
end
puts "Successfully created #{title} at #{path} 🎉"
end