Today I Learned

A Hashrocket project

436 posts by jakeworth @jwworth

Supercharge Your Script with psql -c 🥞

Want to execute a PostgreSQL command from the command line? You can! The --command or -c flag takes a string argument that will be executed on your database of choice.

I’ve been using it as part of a script that creates a remote database backup, downloads the backup, drops and creates a local database, dumps the database backup into the local database, and then runs a select statement on the dataset. That final command looks like this (query has been simplified):

$ psql -d tilex_prod_backup -c "select count(*) from posts";

 count
-------
  2311
(1 row)

List Files by Updated

I’m currently working on an app that forwards logging around to various locations on the Linux server. It’s a bit tricky for me to figure out where any action I take in the browser is being logged. I need those logs!

A nice way to figure out where the logging is happening is to narrow it down to one directory (say, /var/log/) then ls that directory, ordering by most recently updated. The items at the top of the list have been recently updated, and thus probably contain valuable loggings!

$ ls -lt

I’m throwing on the -l flag for more detail. If there are lot of logs, filter it down with head:

$ ls -lt | head

Thanks for the idea, Kori!

Base64 Encode Your Images

This is a companion to my previous post about inline HTML styles. If you want to put your images inline in your HTML, GNU coreutils provides the base64 program.

Here’s me running it in Vim command mode, sending the output right to my current line:

:.! base64 -w 0 public/images/bg.gif

The -w 0 disables line wrapping, which I don’t want for inline images. Prefix this string with "data:image/<MIME TYPE>;base64," and you’re good to go.

What Styles are Being Used?

I like my exceptional pages (404, 500, 503) to rely as little as possible on the webserver to render in the browser. A nice tool to support this is CSS Used for Chrome.

CSS Used adds a panel to DevTools that reports which CSS classes from external stylesheets are being used on your page. You can then paste these styles inside a style tag and remove stylesheet references in your HTML. I iterate on this by opening the HTML file in my browser outside of my project repo; when all the styles are loading, I’ve removed the stylesheet dependency.

image

DNS Lookup with host

Today while doing some sleuthing, I learned about the host command. host “is a simple utility for performing DNS lookups.” It helped me connect a series of domains to their respective AWS EC2 servers, without a visit to the domain registrar.

Example:

$ host jakeworth.com
jakeworth.com has address 184.168.131.241
jakeworth.com mail is handled by 10 mailstore1.secureserver.net.
jakeworth.com mail is handled by 0 smtp.secureserver.net.

More info: man host

UUIDs in Vim with Ruby/JavaScript 🆔

UUID’s (universally unique identifiers) are really handy. I use them for all sorts of things, like key props in a React map, and I like to have them easily accessible when writing code.

Today I wrote two Vim mappings to support this workflow. I can shell out to Ruby and use SecureRandom:

" Insert a UUID with Ruby
nnoremap ruid :read !ruby -e "require 'securerandom'; p SecureRandom.uuid"<cr>

Or, if you’re happier in the JavaScript ecosystem, here’s a similar command using Node and the uuid library. I did not have to install uuid, it was already available to me.

" Insert a UUID with JS
nnoremap juid :read !node -e "var uuid = require('uuid'); console.log(uuid.v4())"<cr>

Include vs. Includes 🤷‍♂️

A hallmark of switching back and forth between Ruby and JavaScript: I mistype the respective array inclusion function a lot. In JavaScript, it’s includes, and in Ruby, it’s include (with a question mark). Each language does not care what I meant.

The way I remember which function to use: in Ruby, I say: “does this array include this item?”. Then when I’m writing JavaScript, I remember I’m not writing Ruby. This technique is… lacking.

Chris Erin’s pneumonic is better: “JavaScript has an ‘s’ in it, so it includes. Ruby does not, so it is include.”

Heroku Psql Oneline 🐘

I cooked up this Heroku/subshell command today, and I like it:

$ psql $(heroku config:get DATABASE_URL)

This will connect me to the primary PostgreSQL database for my Heroku application in the psql client. Now I’m ready to query!

NOTE: why not $ heroku pg:psql? I’m not sure. I think Heroku was reporting status issues today, and I wanted to bypass any infrastructure I could.

Firefox Profiles for Work and Home 👤

I’m managing two Firefoxes on my laptop: one for work and one for after work. A feature that supports this well is Firefox profiles. Visit them in Firefox by typing about:profiles into the browser bar.

These work like Chrome People— separate sessions, histories, bookmarks, etc. I have styled the two browsers a little differently so I can quickly tell them apart.

I used to use Incognito/Private Windows for this setup, but those aren’t great for long-running browser sessions, because when you close or crash the browser, anything you’ve done in that browser is gone. Profiles give me the isolation I need with some persistence, too.

Perform on Zoom 🎸

Planning to use Zoom for something other than a meeting, like a reading or musical performance, that would benefit from room noise and a softer audio experience? If so, read on!

Zoom has several default audio features in place to make your business calls sound great. We don’t want those features in place in a performance setting. Jettison them by enabling ‘original sound’ under advanced audio settings:

image

All you need to do from here is turn on your best (quality and/or position) microphone option. For me, that’s my display audio.

h/t Suzanne Erin

Git Checkout in Patches

Something I’ve learned pairing with Chris Erin is to checkout code you don’t want in patches. Here’s the command:

$ git checkout --patch

Like the git add --patch command many developers know, this puts you an interactive workflow where you can decide how to handle each chunk, or patch, of your changes. It works opposite of git add --patch, in that y means check out the patch (abandon the changes), and n means keep the changes.

This is a great flow to go through before trying to commit code; use it to get rid of debugger statements, pseudocode, unwanted autoformatter changes, etc.

Toggle Dark Reader 🌓

I really love the Dark Reader Browser plugin (h/t Chris Erin). It turns most websites into a dark mode that is really easy on my eyes. However, some sites just don’t look right in dark mode. Luckily, the plugin can be toggled on and off with ALT + SHIFT + D on Firefox and Chrome. I use it a couple of times a day on websites I encounter on the internet.

Bonus: Here’s an example of this plugin in action, that is very meta.

image

Dark Reader

Git 101

There are lot of tutorials about Git. One that is built right into Git is the ‘everyday help’. Print this help with:

$ git help everyday

The output is a series of must-know commands for a variety of roles in a technical organization: individual developer (standalone), individual developer (participant), integrators, and admins.

Pick a lane and go! 🏁

Run Git Commands From Any Dir

Git has one feature that I find irksome; you have to be in the directory with the Git repository to run commands against it.

…Or do you?

Git provides the -C flag for this scenario. Follow it with a directory name, and Git will execute your command as if it was run from <path>.

$ git -C ~/tilex status
On branch master
Your branch is up to date with 'origin/master'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   lib/tilex_web/templates/layout/app.html.eex

no changes added to commit (use "git add" and/or "git commit -a")

Tmux Clear History

I’ve been doing an experiment lately that requires reading and searching lots of logs in Tmux. Something that makes this harder is that we collect a deep history there. Sometimes I’ll ‘find’ a query I’ve been looking for 😀, only to realize it is hours or days old ️😐.

Tmux clear-history has been our solution. Running this command on an already cleared Tmux pane clears your history for that pane; you can’t scroll up or search the previous output.

We’re doing this enough that I put this alias in our terminal dotfiles.

alias tc='clear; tmux clear-history; clear'

tmux clear-history is the CLI version of the Tmux meta command :tmux clear-history.

Vim Mark That Test! 🔖

This week Chris Erin taught me a technique that has changed my testing game: Vim mark your current Ruby test with mA.

When writing TDD-style code in a test-crazy language like Ruby, I tend to follow a predictable workflow: create a test, watch it fail, bounce around the code making changes, and run/edit the test again. This loop can repeat for hours on a complex feature.

There are many ways you could navigate back to your test from elsewhere; a very efficient method is to mark it in Vim with mA. Like any mark, you can return to it with `A. Why ‘A’? Capitalized marks are file marks and are valid between files. With this command, you can mindlessly jump back to your test from anywhere in the jumplist stack.

Git Diff Matches Paths 📁

Today I learned that the git-diff command accepts a <path> argument. I used this knowledge to construct a command that runs only the RSpec test files on my branch that differ from master.

(other-branch)$ git diff master --name-only spec | xargs rspec

This is handy on a big test suite; when you can’t run every test, make sure you run the ones that you have changed.

See man git-diff for more info.

Mac Notes Default Text Size 🔎

I use Mac Notes a lot during pairing and brainstorming. It works, and it’s right there on the Mac!

One issue I’ve had is that the default text size on Mac Notes is unreadably small on a big monitor or iMac. I always end up creating a note, then bumping the text size with CMD-SHIFT ..

Of course, there’s a better way. Set the default font size in preferences.

image

Byline Class and Time Tag 📰

I’ve been hacking on TIL to optimize our site for Safari Reader mode. A lot of this is black box, because Apple doesn’t have easy-to-find documentation about how the feature works.

One thing that seems to matter is a class called byline for your author information, and an HTML tag time for the publication date. Here’s an example, borrowed from this site:

<p class="byline">
  <%= name %>
  <time datetime="<%= inserted_at %>">
    <%= inserted_at %>
  </time>
</p>

It gives us relevant reader information, shown here in Safari:

image

Here’s the PR:

https://github.com/hashrocket/tilex/pull/650

Meta Charset Top That! 🔝

When writing HTML, make sure that your meta charset tag is in the first 1024 bytes on the page.

Per MDN:

The <meta> element declaring the encoding must be inside the <head> element and within the first 1024 bytes of the HTML as some browsers only look at those bytes before choosing an encoding.

What does this mean practically? Keep this tag near the top of your document, and use a website validator like https://validator.w3.org to check your tag placement.

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta

Type "text/javascript" is Redundant

Have a script tag in your HTML annotated with <script type="text/javascript">? Per the HTML5 specification, the MIME type of a script tag, when omitted, is text/javascript. We are encouraged to omit it.

Delete that code and go green 💚.

Per MDN:

Omitted or a JavaScript MIME type: This indicates the script is JavaScript. The HTML5 specification urges authors to omit the attribute rather than provide a redundant MIME type. In earlier browsers, this identified the scripting language of the embedded or imported (via the src attribute) code. JavaScript MIME types are listed in the specification.

Source:

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script

Git Interactive Single Key 👇

Today I became familiar with the Git configuration interactive.singleKey. In the Hashrocket dotfiles this is enabled by default, and I’m not sure how common it is out in the wild. To quote the docs:

In interactive commands, allow the user to provide one-letter input with a single key (i.e., without hitting enter).

This allows git add --patch to be very powerful by enabling a quick vote up or down on a patch with a single keystroke.

Make sure you have the Perl module Term::ReadKey installed; it is a dependency.

Linking to a PayPal Transaction Page ⛓

This is a follow up to PayPal Transaction Pages aren’t Linkable. We figured out a way to build this feature!

When you process a PayPal transaction with the SDK (i.e. as a seller), you get a token that could be considered a transaction ID. It is something like a primary key on an object that is the parent to several other transactions: the seller’s transaction, any currency conversions, etc.

With this ID in hand, you can link to the seller’s dashboard and see a summary of this parent transaction. It’s not a documented feature, so the link could be broken at any time.

Thanks for sticking with me, PayPal support.

PayPal Transaction Pages aren't Linkable ⛓

I spent some time this week trying to create a link directly to a PayPal Merchant transaction show page. This is the page you’d see as a merchant when somebody has paid you via PayPal.

These pages use the transaction’s ID as a lookup, so I’d need the know that ID in order to dynamically create the link. After some Googling, reading GitHub issues, and finally the source code of my PayPal SDK of choice, I’d like to report: PayPal does not expose this ID in the normal course of business.

To quote my PayPal caseworker:

“While there are ways of retrieving the Transaction ID… you will not be able to link directly to the PayPal transaction details page, for security. The only way that your buyers can view the transaction details page is by accessing PayPal themselves, logging in with their credentials, and navigating to the Activity.”

I hope this spares another developer from the same rabbit-hole I just emerged from. Sometimes things with technology don’t work. 🤷‍♀️

Edit: we figured it out!

Class.new with Superclass

Today I encountered the following syntax (observed in Ruby 2.7):

SpecialError = Class.new(StandardError)

What’s going on here?

According to the Class docs, Class.new takes a superclass as an argument, creating an anonymous unnamed class. So this could be written as:

class SpecialError < StandardError
end

We’d lose the anonymity of the SpecialError class, but in the first example, we are assigning it to a Pascal-cased variable name anyway.

I think the first syntax would make sense when the code looks just like this example: a simple class that inherits some behavior, where the name is needed only in the scope where the class is declared.

Sort Git Branches by Latest Commit

Some of my repos have a lot of branches, and a command I discovered this week sorts them by the most recent committer date:

$ git branch --sort=-committerdate
* new-branch
  not-so-new-branch
  super-old-branch

The - reverses the order, putting the most-recently updated branch at the top, rather than the bottom, of my output. That’s more intuitive to me, but it certainly works in reverse.

Capitalize Hashtags for #a11y

At RubyConf 2019, I learned that social media hashtags are more easily read by screen readers if they are capitalized. So #rubyconf is more accessible when written as #RubyConf, because the screen reader can more easily make sense of the word breaks. Keep this in mind when posting and designing marketing campaigns.

I saw #rubyfriends and #rubyconf migrate to #RubyFriends and #RubyConf at the conference in realtime as this idea spread.

more info

h/t Coraline Ada Ehmke

Multiline HAML, One Way or Another 🥞

HAML uses meaningful whitespace identation, so in general, multiline code doesn’t fly. The prevailing wisdom is that ‘it’s better to put that Ruby code into a helper’ rather than support multiline blocks. But what if I really want to?

Here’s an example of a multiline HAML block using pipes.

= link_to(           |
  'someplace',       |
  some_path,         |
  class: 'someclass'

The pipe character preceded by whitespace signifies a multiline block. Make sure you don’t end your final line with a pipe; this can break your templating.

Tmux Attach Sessions with Working Directory

Your Tmux working directory is the root directory of the session. You can figure out what it is by opening a new window or pane in your session. The directory you start in is your working directory.

Sometimes it’s not the best directory for the type of project you’re developing. For instance, it could be set to the root directory of an umbrella app, when you’re working exclusively in one of the subdirectories.

Reset it with the -c flag:

$ tmux attach-session -t my_session -c ~/my_project

Force Code Block Length with Non-Breaking Space 📏

Services that render fenced code blocks tend to remove whitespace. They’ll display these two code blocks the same way, trimming the blank lines from the second example.

let something;
let something;

GitHub does this, as does Deckset. Deckset also adjusts your code’s font size based on how many lines are in the block, which means these two code blocks would have different font sizes on their slides. Sometimes I don’t want that to happen, like when building a series of slides that fill in different pieces of an example and should look consistent.

I cheat this feature putting a non-breaking space on the last line. On Mac, I can do this with OPTION + SPACE. I can see the character in Vim (‘+’), but it’s invisible on the slide, and it prevents Deckset from collapsing the line it’s on, forcing the code block to the length I choose.

SO: Use non-breaking spaces

Vim Tags in Visual Mode 🏷

This is my 400th TIL! 🎉

I’ll file this under ‘Vim is endlessly composable’. Today I learned that Vim tags can be used to define a range in visual mode. Here’s how you’d fold your code between two Vim tags.

Go to the first tag. If you marked it 1, here’s how you’d do that:

m1

Enter visual mode and extend to your second tag 2:

m2

Enter command mode and fold the range:

:fold

Which automatically extends to:

:'<,'>fold

I use this in big markdown files to hide all but the thing I’m currently working on. Enjoy.

Vim Reverse Sort

I use Vim’s :sort all the time. If I can’t have a more meaningful algorithm than alphabetical, at least my lists are in some kind of order.

This function comes in surprisingly useful while writing GitHub-style checkbox lists.

- [x] Check mail
- [ ] Play guitar
- [x] Write TIL

Sorting this list alphabeticaly puts the undone items at the top.

- [ ] Play guitar
- [x] Check mail
- [x] Write TIL

Reverse the order (in classic Vim style) with a bang:

:sort!

GitHub PR Team Reviews

Pull request openers on GitHub can request a review from a GitHub user, or a team that has at least read-access to the repository. In the screenshot below, deploying the ‘Ninjas’ to review this PR is effectively the same as requesting a review from each ninja on the team. If they have notifications for such things, they’ll be notified, and they’ll see a banner on the PR’s show page requesting their input on the change.

image

This is a handy way to request a lot of reviews at once.

About Pull Request Reviews

Mechanical Keyboard DIP Switches

I’ve owned a WASD keyboard for a while but totally forgot about the DIP switches on the bottom. What’s a DIP switch? From Wikipedia:

A DIP switch is a manual electric switch that is packaged with others in a group in a standard dual in-line package (DIP). The term may refer to each individual switch, or to the unit as a whole. This type of switch is designed to be used on a printed circuit board along with other electronic components and is commonly used to customize the behavior of an electronic device for specific situations.

DIP switch

On a WASD V2 87-key, these switches let you enable Mac mode (switch command and option), swap caps lock with CTRL, activate function commands, and more. These can be set in the OS or via different applications, but setting them at the hardware level is very convenient.

DIP Switch

Change Mechanical Keyboard Keycaps Faster ⌨️

I change the keys on my mechanical keyboards often. Sometimes I’m upgrading from stock, or trying an experiment, or just pursuing a look. It’s a reality of being really into keyboards.

Something I’ve learned along the way: removing all your old caps at once is a bad idea. When you do this, you have to figure out where every key goes. Some keycaps have a code on the underside telling you the row it belongs to, most do not. I end up pulling up my Mac virtual keyboard, or looking at another keyboard, to sort it out.

A better techique: take the new keys and line them up in the correct order for each row. Some keycaps ship in separate rows, making this easy. If that’s the case, slide each row out of its shrinkwrap like a sleeve of Thin Mints.

Then, change one row at a time. Remove all the keycaps in one row, and then put all the new ones in place. This is fast, foolproof, and if you get interrupted in between rows, you still have a functioning keyboard.

image

Tmux New Window and Process ⏩

This is a command I am continually a huge fan of. Here’s one way to open a new Tmux window, from Tmux command mode:

:new-window <program> <arguments>

My practical example from today:

:new-window psql my_database

This opens a new Tmux window psql with the arguments supplied, connecting me to my_database. When I terminate database connection, the window closes. For web development, this is a great way to quickly connect to a program, run some commands, then close the connection and cleanup the Tmux session.

Open the Vim Quickfix

Today I learned a new Vim command, :copen or :cope. The headline for this command is that it “open[s] a window to show the current list of errors”. The side benefit is that if you already have quickfix window in your buffers, like you would after greping the codebase, it will open or reopen that quickfix buffer.

See :help :copen for more info.

Reset a Vim Split

When I make a Vim horizontal split, the two panes are evenly sized. I then often use :resize n to make one pane larger or smaller. To restore the panes to their evenly sized split, use <vim-leader> =. In the Hashrocket dotfiles, this translates to CTRL + W =.

IO.inspect Label

When doing puts-driven-development in Elixir, IO.inspect/1 and IO.inspect/2 are very useful. These functions return their items unchanged, allowing us to spy on a value in our Elixir code.

I’m a fan of the :label option, which decorates our output with a label, making it easier to understand.

def channel_name_split(channel) do
  channel.name
  |> IO.inspect(label: "channel name before")
  |> String.split("")
  |> IO.inspect(label: "channel name after")
end

And here’s the output in our server log:

channel name before: "workflow"
channel name after: ["", "w", "o", "r", "k", "f", "l", "o", "w", ""]

Check out h IO.inspect in IEX for more info.

Set Splits Strings

Examples of JavaScript’s Set usually include an array as the argument:

const arraySet = new Set([1, 2, 3, 4, 5]);

However, the Set constructor also accepts a string, splitting it into a set for you:

const text = 'India';

const stringSet = new Set(text);  // Set ['I', 'n', 'd', 'i', 'a']

Enjoy those extra keystrokes!

docs