Today I Learned

A Hashrocket project

Specify Port Of CRA's Webpack Dev Server

create-react-app gives you a set of scripts, one of which allows you to start a development server that bundles and serves your javascript. This is handled under the hood via webpack-dev-server. By default it attempts to serve from port 3000. If port 3000 is taken it will attempt to connect to another sequential port.

Alternatively, you can just specify the port when starting the development server. This can be done with the PORT env var.

$ PORT=3333 yarn start

GenServer child_spec/1 in Elixir 1.5

Elixir 1.5 GenServer introduces overridable child_spec/1. Now instead of, in your application supervisor, calling;

# MyExample.Application
def start(_type, _args) do
  children = [
    worker(MyExample.MyChild, [], restart: :permanent, shutdown: 5000)
  ]
end

You can now let the child decide how its supposed to be implemented by overriding child_spec/1 in the child.

#MyExample.Application
def start(_type, _args) do
  children = [ 
    MyExample.MyChild
   ]
end

# MyExample.MyChild
def child_spec(_args) do
  %{
    id: __Module__,
    start: { __Module__, :start_link, []},
    restart: :permanent,
    shutdown: 5000,
    type: :worker
   }
end

You can view the defaults that child_spec/1 implements in the source code.

Arguments can be passed to child_spec/1 which can then be used for pattern matching and custom configurations based on the supervisor accessing it:

#MyExample.Application
def start(_type, _args) do
  children = [ 
    {MyExample.MyChild, "temporary"}
   ]
end

# MyExample.MyChild
def child_spec("temporary") do
  %{
    id: __Module__,
    start: { __Module__, :start_link, []},
    restart: :temporary,
    shutdown: 5000,
    type: :worker
   }
end

def child_spec(_) do
  %{
    id: __Module__,
    start: { __Module__, :start_link, []},
    restart: :permanent,
    shutdown: 5000,
    type: :worker
   }
end

Advanced Google Queries

You can use various techniques to narrow your Google queries:

To start, open a new tab, and google hashrocket.com. Compare those results to the following:

site:hashrocket.com This will only return resources that has a reference to this website.

site:hashrocket.com admin Same as above, but only containing resources that contain the word admin. In this case, it shows all of the TIL posts containing admin.

link:hashrocket.com Only pages that have links to hashrocket.com

related:hashrocket.com Sites that are similar to hashrocket.com (other dev shops).

source: ‘The Web Application Hackers Handbook 2’ - Dafydd Stuttard & Marcus Pinto

Message order constraint in RSpec

Sometimes you need to make sure your code is executing in a specific order. In the example below we have a Payment double that needs to first call processing! and then approved!. So you write a test like this:

it "approves the payment" do
  payment = double("Payment")

  expect(payment).to receive(:processing!)
  expect(payment).to receive(:approved!)

  payment.processing!
  payment.approved!
end

If you change the order of the method calls your test will still pass:

...
  payment.approved!
  payment.processing!
...

Finished in 0.01601 seconds (files took 0.20832 seconds to load)
1 example, 0 failures

To guarantee the order, RSpec has an option to specify an order constraint. So we want to make sure processing! is called before approved! :

 expect(payment).to receive(:processing!).ordered
 expect(payment).to receive(:approved!).ordered

Now if you run the test with the wrong order, you will see the error:

it "approves the payment" do
  payment = double("Payment")

  expect(payment).to receive(:processing!).ordered
  expect(payment).to receive(:approved!).ordered

  payment.approved!
  payment.processing!
end

Failure/Error: payment.approved!
   #<Double "Payment"> received :approved! out of order

Yarn Commands Without The Emojis

If you are a hater and you’d like to run yarn commands without emojis being playfully included in the output, just include the --no-emoji flag. The output of a command like add will look like this:

$ yarn add chalk --no-emoji
yarn add v0.17.10
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
success Saved 7 new dependencies.
├─ ansi-styles@3.1.0
├─ chalk@2.0.1
├─ color-convert@1.9.0
├─ color-name@1.1.3
├─ escape-string-regexp@1.0.5
├─ has-flag@2.0.0
└─ supports-color@4.2.0
Done in 0.54s.

See yarn help for details.

Rebase Commits With An Arbitrary Command

Interactive rebasing is a powerful way to manage and tend to the history of a git repository. Rewording and squashing commits are fairly common actions. But what if you need to run some arbitrary command against a series of recent commits?

This is where the --exec flag comes in to play.

$ git rebase -i HEAD~3 --exec "git commit --amend --reset-authors -CHEAD"

This generates an interactive rebase file that you can review and save when ready.

pick ea4a215 Add Globally Install A Package With Yarn as a javascript til
exec git commit --amend --reset-author -CHEAD
pick a4f4143 Add Initialize A New JavaScript Project With Yarn as a javascript til
exec git commit --amend --reset-author -CHEAD
pick 2f00aeb Add Default And Named Exports From The Same Module as a javascript til
exec git commit --amend --reset-author -CHEAD

As you can see, the specified command is prepared for execution for each commit involved in the rebase.

h/t Patricia Arbona

Terminate incomplete expression in IEx

Occasionally you get stuck in an incomplete expression while in IEx. Instead of figuring out which character you need to type to terminate the expression, you can terminate early with #iex:break

iex(1)> ["ab
...(1)> c"
...(1)> "
...(1)> ]
...(1)> #iex:break
** (TokenMissingError) iex:1: incomplete expression
iex(1)>

Another shortcut to achieve the same result is hit ctrl-g (User switch command), i (interrupt job), c (connect to job). This puts you right back in IEx.

iex(1)> ["ab"
iex(1)>   <<<ctrl-g typed here>>>
User switch command
 --> i
 --> c
Bug Bug ..!!** (EXIT) interrupted
iex(1)>

Expect page to have a link... an exact link

Sometimes, while writing integration tests, we expect there to not be a link on a page, for instance if our page looked like this:

<a href="#create_jetpack">Create Jetpack</a>

And we want to make sure there is no general create link so we expect this:

expect(page).to_not have_link('Create')

But the expectation fails! By default capybara will match if the substring is anywhere in the content.

To avoid this problem use the exact flag like:

expect(page).to_not have_link('Create', exact: true)

Default And Named Exports From The Same Module

ES6 module syntax allows for a single default export and any number of named exports. In fact, you can have both named exports and a default export in the same module.

Here is an example:

// src/animals.js
export default function() {
  console.log('We are all animals!');
}

export function cat() {
  console.log('Meeeow!');
}

export function dog() {
  console.log('Rufff!');
}

In this case, you could import the default and named exports like so:

// src/index.js
import animals, { cat, dog } from './animals.js';

animals(); // "We are all animals!"
cat();     // "Meeeow!"
dog();     // "Rufff!"

source

"experience uses an unsupported version of Expo"

error

If this happens when developing a React Native app with Expo and trying to test it in the iOS Simulator, it means the version of Expo on the iOS Simulator is out of date.

To fix that try the following:

  1. Quit the Expo app on the simulator
  2. Uninstall the Expo app on the simulator
  3. Lunch the app again in the simulator from the Expo XDE

This will cause the Expo app on the simulator to reinstall with the latest version.

Move window (tab) in tmux

To move a new window to the left do this:

tmux-prefix, :swap-window -t -1

To move window to the right

tmux-prefix, :swap-window -t +1

You can also bind a key to that command:

bind-key S-Left swap-window -t -1
bind-key S-Right swap-window -t +1

Now it will be tmux-prefix, Shift + Left and tmux-prefix, Shift + Right

Require local package in mix.exs

In Elixir as you are writing your application it is recommended to split parts of it into smaller applications (also can be called micro-services if you want to be buzzword compliant).

You don’t however need to publish those dependencies to the Hex package manager in order to load them, instead you can use the path argument when defining a dependency.

In this example we have our main application Foo and in the directory above it we have an application called Bar.

To make the Bar module available in Foo we can do it like so:

mix.exs

defp deps do
  [
    {:bar, path: "../bar"},
  ]
end

List Merged Branches

Today I learned a new Git trick: to show branches already merged into a branch, try this command:

$ git branch --merged master
  add-basic-auth
  add-channels
  add-developer-username
  add-developers
  add-developers-show
  add-hashtag-to-slack-post

For an open source project like Today I Learned, this is an interesting way to get a sense of the project.

Module attribute constants nil in Elixir

Module attributes in elixir (@something) can be used as constants and assigned a value, however one must make sure that the value assigned to the constant is available at compile time.

For example when using a constant that loads environment variables if the value is not available in compile time they will resolve to nil.

@salt System.get_env(:your_app_name, "AUTH_SALT")

So either export the environment variables before compiling, or don’t use module attributes, instead you can use a function:

defp salt do
  System.get_env(:your_app_name, "AUTH_SALT")
end

Consider:

  • The downside to using a function is that it will be re-evaluated each time.
  • The downside of exporting env-vars before compile is that they you might forget and your app will crash in production. You can circumvent that by writing a script for compilation.
  • You can also call System.get_env from your config.exs but make sure to run mix clean after doing so since the compiler seems to cache the config compilation.

Weekly jobs in crontab

The syntax for crontab entries is confusing at best. Fortunately, cron provides easy to read special strings for common cases.

If you want a job to run once a week your crontab would look like this:

@weekly /usr/bin/my_job

And thats it! @weekly in this case means 0 0 * * 0. Every Sunday at midnight.

You can check other crontab special strings with man 5 crontab.

H/T Dorian Karter

Authenticate With Username or Email

Today I learned a way to implement a login form that accepts email or username as the login. I’ve been on the other side of a form like this many times, but had never written one myself.

Here’s one solution, with ActiveRecord:

User.where('username = ? or email = ?', "jwworth", "jake@example.com")

title or slug are represented by the same parameter, and either can be nil.

login = params.fetch('username_or_email')
User.where('username = ? or email = ?', login, login)

Vim move cursor within a visual selection

When expanding a visual selection you might want to increase both sides. For instance, if you have made a selection from line 20 to line 40 you may want to expand the selection to line 18 to line 42. The visual selection can only be expanded with the cursor and the cursor is only on one side, but the cursor can be moved to the other side of the selection with o.

Read more about it with: :help visual-change.

Convert nested JSON object to nested OpenStructs

If you are parsing a nested JSON string such as this:

{
   "vendor": {
       "company_name": "Basket Clowns Inc",
       "website": "www.basketthecloon.com"
 }

And want to access it with dot notation, simply doing:

OpenStruct.new(JSON.parse(json_str))

will not do!

Turns out there is a cool option on JSON.parse called object_class:

JSON.parse(json_str, object_class: OpenStruct)

Now you can access the resulting object with dot notation all the way down:

obj.vendor.website #=> "www.basketthecloon.com"

Toggle line numbers in VIM

I often find myself needing to turn line numbers on and off in VIM. I’ve typically typed out the full

off - set nonumber and on - set number

Theres also abbreviations:

off - set nonu and on - set nu

TIL you can also toggle quickly between on and off by using:

set nu!

h/t Jason Cummings

Allow an Empty Commit

Today my pair did something I’d never seen: create an empty commit. Out goal was to test a third-party integration, but we didn’t have a meaningful change to contribute at the time. In this situation, I think an empty commit is a good compromise, because it’s honest about our intent— to simply kick off a remote process.

Here was the command:

$ git commit --allow-empty

h/t Dorian Karter

Fork A Heroku Project

The Heroku CLI has a useful command I recently learned about, called heroku fork. Here’s how it works:

$ heroku fork --from tilex-staging --to tilex

As the example suggests, I’ve used this tool to clone a tricky-to-set-up Heroku staging application as a production application. It’s great.

The bad news is that Heroku us sunsetting fork as a core CLI command. Use it while you can. After that, you can fork the Github repo and use it as CLI plugin.

Set filetype/settings for a specific file in Vim

Given a file with a weird extension but an underlying known filetype e.g. yaml file with a .config extension. It is possible to force vim to set the filetype to yaml for that file:

At the top/bottom of the file add a comment (with the filetypes acceptable comment syntax - for yaml it is #):

# vi: ft=yaml
baz:
  foo: 'bar'

Re-open the file and vim will automatically set the filetype to yaml for that file.

This can also be used for setting other setting such as shiftwidth, tabstop etc

I’ve been using this trick for a while but keep forgetting it the exact syntax, usually using # vim: instead of # vi:. Hopefully my wording will make it more easily duckduckgoable.

Ruby Object Reference in blocks

Usually when I want to set the value of a variable by yielding to a block, I will explicity set it

  x = 'something'
  x = yield(x)
  #....

Turns out ruby will treat different types of objects different when yielded to a block (remember everything is an object). If you are yielding an Integer, or String for (a contrived) example:


def do_stuff_by_val
  do_block_stuff_by_val do |name|
    name += 'rocket'
  end
end

def do_block_stuff_by_val
  company_name = 'hash'
  yield(company_name)
  puts company_name #prints 'hash', not 'hashrocket'
end

If we wanted the company name to change to “hashrocket”, we would need to explicitly set the variable to the result of yielding:

company_name = yield(company_name)

Other types of objects do not behave this way (hash or array). If we yield a hash and set a key, the hash in the calling method will be updated:


def do_stuff_by_object_reference
  do_block_stuff_by_object_reference do |company|
    company[:name] = 'hashrocket'
  end
end

def do_block_stuff_by_object_reference
  company = {}
  yield(company)
  puts company # { name: 'hashrocket'}
end

Typing card suits in vim ♢♡♣♠

Digraphs are two letter combinations that provide a easy way to type and remember non-ascii characters in vim. In insert mode you can type a digraph with Ctrl-k and then two letters that map to the unicode character.

For card suits the pneumonic is lower case c for card and upper case C for clubs, D for diamonds, H for hearts, and S for spades.

cD ♢
cC ♣
cH ♡
cS ♠

You can see all the digraphs with :digraphs.

Now you have all the necessary unicode characters to easily create card games in the terminal!

Show Tables That Match A Pattern In MySQL

An unfamiliar MySQL database with tons of tables can be a difficult thing to navigate. You may have an idea of the kind of table you are looking for based on a domain concept you’ve seen elsewhere.

You can pare down the results returned by show tables by including a like clause with a pattern. For example, this statement will show me only tables that have the word user in them:

> show tables like '%user%';
+-------------------------------+
| Tables_in_jbranchaud (%user%) |
+-------------------------------+
| admin_users                   |
| users                         |
+-------------------------------+

Resetting the bundler --path

When running bundler install you can pass an option --path <dir>:

bundle install --path ./gems

Which will specify where to install the gems. This is a one time option. Everytime you invoke bundle from here on in you’ll see that its using the directory you specificed with the —path variable as the gem directory.

Bundler keeps track of this option in the .bundler/config file in the folder from where bundler was initially run. That file looks like this:

---
BUNDLE_PATH: "./gems"
BUNDLE_DISABLE_SHARED_GEMS: "true"

To reset the gems path back to the default, remove the BUNDLE_PATH line from the bundle/config file.f

Rename A Remote

If you just added a remote (git remote add ...) and messed up the name or just need to rename some existing remote, you can do so with the rename command.

First, let’s see the remotes we have:

$ git remote -v
origin  https://github.com/jbranchaud/til.git (fetch)
origin  https://github.com/jbranchaud/til.git (push)

To then rename origin to destination, for example, we can issue the following command:

$ git remote rename origin destination

See man git-remote for more details.

Override ssh command for git

Git supports a number of environment variables one of them being GIT_SSH. You can override the default ssh command (ssh of course) with that environment variable.

GIT_SSH=./my_ssh git pull origin master

In this case my_ssh is a bash executable file that looks like this:

#!/bin/bash

ssh -i ~/.ssh/id_rsa $1 $2

An idea I got from this stack overflow answer.

Clearly the private key file I used is the default private key file so a bit redundant but its a way to add any options that might be necessary for the ssh connection, although specifying a host configuration in the ssh_config file might be simpler.

Dump A MySQL Database To A File

The mysqldump client is a handy tool for creating a backup or snapshot of a MySQL database. The standard use of this command produces an alphabetical series of statements that comprise the structure and data of the specified database. It directs all of this to stdout. You’ll likely want to redirect it to a file.

$ mysqldump my_database > my_database_backup.sql

The output will include special comments with MySQL directives that disable things like constraint checking. This is what allows the output to be in alphabetical order without necessarily violating any foreign key constraints.

If you need to dump multiple databases, include the --databases flag with a space-separated list of database names. Or dump all of them with --all-databases.

See man mysqldump for more details.

Reinstall all rubies with rvm

When compiling ruby the executable is attached to various C system libs like libreadline. If libreadline is updated then each ruby on the system attached to the old libreadline must be re-compiled. If you are using rvm then this can be done with one command:

rvm reinstall all --force

The --force flag will skip any question the process asks.

Be careful, if you are working on a machine that has installed many rubies and has had many projects for those rubies this could take an extraordinarily long time.

Specifying the private key to use in ssh

A private key is necessary in ssh to authenticate the connection securely. Generally ssh will look for a file in the ~/.ssh/ dir with a name of id_rsa (or if not using rsa a file beginning with id_ and the encryption algo name). That file should contain the private key.

You can, however, specify a different primary key at the command line with the -i flag like so:

ssh -i ~/.ssh/my_other_key.pem

Additionally, you may use the IdentityFile option the the ssh_config file to permanently configure the private key for a specific connection.

Display Output In A Vertical Format In MySQL

Output for tables with lots of columns can be hard to read and sometimes overflow the terminal window. Consider the output from Show Indexes For A Table:

> show indexes in users;
+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name     | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| users |          0 | PRIMARY      |            1 | id          | A         |           0 |     NULL | NULL   |      | BTREE      |         |               |
| users |          0 | unique_email |            1 | email       | A         |           0 |     NULL | NULL   |      | BTREE      |         |               |
+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

We can vertically orient the output of a statement by terminating it with \G instead of ; (or \g).

> show indexes in users\G
*************************** 1. row ***************************
        Table: users
   Non_unique: 0
     Key_name: PRIMARY
 Seq_in_index: 1
  Column_name: id
    Collation: A
  Cardinality: 0
     Sub_part: NULL
       Packed: NULL
         Null:
   Index_type: BTREE
      Comment:
Index_comment:
*************************** 2. row ***************************
        Table: users
   Non_unique: 0
     Key_name: unique_email
 Seq_in_index: 1
  Column_name: email
    Collation: A
  Cardinality: 0
     Sub_part: NULL
       Packed: NULL
         Null:
   Index_type: BTREE
      Comment:
Index_comment:

Show Indexes For A Table In MySQL

When describing a table, such as users:

> describe users;
+------------+-----------------------+------+-----+---------+----------------+
| Field      | Type                  | Null | Key | Default | Extra          |
+------------+-----------------------+------+-----+---------+----------------+
| id         | mediumint(8) unsigned | NO   | PRI | NULL    | auto_increment |
| first_name | varchar(80)           | NO   |     | NULL    |                |
| last_name  | varchar(80)           | NO   |     | NULL    |                |
| email      | varchar(80)           | NO   | UNI | NULL    |                |
+------------+-----------------------+------+-----+---------+----------------+

We can see in the Key column that there’s a primary key and a unique key for this table on id and email, respectively.

These keys are indexes. To get more details about each of the indexes on this table, we can use the show indexes command.

> show indexes in users;
+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+
| Table | Non_unique | Key_name     | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type |
+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+
| users |          0 | PRIMARY      |            1 | id          | A         |           0 |     NULL | NULL   |      | BTREE      |
| users |          0 | unique_email |            1 | email       | A         |           0 |     NULL | NULL   |      | BTREE      |
+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+

Hack to size the container of a background image

An element that contains a background image cannot have its height and width derived from that background image. An element can have a height and width that is determined by the size of a child element however. Combine the two to ensure that the container of the background image has the height and width of the image itself.

<div style="background-image: url('http://example.com/image.png')">
    <img src="http://example.com/image.png">
</div>