Joel Always one syllable, sometimes "@jayroh"

Fathers Day 2022

19 Jun 2022

After finishing a recent book – Mouth to Mouth (verdict: “meh. ⭐⭐”) – I picked up Michael Ian Black’s “A Better Man: A (Mostly Serious) Letter to My Son” and dived in. I figured, hey it’s almost Father’s Day, so let’s see what this funny guy has to say. And as the title of the book says, yes - this really is a mostly serious piece of writing. He gets into the heavy stuff pretty quickly.

But that’s not why I’m writing this. There’s a bit in the first 10 or 20 pages where he explores the feeling of when he crossed into the realm of “manhood”:

Before I sat down to write this, I couldn’t have told you the moment I felt I’d crossed, irrevocably, into manhood.

It was when I drove my family home from the hospital for the first time.

I’ve never been more terrified than the moment I turned out of the parking lot.

This statement stopped me, and I let out a quiet, “heh”, chuckle.

Because this has been, almost verbatim, what I have shared with first-time parents through the past 7+ years that I’ve been a father. “No one prepares you for the moment you strap your child in that car-seat, and drive away. There was ‘you before’, and ‘you now’, there is no manual, so go figure it out.”

Happy Father’s day to all you Dads out there. I trust, and hope, that you are navigating those waters successfully. ❤️

Porting the blog to TailwindCSS

18 Jun 2022

A couple weeks ago I noticed there were some style-related issues here, so I reached for the CSS to make the necessary fixes. Easy enough.

But when I did so - I paused, confused, then realized I had no idea how to edit and rebuild it(?). It had been a long, long, while since I last adjusted the styles.

Side note: remember Compass? This website was using Compass! I loved it! Shout out to a real OG, author of compass and co-founder of Sass, Chris Eppstein. Absolute legend.

The small issue here was that, as it pertains to Compass, I just didn’t recall the conventions around mix-ins, building, file locations, etc. So, like every “good” (air-quotes) writer of software I decided to go the long-way ‘round and re-implement all of the styling with TailwindCSS, the current CSS Belle of the Ball.

Rough steps:

  1. Stripped the site of any and all CSS-related code, assets, dependencies, etc.
  2. Use the jekyll-postcss-v2 plugin.
  3. Installed with their instructions, except for the npm dependencies, which they instruct that you install via npm i -D postcss postcss-cli. If you are using Netlify to build and deploy your website (as I do), then make sure to omit the -D because if and when you set JEKYLL_ENV to production then npm won’t install whatever is inside the devDependencies key of your package.json.
  4. Rewrite the old styles using the new framework. AKA, “draw the rest of the owl

The process was pretty straightforward and relatively painless if you run your local Jekyll server with jekyll serve --livereload, and have your editor, work in progress in one browser window, and your source/reference in another browser. The Tailwind docs workflow for Alfred also came in handy for all of the documentation reference.

Final thought part 1: while doing this bit of work I took the opportunity to examine the blog’s performance via Lighthouse and made some further changes to improve its score. I’ll add some details related to that in a follow-up post.

Final final thought: additional shout-out to Dan for the original design and CSS for this website. Literally couldn’t have done this without you, Dan. Thank you 😄.

Weeknotes for the week ending Jun.17

17 Jun 2022

Hazel.app icon or logo. Hazel.app is an outstanding utility – one I’ve written about before – for watching directories and doing something based on when things changed, certain criteria, etc. The lightest lift is something like “move all screenshots in my Desktop to the trash after a month”, yadda yadda.

I host this blog on Netlify, but new images are being served by an instance of imgproxy that grabs them from an s3 bucket. All new photos that I add to my local “photos” directory I also want sent up to that S3 bucket. Until now it’s been a process of manually copying those files to the bucket.

Well, that’s boring.

How can I set things up to just automatically do it?

  1. Install s3cmd
  2. Set it up with s3cmd --configure. Save the config to the default location which is ~/.s3cfg
  3. Test it out: s3cmd put /path/to/local/file.jpg s3://your-bucket/some/existing/directory/ (it should work)
  4. If you’re using Hazel, at this point you can drag the directory you’re watching to the “Folders” pane on the left.
  5. Create a new rule that looks something similar to:

    If all of the following conditions are met:

    Extension is jpg

    Do the following to the matched file or folder:

    Run shell script, embedded script, (i) Edit Script

  6. Click that “Edit Script” and make it look like:

    /opt/homebrew/bin/s3cmd --config=~/.s3cfg put $1 s3://your-bucket/your/target/path/
    
  7. Open up the Hazel logs to make sure things worked: Help -> View Logs

Weeknotes for the week ending Jun.10

10 Jun 2022

G standing in front of TD Garden
We're in the midst of the NBA Finals, which calls for a trip to TD Garden.

I noticed that this week marked the 6 month mark since I started working with Alexa, my trainer via All-Tru Health and Performance. The main reason I took notice? I saw in the Trainerize app that Thursday was the 100th workout since the beginning of December. For those gym-rats among us, that’s no big deal. For me - it’s a big deal!

  • One hundred intense workouts - a mix of HIIT, dumbbells, body-weight.
  • Between 16-17 workouts a month.
  • About 4 times a week.
  • Paired with a 1750-2000 calorie, 40/20/40 carb/fat/protein macro.

That’s a level of commitment to physical activity I’ve never previously achieved, so you could say I’m a little proud of myself. After 6 months the results have been excellent – I’ve dropped 25 lbs of fat, put on 10 lbs of muscle, and, most importantly, I feel great. There’s more I could say but I’ll save that for after the next 6 months. This is only the start.

(One note: big ups to Alexa for keeping me on point for the last 6 months. She’s been the steadying and encouraging force I’ve needed.)

Jekyll Plugin Conventions

30 May 2022

Jekyll logo.

When it comes to static-site generators Jekyll is clearly among the old heads (if not the oldest). I know it’s not sexy. I know it’s not shiny.

I don’t care. 😄

It works, and it’s easy to grok.

It’s also pretty easy to extend its functionality with plugins – either on your own, adding code to your website’s code-base, or via rubygems. Or creating your own plugin, and distributing it as a gem.

This post is for those getting to that last point. Just what does a typical jekyll plugin look like? What are the typical conventions for file structure? Naming? Any nuance?

Common themes when writing Jekyll plugins

  1. Jekyll plugins are often named via the kebab-case convention, instead of snake_case which is what you might see more commonly for general rubygems. This doesn’t matter much as we can make it work. But if you’re seeing a pattern within a community, then might as well follow the lead instead of bucking the trend. “When in Rome” and all that.

    Some example plugin gems in the wild:

  2. Per the rubygems guides, there are recommendations for how you structure your files and class-names when you use certain naming conventions.

    Chart with recommendations for how to name gems.

    So, if you are naming your plugin “jekyll-awesome-possum” your file and directory structure would look like so:

    Gemfile
    Rakefile
    jekyll-awesome-possum.gemspec
    lib/jekyll-awesome-possum.rb
    lib/jekyll/awesome/possum.rb
    lib/jekyll/awesome/possum/**/*.rb
    

    Where your gemspec would potentially, probably, start out looking like:

    # frozen_string_literal: true
    
    lib = File.expand_path('lib', __dir__)
    $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
    require 'jekyll-awesome-possum'
    
    # ...
    

    Note: There is a bit of unorthodoxy going on here that’s worth pointing out. Normally the file lib/jekyll-awesome-possum.rb would not be necessary as ruby conventions would expect to auto-load code in lib/jekyll/awesome/possum.rb. Jekyll, however, does look to directly load that file and will complain if you don’t have it:

    jekyll-4.2.1/lib/jekyll/external.rb:60:in `require': cannot load such file -- jekyll-imgproxy-tag (LoadError)
    

    Oops.

    Adding that file and further requiring the meat and potatoes of your code does the trick.

    lib/jekyll-awesome-possum.rb

    # frozen_string_literal: true
    
    require 'jekyll/awesome/possum'
    
  3. What does your first class look like?

    lib/jekyll/awesome/possum.rb

    require 'jekyll'
    
    module Jekyll
      module Awesome
        class Possum < Liquid::Tag
          VERSION = '0.1.0'
    
          def initialize(tag_name, markup, tokens)
            super
            @markup = markup
          end
    
          def render(_context)
            'Hello I am the output of a tag'
          end
        end
      end
    end
    
    Liquid::Template.register_tag('awesome_possum', Jekyll::Awesome::Possum)
    

    If you take a look at the Jekyll source, you can see where the Jekyll team name-spaces all of the project within a Jekyll module. As a result, it should do the same, otherwise an error raises due to the constants’ names clashing. Otherwise, at this point we’re pretty much free to flesh out the rest of our plugin as much as we would like.

For more information on how to author Jekyll plugins visit the docs on their site. Additionally, take a look at some of the other plugins out there and read through their source. There’s nothing better than seeing the theoretical applied in real life.

Final thought – this blog post is a result of a little digging for these conventions as I start writing a plugin to get tags generated for the imgproxy image processing tool. If you look at the source and the commit for this post you will see all of the above applied as I flesh out the skeleton of the plugin.

Thanks for reading!