Today I Learned

A Hashrocket project

Find an npm library from the command line

When looking for a new package to use with npm you can use npm search <string>. This will query npm and return 20 - 25 results that match your search.

> npm search react-router
NAME                      | DESCRIPTION          | AUTHOR          | DATE       | VERSION  | KEYWORDS
react-router              | Declarative routing… | =ryanflorence   | 2017-08-24 |          | react router 
react-router-dom          | DOM bindings for…    | =mjackson…      | 2017-08-24 |          | react router 
react-router-redux        | Ruthlessly simple…   | =jlongster…     | 2017-02-10 |          | react redux r
react-router-native       | React Native…        | =jmurzy…        | 2017-08-24 |          |
react-router-config       | Static route config… | =mjackson…      | 2017-08-24 |          | react router 
react-router-bootstrap    | Integration between… | =monastic.panic… | 2017-04-19 |          | react react-
react-router-scroll       | React Router scroll… | =taion          | 2017-04-10 |          | react react r
react-native-router-flux  | React Native Router… | =aksonov        | 2017-08-23 |          |
...

There doesn’t seem to be a way to search by date, version or popularity, but if you pass the --long flag you’ll be able to see the entire description. Without the --long flag the results will be truncated to fit onto one line.

Check that an executable exists on the $PATH

When writing a vim plugin interacting with different programs on the server might be necessary. For instance you might want to use ruby to make a network request or perform some file management. But first, the vim plugin should check to see if the program ruby exists which can be accomplished with the executable() vimscript function.

:echo executable('ruby')
1
:echo executable('doesnotexist')
0

This can be used in a condition before running the ruby command.

if executable('ruby')
  system('ruby -e "puts YAML"')
endif

CamelCase to underscore and back again w/Elixir

If you have a mix project name with multiple words, then those multiple words are generally separated with underscores in the project directory name, like honey_bears. The module name for the project however is HoneyBears.

Converting a string from underscore to CamelCase is built into Elixir. Its in the Macro module:

> Macro.camelize("honey_bear")
"HoneyBear"

The reverse case also can be solved with a Macro function.

> Macro.underscore("HoneyBear")
"honey_bear"

The Macro module has a number of convience functions for working with macros.

Elixir Static Code Analysis in Vim

Today I learned how to set up Credo, a static analysis tool for Elixir, to run on every Vim buffer write, using Neomake.

To start, I added Credo to my project:

# mix.exs
defp deps do
  {:credo, "~> 0.8", only: [:dev, :test], runtime: false}
end

Including it with:

$ mix deps.get

Next, I loaded and sourced the Neomake plugin with Pathogen:

" ~/.vimbundle
neomake/neomake

Next, I told Neomake to run on every file, enabling Credo for Elixir files:

" ~/.vimrc
let g:neomake_elixir_enabled_makers = ['credo']
autocmd! BufWritePost * Neomake

Now I have Credo style recommendations right in my text editor.

Specifying the location of your vim plugin

If you are working on a vim plugin and you want to keep this plugin amongst your projects rather than with your other vim plugins you can add a new entry to the runtimepath or rtp.

Place the following in your vimrc:

set runtimepath+=~/projects/vim-my-plugin

Or

set rtp+=~/projects/vim-my-plugin

You can confirm that the path was added correctly by checking that setting with:

set rtp

Set the Domain or Host in Rails URL Helpers

You can explicitly set the domain with Rails URL Helpers:

app.root_url
=> "http://www.example.com/"

app.root_url(domain: 'www.customdomain.org')
=> "http://www.customdomain.org"

 

If we include the protocol in our domain argument, this brings up an interesting gotcha. Check it out:

app.root_url(domain: 'http://www.customdomain.org')
=> "http://www.http://www.customdomain.org/"

 

Thankfully, Rails gives us the host option. Host will use a Regex to remove the protocol from the argument:

app.root_url(host: 'https://www.customdomain.org')
=> "http://www.customdomain.org/"

 

Notice the output in the last example; our protocol was replaced removed and replaced with http. You can use the protocol argument to enforce your protocol on a given host:

app.root_url(host: 'http://www.customdomain.org', protocol: 'https')
=> "https://www.customdomain.org/"

Resize vim window to the size of its content

If you’re writing a vim plugin and in that plugin you are opening a new window to display some content, you may want to resize that window so that it is only the size of the content within. For instance, if you have 10 lines of content but the window is half the screen, then you want to resize the window to 10 lines.

Resizing a window is accomplished with the resize command like:

:resize 10

Getting the number of content lines is accomplished by getting the line number of the last last:

:echo line('$')

Putting the two together is tricky because the argument to the resize command is interpreted literally. :resize line('$') does not work. You have to combine the two into a string and then pass it to the execute command.

:execute('resize ' . line('$'))

List Files Ordered By Modification Date

The ls command lists the files in a directory. Tacking on the -l flag will list it in long format. By default, everything is listed in lexicographical order. This is what ls -l looks like for this repository.

-rw-r--r--    1 jbranchaud  staff    628 Feb 14  2016 CONTRIBUTING.md
-rw-r--r--    1 jbranchaud  staff   1058 Feb 19  2015 LICENSE
-rw-r--r--    1 jbranchaud  staff  40983 Aug 18 16:59 README.md
drwxr-xr-x    5 jbranchaud  staff    170 Apr  1 14:45 ack
drwxr-xr-x    5 jbranchaud  staff    170 Feb 24 16:31 chrome
...

Sometimes you want a sense of what has been modified and when. Lexicographical order isn’t going to help much here. By tacking on the -t flag, the files will be listed in order of their modification dates. Here is ls -lt for the same repository.

-rw-r--r--    1 jbranchaud  staff  40983 Aug 18 16:59 README.md
drwxr-xr-x  119 jbranchaud  staff   4046 Aug 17 11:38 vim
drwxr-xr-x    5 jbranchaud  staff    170 Aug 16 10:47 internet
drwxr-xr-x   23 jbranchaud  staff    782 Aug  1 10:17 javascript
drwxr-xr-x    7 jbranchaud  staff    238 Jul 22 14:04 webpack
...

See man ls for more details.

Complete a Whole Line in Vim

This week I picked up an excellent Vim command: CTRL-X CTRL-L. This command searches backwards through your project and inserts a matching line after the cursor.

So, if there’s a line in your project like this:

defimpl Phoenix.Param, for: Tilex.Developer do

And I type defimpl (which is unique enough to match only a lines of code in my project), Vim will suggest matching options, letting me choose a match to complete it:

defimpl Phoenix.Param, for: Tilex.Developer do
defimpl Phoenix.Param, for: Tilex.Developer do

This is useful when writing code in a framework like React.js, where the head of many files often includes a group of common and repetitive import statements.

See ‘Insert mode completion’ inside insert.txt in the Vim help for more information.

h/t Dorian Karter

Prettier ignore! 💁 #javascript

Prettier is super helpful but sometimes you just want to format things your way if the output of prettier is not very readable.

To solve this, prettier provides a comment that you can put above any “node” in the resulting javascript AST.

For example:

BEFORE (w/ prettier)

const street_number = this.findAddressComponent(
  resultObj,
  'street_number'
).long_name;
const route = this.findAddressComponent(resultObj, 'route').long_name;
const zip_code = this.findAddressComponent(resultObj, 'postal_code')
  .long_name;
const city = this.findAddressComponent(resultObj, 'locality').long_name;
const state = this.findAddressComponent(
  resultObj,
  'administrative_area_level_1'
).short_name.toUpperCase();

The above is a result of prettier formatting and is not very readable or pretty - so I would need to turn it into a single AST node and put the prettier-ignore comment over it:

AFTER (w/ prettier-ignore)

// prettier-ignore
const address = {
  street_number: this.findAddressComponent(resultObj, 'street_number').long_name,
  route: this.findAddressComponent(resultObj, 'route').long_name,
  zip_code: this.findAddressComponent(resultObj, 'postal_code').long_name,
  city: this.findAddressComponent(resultObj, 'locality').long_name,
  state: this.findAddressComponent(resultObj, 'administrative_area_level_1').short_name.toUpperCase(),
}

Now the address components will be accessible from the address object (e.g. address.route) and while still not the prettiest, it is a lot more readable IMO.

Quickly Switch To A Buffer By Number

There are a number of different commands you can use for switching to a buffer by its number. For example, if you want to switch to the buffer assigned 7, you can do :7b or :e #7. However, there is a quicker way than typing out either of those commands.

You may already be familiar with CTRL-^ for switching to the alternate file which is generally the previous buffer. If you precede that command with a number, you will switch to the buffer with that number instead of the alternate file.

From normal mode

7 Ctrl-^

will switch to buffer 7.

See :h Ctrl-^ for more details.

Alias A Model Method Or Field in a GraphQL Type

If you need to override the name of a model method or field in a GraphQL type, you can use the property argument.

Let’s say we have a model called Message:

class Message < ApplicationRecord
  def bar
    "bar"
  end
end

We can then make an alias to the bar method by specifying a property in our MessageType:

Types::MessageType = GraphQL::ObjectType.define do 
  field :foo, types.String, property: :bar
end

Handle JS Errors in React 16

React 16 introduced a new method called componentDidCatch to catch all JS errors. It can catch errors during rendering, lifecycle methods and constructors of the whole tree below.

class App extends React.Component {

  componentDidCatch(error, info) {
    ErrorService.log(error, info);
  }

  render() {
     // code that raises error, it could come from this component or its children.
  }
}

Configure max http header size in Elixir Phoenix

If you store lots of data in cookies, you may eventually run up against the maximum header value length in Cowboy which by default is 4096.

While storing that much data in cookies is maybe not the best idea, there is a configuration setting that can help you work around this issue:

config :myapp, MyAppWeb.Endpoint,                                                                                                                 
  http: [protocol_options: [max_request_line_length: 8192, max_header_value_length: 8192]]

There ya go! Now you can accept http header values up to 8192 bytes in length!

Search Tweets By Author

Twitter has some advanced search features that allow you to do more than just search by keyword. The from:<author> syntax is the way that you can restrict your search results to a specific twitter user.

twitter from search

By using "pair programming" from:hashrocket, I am able to find all of the tweets by @hashrocket that use the exact phrase pair programming.

Check to see if a command exists at #shell

If you want to check to see if a command exists on a user’s machine you can use command -v. command without flags will run the command passed as an argument.

> command echo "A"
"A"

command -v with the -v flag will return the path of the command, and most importantly, a non-zero status code if that command does not exist.

> command -v brew
/usr/local/bin/brew

Or on Linux

> command -v brew
# returns nothing and also returns a status code of 1

Importantly, you can check for a command before using it.

command -v brew && brew install something

Detect If You Are On A Mac

There are a couple ways of detecting with vimscript if you are on a mac. This can be useful if you are writing a plugin with OS-specific functionality. Here are two ways to make that check.

if has('macunix') || has('mac') || has('osx')
  ...
endif

Alternatively, you can use Vim’s system() function to execute unix’s uname command. This command will give you the name of the operating system. In the event you are using a Mac, the result of uname should be Darwin. The following regex match is a good way to make this check.

if system('uname') =~ "Darwin"
  ...
endif

See :h has(), :h system(), and man uname for more details.

Phoenix will watch your JS for you, just watch!

With es6 javascript ecosystems most compilation/transpilation is done with watchers, programs that watch for changes in your code and then trigger compilation based on the changes you’ve made.

Phoenix has a method of integrating those watchers into the server itself.

config :myapp, MyApp.Endpoint,
  watchers: [yarn: ["run", "watch", cd: Path.expand("../assets", __DIR__)]]

The above configuration goes in config/dev.exs and runs the watch command whenever you start the server/endpoint. The keyword option cd is as of yet undocumented, but does what you think it does, changes the directory to the path you configure, which by convention in Phoenix 1.3 would be the assets directory. cd is the only keyword option.

The watchers start when you run your server. Just make a change to your javascript and refresh the page!

String concatentation in the Bourne Again Shell

String concatenation must be different in every lanaguage, or so it seems, and Bash is no different! You can string concat just by putting too strings next to each other.

> echo "a""b"
ab 

Its ok if one of these strings is a variable.

> a = "x" 
> echo $a"b"
xb

Its ok if you put a double quoted string next to a single quoted string.

> echo 'a'"b"
ab

Its ok if you put spaces in between the strings, but that space now will be part of the new string.

> echo "a" "b"
a b

But multiple spaces in between strings will be squashed to one string.

> echo "a"      "b"
a b

This works when setting a variable too, but only surrounded by parens.

> c=('a'      'b')
> echo $c
a b

Don’t worry about the parens though when they are right next to each other.

> c = "a""b"
> echo $c
ab

Edit bash command at certain point in history

Jack introduced our team to the fc command a couple weeks ago. We had a command in our history that we wanted to edit, but it was not the last command. In fact, it was several 100 commands up in our history.

It turns out that the fc command takes an id argument, and each item in history has an id. To find the id of the particular command we wanted we ran:

> history | grep curl
10256 curl www.google.com
10500 curl www.amazon.com

To edit the first command listed in curl we just use:

fc 10256

H/T Ifu Aniemeka

Execute raw parameterized sql with Ecto in Elixir

Using sql directly is a good way to use some of the more interesting parts of sqlthat Ecto does not provide a ready abstraction for in its dsl. And parameterization is necessary to avoid sql injection and just to be able to deal with single quotes correctly. Its fairly straight forward once you find the right module (Ecto.Adapters.SQL) and function (query or query!). Parameters are indicated by $1.

sql = """
  select * from users where name = $1;
"""

results = Ecto.Adapters.SQL.query!(MyApp.Repo, sql, ["chris"])

There is also a stream function on the Ecto.Adapters.SQL module with the same signature as query but the documentation doesn’t necessarily state the advantages or situations where it may be useful. More to learn.f8

Load all records for an association in Ecto

Lets say you get a collection of Posts with:

posts = Repo.all(Post)

If you try to access the associated developer for one of these posts, you get an error:

hd(posts).developer
#Ecto.Association.NotLoaded<association :developer is not loaded>

The same is true for all posts in the collection, none of them have a loaded developer. You can load them one by one with:

developer = Tilex.Repo.one(Ecto.assoc(post, :developer))

But if you need to do this for each developer you’ll get into an N+1 situation, making an additional trip to the database for each post.

Instead you can load all the developers at one time with:

posts = Repo.preload(posts, :developer)

Clearing Phoenix npm cache on Heroku

I recently encountered an issue where the solution, as found on the internet, was to remove all the npm_modules, re-install them and build again. My issue however was on Heroku rather than local.

If you’re using Elixier and Phoenix on Heroku then you’re likely using the heroku-buildpack-phoenix-static. This buildpack compiles the static assets for Phoenix.

This buildpack caches npm_modules by default, to clear the cache you must provide a configuration file at the root level of your project named phoenix_static_buildpack.config that looks like:

clean_cache=true

The buildpack will now download the npm_modules on each deployment.

What applications are running in your Elixir app?

Ever wonder what applications are running in your Elixir or Phoenix app?

Pop open IEx and take a look with Applications.started_applications/1

iex(1)> Application.started_applications
[{:tilex, 'tilex', '0.0.1'},
 {:ueberauth_google, 'An Uberauth strategy for Google authentication.',
  '0.6.0'},
 {:ueberauth, 'An Elixir Authentication System for Plug-based Web Applications',
  '0.4.0'}, {:oauth2, 'An Elixir OAuth 2.0 Client Library', '0.9.1'},
 {:timex,
  'Timex is a rich, comprehensive Date/Time library for Elixir projects, with full timezone support via the :tzdata package.\nIf you need to manipulate dates, times, datetimes, timestamps, etc., then Timex is for you!\n',
  '3.1.24'},
 {:combine, 'A parser combinator library for Elixir projects.', '0.9.6'},
 {:tzdata, 'Tzdata is a parser and library for the tz database.\n', '0.5.12'},
 {:postgrex, 'PostgreSQL driver for Elixir.', '0.13.3'},
 {:db_connection,
  'Database connection behaviour for database transactions and connection pooling\n',
  '1.1.2'},
 {:connection, 'Connection behaviour for connection processes\n', '1.0.4'},
 {:phoenix_html,
  'Phoenix.HTML functions for working with HTML strings and templates',
  '2.10.2'}, {:phoenix_ecto, 'Integration between Phoenix & Ecto', '3.2.3'},
 {:ecto, 'A database wrapper and language integrated query for Elixir.\n',
  '2.1.4'}, {:poolboy, 'A hunky Erlang worker pool factory', '1.5.1'},
 {:decimal, 'Arbitrary precision decimal arithmetic.', '1.4.0'},
........

Suppress errors when substituting in vim

The substitute (or s) command in vim throws an error the search pattern is not found.

:substitute/banana/apple
E486: Pattern not found: banana

This error can be suppressed with the e flag at the end of the statement.

:substitute/banana/apple/e

When operating in just one file or on just one line the error is a minor annoyance but when combining the substitute command with :argdo you receive an error for every file in the args list that does not contain the pattern in question.

A typical argdo command would look like this.

:argdo s/banana/apple/gec

The flags are:

g - global

e - suppress errors

c - confirm

tmux copy-mode -u, useless or useful?

Tmux comes with a key binding for both copy-mode and copy-mode -u. The first is straight forward, you can navigate through the window history, highlight something and place it into your tmux buffer. I was curious about what the -u flag was for, and the man page says:

The -u option scrolls one page up.

So the -u option just places you into copy-mode one page up. Useless! Or wait, maybe that’s something I want…

Check For An Executable

Sometimes Vim needs to reach outside of itself to use an existing program. For example, wiring up auto-formatting of JavaScript code requires Vim to call out to the prettier binary.

We want our .vimrc files and plugins to, generally, be as portable as possible. What happens if you haven’t yet installed a particular program? Vim will likely experience a runtime exception. One way to get around this is to check for the presence of that program on the path. If it isn’t there, don’t do the thing. We can use the executable() function for this.

if executable('prettier')
  ...
endif

It will return 1 (true) if prettier is an executable on the path, otherwise it will return 0 (false).

See :help executable() for more details.

Create Bootstrapped Apps With Yarn

The yarn cli comes with a create command that is a convenience command for generating bootstrapped apps that follow the create-<name>-app convention.

Want to create a React.js app using create-react-app, invoke the following command:

$ yarn create react-app my-app

Don’t already have a particular package globally installed? yarn create will install it for you. For instance, the following command with install and use create-vue-app:

$ yarn create vue-app my-other-app

h/t Gabe Reis

Difference between `union` and `union all` in psql

union is an operator that operates on two sets of results, combining them:

chris=# select 1 union select 2;
 ?column?
----------
        1
        2
(2 rows)

It filters duplicate results though:

chris=# select 1 union select 1;
 ?column?
----------
        1
(1 row)

If you want to not worry about duplicate results and just stack the result sets on top of each other use union all:

chris=# select 1 union all select 1;
 ?column?
----------
        1
        1
(2 rows)

Enable history in IEX through #erlang (OTP 20) ⏳

If you are using the latest version of Erlang, OTP 20 now ships with shell history, so you can use Ctrl-p / Ctrl-n or the up/down arrow keys.

The shell history is turned off by default though, so you will have to turn it on by adding the following to your .zshrc/.bashrc etc.

export ERL_AFLAGS="-kernel shell_history enabled"

Once you do that make sure to source your bash config file or open a new window.

Every subsequent iex session will now have shell history. 🚀

Postgres Natural joins squash unneeded columns

Dealing mostly with Rails style databases we generally write inner joins on ids and foreign keys but there are other ways to create joins, the most fun being the natural join.

The below query works like a natural join but uses inner join syntax. When two tables having columns with the same name, join on that column. You can see that both columns have been returned even though they have the same value.

chris=# select * from (select 1 x) foo inner join (select 1 x) bar on bar.x = foo.x ;
 x | x
---+---
 1 | 1
(1 row)

When using the natural join syntax the query is less verbose and only returns one column. Postgres knows that they have the same value, thats the whole point! So only present one column.

chris=# select * from (select 1 x) foo natural join (select 1 x) bar;
 x
---
 1
(1 row)

Skip all changes in this file

git add --patch gives you the opportunity to make a decision on every code change in all files individually, providing you a menu that looks like this:

Stage this hunk [y,n,q,a,d,/,j,J,g,e,?]?

Option d is

d - do not stage this hunk or any of the later hunks in the file

This comes in handy when there is a host of whitespace changes in a file that you don’t want to commit. Just hit d to skip all those whitespace changes and go to the next file.

Postgres `coalesce` errors with multiple types

The Postgres function coalesce takes a variable number of arguments and returns the first non-null argument.

psql> select coalesce(null, null, null, null, 'hi!');
hi!

But if you include a number and a string, then Postgres throws an error.

psql> select coalesce(1, 'hi!');
ERROR:  invalid input syntax for integer: "hi!"

Coalesce will try to coerce value to the type of the first argument if possible.

psql> select coalesce(1, '2');
1

Mysql behaves a bit differently, it allows values of different types.

mysql> select coalesce(1, 'hi!');
1

The postgres way makes a bit more sense to me. What is the type of a column if there are multiple possible types? Is it always a string? But I wanted a number? I feel like the additional type safety will help catch errors a bit earlier.

Screengrab to Clipboard on Mac

If you’ve ever taken a screengrab on a Mac with CMD + Shift + 4, then pasted or dragged that image into a text area such as a Github issue description, there is a better way: CMD + CTRL + Shift + 4. This captures your screengrab right to the clipboard, ready to paste wherever.

The equivalent command with 3– take a screenshot– also works as expected.

This isn’t a particularly ergonomic key combination, but it helps when adding visuals to bug reports and feature requests.

h/t Dorian Karter

Has ActiveRecord::Relation already been grouped?

I’ve recently run into a situation where I needed to apply a group statement to an ActiveRecord scope if a group statement had already been applied. In this case we need to examine the current scope to see if in fact a group statement has already been applied. ActiveRecord::Relation fortunately has a group_values method that returns an array of all the columns that the query has been grouped by as symbols.

if current_scope.group_values.length > 1
  current_scope.group(:another_column)
else
  current_scope
end

Setting breaks in IEx for debugging

With the release of Elixir 1.5 comes some handy new IEx helpers, one of which is the ability to add break points throughout your code.

You can add a break to any function using break!/2 or break!/4:

defmodule MyModule do
  def hello(name) do
    "hello " <> name
  end
end
iex(1)> break!(MyModule.hello/ 1)
or
iex(1)> break!(MyModule, :hello, 1)

Both break/2 and break/4 accept an additional argument for how many stops you want to make. Useful for recursive functions where you may want to stop multiple times.

To see what breaks you have use breaks/0

iex(1)> breaks()
 ID   Module.function/arity   Pending stops
---- ----------------------- ---------------
 1    MyModule.hello/1        1

Now when you call the function, you’ll be placed into the a debugger and you can inspect whats being passed in:

iex(4)> MyModule.hello("world")
Break reached: MyModule.hello/1 (lib/my_module.ex:2)
    1: defmodule MyModule do
    2:   def hello(name) do
    3:     "hello " <> name
    4:   end
pry(1)> name
"world"

To exit the break and start a new shell process use respawn/0

pry(2)> respawn
Interactive Elixir (1.5.0) - press Ctrl+C to exit (type h() ENTER for help)
"hello world"
iex(1)>

Operators to get a string or more json in Postgres

There are two operators in Postgres that I have trouble telling apart. The -> operator and the ->> operator. They both take a json object on the left and a key on the right, but result in different types.

Given json in postgres that looks like this:

> select '{"a": {"b": 2}}'::jsonb;
{"a": {"b": 2 }}

I can traverse the data structure with the -> operator because it returns a data structure.

> select '{"a": {"b": 2}}'::jsonb  -> 'a' -> 'b';
2

I can get a value as a string from the json with the ->> operator.

> select '{"a": {"b": 2}}'::jsonb ->> 'a';
{"b": 2 } -- ITS A STRING

But if you use the ->> operator to get a string, then you can’t traverse the data structure with the -> operator anymore.

> select '{"a": {"b": 2}}'::jsonb ->> 'a' -> 'b';
ERROR:  operator does not exist: text -> unkown

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 have 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.