Today I Learned

A Hashrocket project

327 posts by jakeworth @jwworth

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

Run One Jest Test

When iterating on a test, I want to run just that test. This is a bit tricky with Jest, but it can be done.

First, tell the test framework to run a file, or a describe block:

 # Test file
$ yarn test path/to/test.test.js

# Describe block
$ yarn test -t 'myAssertiveDescribeBlock'

Then, add .only to your it or test block to run just that example:

it.only('is true', () => {
  // your test here
});

It’s just that easy.

only docs

Interval Comparison in JavaScript

Today I learned a bit about interval comparison. It’s something you might recall from grade-school math:

1 < 5 < 10 -- is this true?

Two languages I’ve found that support it are Python and Clojure:

> if (1 < 5 < 10):
...   True
...
True
> (< 1 5 10)
=> true

JavaScript doesn’t support interval comparison, so we have to find another way to check that condition. Here’s one technique:

if (1 < number && number < 10) {
  // do something
}

It’s a wordier that the previous examples, but I think keeping the variable in the middle of the condition stays true to the interval comparison idea.

Extract a Shared Yup Validation

In a growing React app with Yup validations, schemas can become repetitive. But since the validation schema is a JavaScript object, we can extract single validations, or a group of validations.

Here’s my schema definition for an address form:

validationSchema: yup.object().shape(addressValidation)

And the address validation:

const addressValidation = {
  address: yup.string().required(),
  address2: yup.string(),
  city: yup.string().required(),
  state: yup.string().required(),
  zip: yup.string().required(),
};

Reuse this helper anytime you need to collect an address.

Vim Verbose Map

Do you have a Vim mapping you’d like to know more about? One technique to explore a mapping is map. Here’s what my machine knows about gcc:

:map gcc
n  gcc           <Plug>CommentaryLine
o  gc            <Plug>Commentary
n  gc            <Plug>Commentary
x  gc            <Plug>Commentary

Need more information? Add verbose, which will also display where it was last set.

:verbose map gcc
n  gcc           <Plug>CommentaryLine
        Last set from ~/hashrocket/dotmatrix/.vim/bundle/vim-commentary/plugin/commentary.vim
o  gc            <Plug>Commentary
        Last set from ~/hashrocket/dotmatrix/.vim/bundle/vim-commentary/plugin/commentary.vim
n  gc            <Plug>Commentary
        Last set from ~/hashrocket/dotmatrix/.vim/bundle/vim-commentary/plugin/commentary.vim
x  gc            <Plug>Commentary
        Last set from ~/hashrocket/dotmatrix/.vim/bundle/vim-commentary/plugin/commentary.vim

Now we know which modes support gcc (normal, plus operator-pending, normal, and ex-mode as gc), what happens when the command is used, and who set it last.

h/t Chris Erin

Generate Zeropadded Ranges

Need to generate 100 directories, named 01/ to 99/? Today I learned that command line brace expansion supports zeropadded (starting with one or more zeroes) ranges. The following command will create 100 zeropadded, numbered directories:

$ mkdir {01..99}

Hit tab to see the expanded command.

The second zeropad, if there is one, can be omitted— the following creates a range of 01-05, even thought there’s no zero in front of the 5:

$ mkdir {01..5}


Which expands to:

$ mkdir 01 02 03 04 05

Shell Out With Elixir

Today I wrote a staging and production deploy script for Tilex, learning about System.cmd/3 along the way. The first argument to this function is the command, the second are arguments, and the third are options.

Here’s an example implementation from our script that deletes a Git tag and pushes that updated reference to origin:

System.cmd("git", ["tag", "-d", "staging"])
System.cmd("git", ["push", "origin", ":refs/tags/staging"])

React StrictMode Component

Today I tried React’s new StrictMode component. Added in React 16.3, StrictMode is, according to the release notes:

[A] tool for highlighting potential problems in an application. Like Fragment, StrictMode does not render any visible UI. It activates additional checks and warnings for its descendants.

Here’s a heavy-handed way to implement it:

// index.js

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
document.getElementById('root')

In this scenario, App and all of its children get help with:

  • Identifying components with unsafe lifecycles
  • Warning about legacy string ref API usage
  • Detecting unexpected side effects

At the time of publishing this post, this will likely mean console warnings about the use of soon-to-be-deprecated lifecycle hooks such as componentWillMount. You’ll get these errors from dependencies, too, which is why we aren’t using StrictMode until at least all our dependencies have upgraded to the latest syntax.

Create an NVM Config File

NVM supports a configuration file; the most basic file would declare your Node version of choice. Assuming you’re using that Node version, here’s a foolproof method to create such a file:

$ node -v > .nvmrc

I ran this in a project I’m working on, and it exposed a syntax issue with my .nvmrc; I had initially typed 9.2 instead of v9.2.0, the syntax NVM expects. This command eliminates errors like these.

Toggle Apps with Redux Stores

Another cool feature of Redux DevTools!

With this tool, we can toggle between any open browser tab with a Redux store, inside the tool:

In this GIF I’m clicking the downward arrow in the upper right. Works the same in Chrome and Firefox.

I’m unsure what problem this solves, but I think it does help promote and educate us about Redux by making other Redux-connected apps easily discoverable via DevTools.

Adding Decorators (And Store) To Storybook

We’ve been using Storybook to build and refine React components.

As we blur the boundary between the tool and our application (for example, importing an application component into a Storybook component) the workflow becomes complicated by dependencies like Redux. Storybook suddenly needs to know about the store.

There are multiple ways to handle this; the first is importing store at the top of you Storybook component hierarchy, then passing it as a prop all the way to the Redux-aware component.

A second is Storybook’s addDecorator function. With it, we can wrap the added component in Provider with store, allowing connect() calls to Redux:

storiesOf(‘My Components’, module)
  .addDecorator(getStory => <Provider store={store}>{getStory()}</Provider>)
  .add(‘Redux Aware Component’, () => <ReduxAwareComponent />);

Now we have a Redux-connected component in Storybook.

Multiple SSH Port Forwardings

This post by Dillon Hafer is one of my favorite remote-work tricks. Today I learned more about this part of the SSH configuration.

Multiple forwardings can be set; in a setup where port 3000 and port 9000 are important, we can forward both:

# ~/.ssh/config

Host example
  Hostname     example.com
  LocalForward 3000 localhost:3000
  LocalForward 9000 localhost:9000

Ports 3000 and 9000 will then be forwarded from the remote host. For a one-time solution, we can also add more via the command line:

$ ssh example -L 4000:localhost:4000

Combining this command and the configuration file above, ports 3000, 9000, and 4000 will be forwarded.

Git Checkout Lines of Code in Vim

Use case: you’ve made a bunch of changes to a file, and want to reset certain lines of the file back to the HEAD commit, while keeping other changes.

To solve this with git-fugitive, view the difference between your working copy and HEAD via :Gdiff . This will open two panes, HEAD (left) and your working copy (right).

Find the lines you want to reset in the working copy. Highlight those lines in Visual mode, and enter :diffget. Your working copy will restore the difference, for just the highlighted lines.

Download/Upload Redux Store In Chrome DevTools

People explaining the value of Redux as a JS state solution often point out that it’s designed to support great developer tools. Today I got a better understanding of what that means.

Chrome DevTools currently includes the toolbar shown below. The upload and download buttons, fourth and third from right, allow you to download, inspect (and edit), and upload the Redux store as a JSON file.

This is seems like a fantastic way to debug situations that might be difficult to reproduce through user interactions.

Python and Neovim

Some Vim plugins require Python, and if you’re using NeoVim, you’ll need to do a bit of extra work to get them working. An error message like this, seen when Python is definitely installed on your machine, is a hint you’re in this predicament:

$ vim
MatchTagAlways unavailable: requires python

Neovim needs its own Python support. Solve the problem with this library, specifically one of the following commands depending on your Python version:

$ pip2 install neovim
$ pip3 install neovim

CircleCI Build Forked Pull Requests

Today I learned that CircleCI does not build against forked pull requests by default. You have to enable it under ‘Advanced Settings’.

This is important if your .circleci/config.yml contains build steps like running an automated test suite, linter, or autoformatter. With this setting enabled, every PR goes through the same motions before human review, whether coming from inside or outside the project organization.

autocmd on a List of Extensions

Yesterday I was VimScripting and learned that the autocmd function can execute against multiple file extensions in a single line of setup. Here’s a contrived example:

" ~/.vimrc
autocmd BufWritePost *.exs,*.ex :! git add %

In this code, after every buffer write on files matching .ex and .exs, add the current buffer to our Git staging area. Learning this helped me reduce duplication in my configuration.

Execute Remote Commands with SSH

Today I switched workstations. As a Vim user this means copying some local dotfiles around, appending a few here, deleting a few there. It was a good reminder that executing remote commands is part of SSH.

Here’s how I’ve been appending old custom configurations on my old workstation, to others’ already existing (shared) configurations on the new machine. The quoted command is executed on the remote machine:

$ ssh jake@oldworkstation "cat ~/.vimrc.local" >> ~/.vimrc.local

List Tmux Keys

Want to see all the mapped shortcuts for your Tmux session? Try this, assuming a Tmux leader of <CRTL-Z>:

<CTRL-Z> ?

This produces a list like the following:

bind-key    -T prefix       :                 command-prompt
bind-key    -T prefix       ;                 last-pane
bind-key    -T prefix       =                 choose-buffer
bind-key    -T prefix       ?                 list-keys
bind-key    -T prefix       D                 choose-client

Chrome DevTools Audit Panel

One highlight of the Chrome 63 update was the addition of four new audits to DevTools.

‘Audits’ are one of the many DevTools panels lurking in the background, waiting to make your application better; I hadn’t noticed them until today. They will analyze and provide a downloadable report on your application’s Progressiveness, performance, accessibility, and best practices.

‘Today I Learned’ scored 91 out of 100 on accessibilty. That’s something I’d like to improve, and this panel could help direct that journey.

Limiting Mock API Restarts with Rerun

On a recent project, we built a Sinatra mock API. A feature we added early on was hot code reloading via the rerun gem. Every time a file in the API changes, Sinatra automatically restarts.

It’s a nice system but not perfect, because the server restarts on changes to any file ending in .rb, .html, .md, and number of other extensions. This captures the README, integration tests, and other undesirables, slowing everything down for no particular reason.

rerun’s --dir flag scopes it to just files in the given directory. We chose the src/ directory, which includes the API, mock database, and helpers.

$ rerun --dir src "ruby src/mock_api.rb"

Import All Exports As Object

Here’s a technique for importing constants from a file:

import * as routes from './routes'

This wraps all the exports from routes.js in the object routes. We can access any of those constants like this:

<Route path={routes.exportedPath} />

I like this technique for this use case, because it keeps our import to one line and adds a meaningful namespace.

Vi + Imitation

It’s understood in the Vim community that the name ‘Vim’ stands for ‘Vi + Improved’, because this tool improves upon the classic Vi text editor.

Last night at the Vim Chicago Meetup, I learned that ‘Vim’ once stood for ‘Vi + Imitation.’ Bram Moolenaar, the creator of Vim, changed the name when the feature surpassed the tool it was originally built to imitate.

This was one of many facts I learned during from a fantastic lightning talk on the history of Vim. We recorded it and plan to post it online soon.

Page and Search Through MySQL

Need to explore results in the MySQL REPL? The pager command can help.

Let’s set our pager of choice (we’ll use Less):

mysql> pager less
PAGER set to 'less'

Then, execute the query:

mysql> select * from users;

The result will be loaded in the Less pager. From here, we can navigate or search through the results.

Leave the custom pager with \n:

mysql> \n
PAGER set to stdout

Toggle Mirror Display (OSX)

When using a separate display like a projector, I often switch between screen mirroring (my screen matches the secondary display screen) and not mirroring. Especially during a presentation that uses both slides and live-coding in the terminal.

Instead of navigating through ‘System Preferences’ > ‘Displays’ > ‘Arrangement’, and checking or unchecking the ‘Mirror Displays’ checkbox, I can toggle between the two with ⌘ + F1.

Slow Down, Sinatra

Right now we’re using Sinatra to mock an API. An important consideration for our frontend experience: what happens when the API takes a long time to respond? How do the pages look when they are waiting on a slow, or absent, server?

Sinatra’s support of before blocks allow us to gauge this:

before do
  sleep(3)
end

get 'some/endpoint' do
  200
end

get 'some/other/endpoint' do
  404
end

With this block, every mocked endpoint will wait three seconds before responding, giving us plenty of time to consider what, in development, would otherwise be an instantaneous delay.

Chrome Dev Tools Selection Variable

Highlight a few HTML elements in the Chrome Developer Tools Elements inspector, and you’ll have a traversable history. The selected element is stored in a variable called $0. We can manipulate it like so:

> $0.click();

Try this when the selected element is hidden or difficult to click. There are four more variables representing your most recently selected elements: $1, $2, $3, and $4.

h/t Josh Branchaud

Compare Form Values with Yup

We’ve been using yup to validate a JavaScript form, and found ourselves facing a common problem when a user signs up for a service:

How do we ensure a user’s email matches their email confirmation?

yup’s test function helped us find a solution. It’s documented like this:

mixed.test(name: string, message: string, test: function)

test takes a name, a message to show on failure, and a function that returns a boolean. We paired this with the email we get from our parent.

var schema = yup.object().shape({
  email: yup
    .string(),
  emailConfirmation: yup
    .string()
    .test('match', 
      'emails do not match', 
       function(emailConfirmation) { 
         return emailConfirmation === this.parent.email; 
       }),
}),

Vim Projectionist Default File of Type

When setting up vim-projectionist, we can add a directory and filetype like this:

{
  "src/components/*.js": {
    "command": "component"
  }
}

With this in place, :Ecomponent will tab-complete to any JavaScript file in src/components, and :Ecomponent navbar will jump straight to the navbar.js component.

Let’s add a second key that includes a hard-coded file name.

{
"src/components/*.js": {
    "command": "component"
  },
  "src/components/App.js": { "type": "component" }
}

This pair tells vim-projectionist to jump to App.js if no argument is provided to :Ecomponent.

Replace App.js with your root component, and you have a shortcut to the top of your component hierarchy.