The main reason I blog is to remember and share my life lessons (and get my thoughts out so my head doesn't explode). It's not always easy, between finding time to do it, not tearing apart my laptop after the first draft, and cringing over grammar mistakes notice months after posting.
But the toughest part is when I learn a lesson or overcome a struggle, only to realize I wrote about the same lesson months ago. Probably like most writers/bloggers/international spies, I have a hard time remembering my notes and how I've grown over time.
So last week, I made it a lot easier and wrote a script to email myself random bits of my writing each day.
Exposing all my site's writing for this was as simple as making a couple of giant XML files. There's one for blog posts, one for the Exocortex, and one for my notes. You can see the blog post example below, and you can see the output at this XML file.
{% assign posts = site.posts %}
{% for post in posts %}
{% assign url = post.url | prepend: site.url %}
<entry>
<title type="html">{{ post.title }}</title>
<link href="{{ url }}" rel="alternate" type="text/html" title="{{ post.title }}"/>
<content type="html" xml:base="{{ url }}">
{{ post.content | xml_escape }}
</content>
</entry>
{% endfor %}
Next up is a Ruby class that can visit any of these URLs, parse the content, and grab a random item.
require 'net/http'
require 'json'
require "base64"
require 'nokogiri'
require 'redcarpet'
require 'redcarpet/render_strip'
class WebsiteContent
def initialize(content_type)
@url = "https://www.maxwellantonucci.com/api/#{content_type}.xml"
end
def get_page
response = api_response(@url)
parse_xml(response)
end
private
def parse_xml(body)
xml_doc = Nokogiri::XML.parse(body)
all_items = xml_doc.css("entry").map do |entry|
{
title: entry.css("title").text,
content: render_markdown(entry.css("content").text)
}
end
all_items.sample
end
def api_response(url)
uri = URI(url)
Net::HTTP.get(uri)
end
def render_markdown(content)
markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML, disable_indented_code_blocks: true, fenced_code_blocks: true)
markdown.render(content)
end
end
Nokogiri
is great for doing the parsing the XML document, and sample
is one of those lovely Ruby methods for common tasks I wish JavaScript had.
All my site content is written in markdown, so that needs to be rendered into HTML. Redcarpet
is good for this since it can handle the code blocks and snippets on some pages.
One last class is needed to email this content to me. It calls up the last class to grab something from my site and uses the mail
gem to send it over. Any email server info I want to keep private is saved in environmental variables and pulled out with dotenv/load
.
require 'mail'
require 'dotenv/load'
require_relative 'website_content.rb'
class EmailSender
def initialize(type)
@type = type
options = email_options
Mail.defaults do
delivery_method :smtp, options
end
end
def send_email
page = WebsiteContent.new(@type).get_page
sender = email_sender
recipient = email_recipient
Mail.deliver do
from sender
to recipient
subject page[:title]
html_part do
content_type 'text/html; charset=UTF-8'
body page[:content]
end
end
end
private
def email_sender
ENV['GMAIL_USERNAME']
end
def email_password
ENV['GMAIL_PASSWORD']
end
def email_recipient
ENV['RECIPIENT_EMAIL']
end
def email_options
{ address: "smtp.gmail.com",
port: 587,
user_name: email_sender,
password: email_password,
authentication: 'plain',
enable_starttls_auto: true }
end
end
Now I just need a task to run all this, which I have in bin/send
that runs the EmailSender
class.
#!/usr/bin/env ruby
category = ARGV[0] || "blog" ;
require_relative '../lib/email_sender.rb'
EmailSender.new(category).send_email
From this project directory, I can call bin/send blog
, bin/send notes
, or bin/send exocortex
and get an email with a random piece from said category. The joys of coding in Ruby! So simple and so enjoyable to write.
I admit all this is a little self-indulgent. But I'm an admitted selfish and casual blogger, so I feel no shame. If this little script helps remind myself to build good habits, write good Ruby, and embrace the horrors of life with humor and curiosity, then I'll take it.