Today I Learned

A Hashrocket project

366 posts by jakeworth @jwworth

PostgreSQL: Table or View?

I’m doing some database exploration today and needed to find out if a collection of tables are all tables, or if some of them are views. By querying the information schema via the following: select table_name, table_type from information_schema.tables;, I learned more about each table and its type:

> select table_name, table_type from information_schema.tables;
              table_name               | table_type
---------------------------------------+------------
 cats                                  | BASE TABLE
 dog                                   | BASE TABLE
 dogs_and_cats                         | VIEW

asdf Global Versions 🌏

Spend a bit of time with asdf, and you might see an error like this:

$ npm install
asdf: No version set for command npm
you might want to add one of the following in your .tool-versions file:

nodejs 10.15.3
nodejs 8.9.1

The project I’m trying to set up via npm install doesn’t specify a Node version in .tool-versions, and since I have multiple Nodes on my machine, asdf isn’t sure which to use.

I don’t want to edit .tool-versions in this project; I’d rather asdf had a global default.

Here’s how I made that happen:

$ asdf global node 10.15.3   

Print Calendar With Week Number 📅

I use the week number (1-52) in my notetaking. How do I know what week number it is? ncal.

$ ncal -w
    May 2019
Mo     6 13 20 27
Tu     7 14 21 28
We  1  8 15 22 29
Th  2  9 16 23 30
Fr  3 10 17 24 31
Sa  4 11 18 25
Su  5 12 19 26
   18 19 20 21 22

Though not shown in the output above, today’s date (the 10th) is highlighted in my terminal output. At the bottom of the column containing today’s date is the week number (19).

Friendly Zoom Personal Meeting URL ➡

If you have a Zoom account, you have a Personal Meeting URL— a permanent video conferencing room tied to your account. It looks like this:

https://zoom.us/j/5551112342

When another person with Zoom installed visits this link in a browser, Zoom starts a call in your room.

A pro move is to permenantly redirect a subdomain to this URL, like so:

chat.tomcruise.com

Now you have a memorable link you can share in online and offline conversation.

Hide an Elixir Module from Documentation

Recently I’ve noticed @moduledoc false sprinkled through some Elixir projects. What’s going on? To quote the docs:

Conveniently, Elixir allows developers to hide modules and functions from the documentation, by setting @doc false to hide a particular function, or @moduledoc false to hide the whole module. If a module is hidden, you may even document the functions in the module, but the module itself won’t be listed in the documentation…

Why would you see this in a project that doesn’t autogenerate docs? Possibly to satisfy a linter like Credo. In a codebase with public APIs, I think this kind of explicit statement is a good practice.

Writing Elixir Docs

Improve Your Stack Overflow Feed ⬆

I like answering questions on Stack Overflow. It helps me stay aware of what people are struggling with in a particular language or framework. To do this well, I manage my tags. Here’s a screenshot of some of the tags I’m watching (subjects I care about and can contribute answers to) and ignoring (the rest).

image

With these settings, my question feed is mostly signal rather than noise.

If you visit Stack Overflow often and haven’t signed up for an account, I recommend it.

killall 💀

Today while pairing I learned about the killall command.

This BSD program kills processes by name, unlike kill, which uses PID.

Here’s me killing my Mac calculator:

$ ps aux | grep Calc
grep Calc
/Applications/Calculator.app/Contents/MacOS/Calculator
$ killall Calculator
$ ps aux | grep Calc
grep Calc

Thanks for the tip, Mark!

Alphabetize Keys with jq

In a previous post, I wrote about how jq is great because it doesn’t alphabetize JSON keys by default. I still think that’s great, because sometimes the key order is meaningful, such as might be found in a package.json file.

We can add alphabetization to jq, however, using the -S flag. To format and and sort you current buffer in Vim, run the following:

:%!jq -S '.'

Happy JSON-ing!

Highlight Diffs With Markdown

Today I learned about the ‘diff’ syntax, supported by many syntax highlighting libraries including those used by Github and Today I Learned.

Add diff to your fenced code block, and this:

def example do
-  :ok
+  {:ok, :more_stuff}
end

Becomes this:

def example do
-  :ok
+  {:ok, :more_stuff}
end

A nice use case is a README or pull request description; show instead of tell the changes you made, or someone should make.

What is my Tmux Previous Window?

Today I noticed a symbol in the Tmux bar that I had not noticed before, the dash (-) next to frontend:

0:code* 2:api  3:frontend-

In a Tmux session, asterisk (*) is the window in focus. The dash is the previous window, which you can easily return to. From window 0, code, I can return window 1, frontend, using CTRL + bb.

Send Tmux Pane to Window

A scenario I find myself in frequently: I’ve started a server in a Tmux pane, and realize I don’t need to see the server logging in my ‘home’ Tmux pane (pane 0 for me).

To send a Tmux pane to its own window, use :break-pane.

A nice addition is the -n flag, which lets you set the new window name while breaking the pane.

:break-pane -n frontend-elm

IEx Last Return

The last item returned in an IEx session is accessible via the v() function. To get the item, call the function with no argument.

iex()> 1
1
iex()> v()
1

This function takes a negative number as an argument, representing n steps back through history.

Python Help in REPL 🐍

Heading to the internet to get help with a Python function? Slow down! There’s help right in your terminal.

With the Python executable installed, it’s as easy as:

$ python
>>> help()
help> string.lower
Help on function lower in string:

string.lower = lower(s)
    lower(s) -> string

    Return a copy of the string s converted to lowercase.

help>

Reset Hub Credentials

On a shared computer, multiple users logged into Hub can lead to confusing Github activity, such as a PR opened from the command line with your name on it that you didn’t open.

These credentials are stored in ~/.config/hub. To reset your Hub credentials, delete this file and run a Hub command, and you will get an opportunity to reautheniticate.

Open Newest Email with Gmail

Part of my Gmail workflow includes hotkeys. I’d recommend them to anyone who wants to use their email more efficiently.

My current favorite command is gio, or gi (show inbox), combined with o (open focused message), which defaults to the newest message. gio lets me open my newest email without a mouse, faster than you can say ‘unsubscribe’.

Combine this with Vim motions (j and k) and you’re off to the races. 🏁

Build a CLI with Elixir

Elixir Mix ships with built-in CLI support, called escript. From the docs:

An escript is an executable that can be invoked from the command line. An escript can run on any machine that has Erlang/OTP installed and by default does not require Elixir to be installed, as Elixir is embedded as part of the escript.

Yesterday I built a CLI that reads an input file, does some calculations, and prints a result. For me, CLI’s are often the mark of a fully-realized project, and I appreciate how the Elixir community treats CLI’s as a first-class idea.

In lieu of a longer explanation, here are the docs:

mix escript.build

Cycle Deckset Themes

Deckset for Mac is my favorite presentation software. Markdown-to-slides with prebuilt themes is pure joy.

Here’s a fun hack: + ] and + [. Use these to cycle through the Deckset themes for your current presentation. I like this feature because it helps me quickly pick a good color palette.

Set Vim Filetype or Syntax with Modeline

Here’s a problem I faced today: I’m writing a Thor CLI. The convention for that project is a file called cli, written in Ruby but with no .rb extension. Vim highlights it and otherwise treats it like a conf file, but it’s Ruby. I want my editor to progamatically recognize that and act accordingly.

One solution is Vim’s modeline. With modeline enabled, either of these settings will enable syntax highlighting on buffer read. They can both be used at the same time as shown.

# vi: syntax=ruby
# vi: filetype=ruby

def ruby_here
end

Gmail 'o'

In my quest to learn all the Gmail hotkeys, today I learned ‘o’.

‘o’ opens the focused email in your inbox. Combine this with ‘gi’ (go to inbox) and Vim-style JK (down/up throught the inbox list), and you’re cruising. 🏁

Hotkeys must be enabled in your settings.

List ImageMagick Fonts

ImageMagick drawing and annotating features rely on fonts on your computer to work. But what fonts are on your computer?

On newer versions of ImageMagick, here’s how you’d find out that information:

% identify -list font

Path: /usr/local/Cellar/imagemagick/7.0.8-24/etc/ImageMagick-7/type-apple.xml
  Font: AndaleMono
    family: Andale Mono
    style: Undefined
    stretch: Undefined
    weight: 0
    glyphs: /Library/Fonts//Andale Mono.ttf
...

AndaleMondo and ~60 other fonts are installed on my machine and accessible by ImageMagick.

Bootstrap CircleCI Setup with Docker 🐳

CircleCI maintains a collection of Docker containers, pre-installed with different languages and tools.

These include language image variants that can eliminate a lot of CI setup churn. I recently used the -browsers variant, which ships with Chrome, Firefox, Java 8, and Geckodriver.

Here’s how you could use such a container.

# .config/circle.yml

version: 2
jobs:
  build:
    docker:
      - image: circleci/ruby:2.5.1-browsers
    steps:
      - run: rake

Add an Empty Directory to Git

Have you ever seen a directory containing a single .gitkeep? Today I learned the history of that file.

Git won’t let us add an empty directory, but sometimes there’s a good reason to want to do that. For instance, I’m building a single-page app that requireds a src/data/ directory, even when there’s no data. Instead of each developer on the project making this directory by hand, I’d like to check it into version control.

There are two competing strategies to achieve this: adding a .gitkeep to the directory, or adding a .gitignore. I prefer .gitkeep because the name tells you what it does and it’s not conventionally used for another purpose.

$ touch src/data/.gitkeep

Stack Overflow

Gatsby 404 Static Sitemap

Iterating through a process of building many static Gatsby.js pages at once, I discovered a hacky way to see what pages have been built. Visit a page that doesn’t exist, and Gatsy’s development 404 page will provide a sitemap with links to all the static pages.

demo

It’s a little nicer than digging through the filesystem.

Prevent a User From Selecting Text

Today I learned about a CSS property called user-select. You might use it like this, to prevent a user from selecting text:

p {
  user-select: none;
}

I discovered this on an event booking website: the event description links were not anchor tags, and the content on the page was not selectable.

If you’re going to disable default behavior on a website, you need to have a good reason. My assumption (which could be wrong) is that the site creators don’t want me to select text on the page and start searching around for a better deal. I don’t think that’s a good enough reason, because there are plenty of cases where a user might copy text on a page that don’t hurt (or actually support) the event organizer’s business.

docs

Separated Table Borders

Today I learned how to make separated table borders, like this:

border-collapse

Each td has a top and bottom border, and these settings make the separation possible:

table {
  border-collapse: separate;
  border-spacing: 3rem 0rem;
}

The border-collapse property sets whether cells inside a table have shared or separate borders. The border-spacing property sets the distance between the borders of adjacent table cells, when border-collapse is set to separate.

More info: table properties

Open Bitbucket PR's from the Command Line

I’m a fan of Git command line tools. The more familiar I become with Git hosting platform’s website, the more I want to control it with a CLI.

When you push a branch to Bitbucket, part of the response is a pull request URL. That URL is a create page for a pull request against the default branch.

I’ve taken this idea a step further and created a script for my project that visits this page:

#!/bin/sh

BRANCH=`git rev-parse --abbrev-ref HEAD`
open "http://bitbucket.org/<organization>/<project>/pull-requests/new?source=${BRANCH}&t=1#diff"

This script reads my current branch name and visits the Bitbucket ‘create PR’ page in a diff view.

Work with a Gist locally

I like Gists, those fun-size Git repositories I fill with coding demos, scripts, and WIP markdown files. Today I learned you can edit these files locally and push them to a remote, just like any Git repo.

Grab your Gist URL:

https://gist.github.com/yourhandle/5bac61ee3fe0083

Alter it slightly, and clone:

$ git clone git@gist.github.com:5c61ee3fe0083.git
$ cd 5c61ee3fe0083/

Make changes, commit, and push away. Your commits will show up under the /revisions tab of your Gist.

Pass a Block on Console Load

Have some Ruby code you want to run as the Rails console loads? Here’s a technique.

In this example, I’m going to use a function from the hirb gem. Add the gem to your Gemfile and bundle.

Next, pass a block to console in your application configuration.

# config/application.rb

module MyApplication
  class Application < Rails::Application
    console do
      # Action(s) I want to run on console load...
      Hirb.enable
    end
  end
end

The next time you start the Rails console, Hirb.enable will run after load.

code / docs

The Outline Property 🖼

Today I learned about the CSS outline property.

Outlines are like borders, except they never take up space, because they’re drawn outside of an element’s content.

Some browsers have a default outline style for interactive elements (like buttons) on focus. This was how I came to learn about the property, because that style clashed visually with an element I was building.

Remove such an outline with either of these settings:

button:focus {
  outline: 0;
  outline: none;
}

Note that if an element can be interacted with, a11y best practices require a visible focus indicator. Provide obvious focus styling if the default focus style is removed.

Start Zoom on Mute 📣

We’ve been using Zoom for a while now; it’s an excellent video conferencing tool.

One setting I recommend enabling is ‘Always mute microphone when joining meeting’, under the ‘Audio’ settings. I’ve been using it for a week and love it. Pausing work in an open office to join a conference call can be a messy affair, and this setting helps me control how I enter the conversation (silently).

Resize Tmux Pane 🖥

Sometimes, after a long day of coding, I resize a Tmux pane using my mouse instead of my keyboard. It’s a habit from my GUI-informed past.

Here’s how to accomplish this without a mouse.

To resize the focused pane left one cell (from the Tmux prompt):

:resize-pane -L

Resize pane number 3 right 10 cells:

:resize-pane -t 3 -R 10

Etc.

Jump Back 🐇

A Vim motion I’ve really been loving lately is '' or ``, which returns you to the previous jump position. It references the previous jump, so using it twice in a row will toggle you back and forth between two locations.

I use this a lot after jumping to the next occurance of a word with *, and then changing that word in some way so I can’t return with *. If you’re using normal mode most of the time, this command can help you walk back through your thought process.

For more info:

:help ''

ES6 Nested Destructuring

I picked this up a while ago on Twitter, use it all the time in my React code, and wanted to document it here. If you’re destructuring a JS object like this:

const { username, zip } = props.user;

A valid (and slightly better, in my opinion) refactor is this:

const { user : { username, zip } } = props;

As you add more destructured variables pulled from props, the object you’re referencing stays the same.

Note that this doesn’t define user— if that’s something you want, you have to destructure it on its own:

const { user, user : { username, zip } } = props;

While a little more verbose, I still think this makes for more maintainable destructuring long-term.

Change Prompt in Z Shell

When I live code, or share terminal commands in a demonstration, I don’t want my customized terminal prompt included in that information. It’s noisy.

Right now I’m changing this in Z Shell via that PROMPT variable.

# Complex prompt
jake@computer-name: echo $PROMPT
%{%}%n@%m%{%}:

# Simple prompt
jake@computer-name: PROMPT="$ "
$ echo 'ready to live code'
ready to live code
$

Go Tests Uncached

Go caches test results, and this can be a problem if you have flickers, are benchmarking your tests, or just want to run all the tests every time.

Disable caching with GOCACHE:

$ go test ./...
ok      monkey/ast      (cached)
ok      monkey/lexer    (cached)
ok      monkey/parser   (cached)
$ 
$ GOCACHE=off go test ./...
ok      monkey/ast      0.005s
ok      monkey/lexer    0.005s
ok      monkey/parser   0.005s

Restore from Diff in Vim

I often use diffs in Vim to compare my current file with the previous Git commit. vim-fugitive is one way to do this, via commands like :Gdiff or :Gvdiff (vertical option).

From this diff state, we can restore the code from one pane to the other using the command :diffput. This is useful for restoring one line, or a range, from the previous commit to my working copy.

Select a Square With Mac Preview

Lately I’ve been taking screenshots of code and my terminal. They seem to look the best when they’re square; that shape translates better to a variety of project management tools and social media platforms.

Mac Preview lets you select part of an image down to the pixel for cropping, and I have found selecting a perfect square very difficult. The solution? Select with SHIFT + click to force a square-shaped selection. ⌘ + K to crop.

🔲

CRA Dependencies and ES5

At the time of this writing, create-react-app requires that all dependencies are precompiled to ES5. If they aren’t, the build will abort.

When this happened to me today, I followed a few of the recommended workarounds, eventually switching to a library that uses the older ECMA standard.

Running $ yarn build-js (or equivalent) when testing out any dependency would be a good way to surface this incompatibility upfront.

Here’s the Github issue on zipcodes-perogi where I documented my journey to this discovery.

Custom Cypress Commands

I’ve been loving my first forays into Cypress integration testing. It feels really well made.

Today I learned how to create a custom Cypress command. Logging into the application is a classic use-case: I need to do it in almost every test, and I’d like a function that accepts arguments and centralizes the DOM manipulation.

Here it is:

// cypress/support/commands.js

Cypress.Commands.add('signIn', ({ email, password }) => {
  cy.visit('/sign-in');
  cy.get('input[name="email"]').type(email);
  cy.get('input[name="password"]').type(password);
  cy.get('form').submit();
});

The command is now available in any test without an explicit import:

cy.signIn({ email: 'dev@hashrocket.com', password: 'password' });

Abstraction!

docs

Traversing Git Conflict Markers

Today I solved several nagging inefficiencies in my Vim setup. One was memorizing a mapping for traversing Git conflict markers.

If you’ve ever had a merge conflict and opened the unresolved file, you’ll see these markers:

<<<<<<<
console.log('keep this code?')
=======
console.log('...or this?')
>>>>>>>

Deciding what to keep can be a process, and Vim-Unimpaired makes it easier by providing mappings to jump between the markers— ]n for the next marker, [n for the previous marker. Use these to traverse the diff and learn about what might be gained or lost during resolution.

MySQL Average

MySQL; it’s like a calculator inside your computer. Today I learned how to compute the average of something using this popular RDBMS.

Let’s compute the average length of name in table dog.

mysql> select avg(char_length(name)) from dog;

Result:

+------------------------+
| avg(char_length(name)) |
+------------------------+
|                 9.2965 |
+------------------------+

Psql Watch

The Postgres REPL psql in includes a \watch command that repeatedly executes a command every n seconds. Here’s the official description:

\watch [ seconds ] Repeatedly execute the current query buffer (like \g) until interrupted or the query fails. Wait the specified number of seconds (default 2) between executions.

It executes the current query buffer, which you can print with \p:

tilex_dev=# \p
select title from posts order by inserted_at desc limit 1;

Run \watch and tail your query result as it changes:

tilex_dev=# \watch
Sun Jul 29 17:06:13 2018 (every 2s)

        title
----------------------
 Psql Watch
(1 row)

Time: 2.175 ms

source

React-Router Location Hash #️⃣

Want to do cool things with the hash element of a URL, using React-Router? You can!

React-Router’s location contains a hash key:

{
  key: 'ac3df4',
  pathname: '/somewhere'
  search: '?some=search-string',
  hash: '#hereiam',
  state: {
    [userDefined]: true
  }
}

Anywhere location is available, pull off hash (defaults to an empty string) and have fun!

Limiting Regex Alternation

The pipe operator (|, or the ‘alternation’ operator) is the ‘or’ of Regexes. Here’s a JavaScript example:

> 'hello'.match(/^hello|goodbye$/)
[ 'hello', index: 0, input: 'hello' ]
> 'goodbye'.match(/^hello|goodbye$/)
[ 'goodbye', index: 0, input: 'goodbye' ]

You might think this Regex can be true in two situations: the string is 'hello' or 'goodbye', because the Regex includes the start-of-line and end-of-line characters (^ and $). I have bad news:

> 'hello there'.match(/^hello|goodbye$/)
[ 'hello', index: 0, input: 'hello there' ]

What’s going on here? This is truthy because the | has a low precedence. It’s evaluated last, after other characters like () and ?. To put this Regex into words (I think): “does this string match anything before the pipe (including the start of line character), or anything after the pipe (including the end of line character)?”. The expression matches on ^hello and ignores anything after that.

We can contain it by telling the pipe to stop evaluating. Parentheses work because they have a higher order of precedence. Here’s our new Regex:

> 'hello there'.match(/^(hello|goodbye)$/)
null
> 'say goodbye'.match(/^(hello|goodbye)$/)
null

Bottom line: when using the pipe the way I’ve described, use parentheses.

Log Into Windows 10 Without A Keyboard

Sometimes you might need to log into a Windows machine without a keyboard. A damaged keyboard, non-functioning ports for connecting an external keyboard, or a faulty keyboard driver could put you in this predicament.

Windows 10 includes an accessibility menu called ‘Ease of Access’, located in the lower righthand corner of the screen. This menu includes an on-screen keyboard. Use it to log in when your keyboard doesn’t work.

Ease of Access

git merge --squash

Today I learned a new Git command that’s really useful. git merge --squash takes all the changes from one branch and stages them on top of another branch, ready to be summarized.

Here’s a sample workflow:

$ git checkout -b feature-branch

# Make changes across multiple commits
$ echo 1 > 1.txt
$ git add 1.txt
$ git commit -m 'Add first textfile'
$ echo 2 > 2.txt
$ git add 2.txt
$ git commit -m 'Add second textfile'

# Stage all changes on master
$ git checkout master
$ git merge --squash feature-branch
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   1.txt
        new file:   2.txt

# Summarize
$ git commit -m 'Add files 1 and 2'

This is a fast way to boil down a lot of WIP commits from a feature branch into a single commit on master.

Yanking a Ruby Gem

Yanking (unpublishing) a Ruby gem is something that has to happen from time to time. Maybe your library has a known vulnerability. Maybe you pushed a gem by mistake. Sometimes the best code is no code.

Here’s how you permanently yank a gem published to Rubygems:

$ gem yank <gemname> -v <version>

What are the side effects? If somebody was locked to your exact version, they would not be able to download that package again and would have to upgrade or downgrade. Consider that when deciding whether to yank.

Policy change about gem yank / CLI reference