Today I Learned

A Hashrocket project

Javascript arguments on ES2015 Arrow functions

Javascript function arguments can be accessed by functions defined using the function keyword such as:

function logArgsES5 () {
  console.log(arguments)
}
logArgsES5('foo', 'bar')
// => Arguments(2) ["foo", "bar"]

But ES2015 Arrow functions does not bind this variable, so if you try this you will see an error:

let logArgsES2015 = () => {
  console.log(arguments)
}
logArgsES2015('foo', 'bar')
// => Uncaught ReferenceError: arguments is not defined

So if we want to have similar variable we can add an ...arguments as the function argument:

let logArgsES2015 = (...arguments) => {
  console.log(arguments)
}
logArgsES2015('foo', 'bar')
// => Array(2) ["foo", "bar"]

FormData doesn't iterate over disabled inputs

If I have a form that looks like this:

<form>
  <input disabled name="first_name" />
  <input name="last_name" />
</form>

And then I use FormData to iterate over the inputs.

const form = new FormData(formElement);

const fieldNames = [];

form.forEach((value, name) => {
  fieldNames.push(name);
});

// fieldNames contains ['last_name']

Then fieldNames only contains one name!

Be careful if you’re using FormData to extract names from a form!

React Testing Library => within nested queries

Wow, React Testing Library has a within helper to get nested searches on the dom. Check this out with this example:

const DATA = {
  movies: ["The Godfather", "Pulp Fiction"],
  tv: ["Friends", "Game of Thrones"],
};

const MyContainer = () => (
  <>
    {Object.keys(DATA).map(category => (
      <MyCategory name={category} list={DATA[category]} />
    ))}
  </>
);

const MyCategory = ({name, list}) => (
  <ul data-testid={name} role="list">
    {list.map(item => <li role="listitem">{item}</li>)}
  </ul>
);

Then let’s say if we want to assert the list of movies that this MyContainer renders and in the same order as it’s been rendered we can:

...
import { render, within } from "@testing-library/react";
import MyContainer from "../MyContainer";

describe("MyContainer", () => {
  it("tests movies", () => {
    const { getByTestId, getAllByRole } = render(<MyContainer />);

    const moviesCategory = getByTestId("movies");
    const movies = within(moviesCategory).getAllByRole("listitem");

    expect(items.length).toBe(2);
    expect(items[0]).toHaveTextContent("The Godfather");
    expect(items[1]).toHaveTextContent("Pulp Fiction");
  });
});

Real code is way more complex than this example, so this within helper function turns to be very convenient.

Erlang records are just tuples

Erlang has a Record type which helps you write clearer code by having data structures that are self descriptive.

One thing that is interesting about a Record is that a record is just a tuple underneath the hood.

Erlang/OTP 22 [erts-10.4.4] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe]

Eshell V10.4.4  (abort with ^G)
1> rd(fruit, {name, color}).
fruit
2> #fruit{name="Apple", color="Red"}.
#fruit{name = "Apple",color = "Red"}
3> #fruit{name="Apple", color="Red"} == {fruit, "Apple", "Red"}.
true

As you can see, that internal representation is exposed when comparing a record to a tuple:

#fruit{name="Apple", color="Red"} == {fruit, "Apple", "Red"}.

You can even use pattern matching with the two data structures:

7> #fruit{name="Apple", color=NewColor} = {fruit, "Apple", "Green"}.
#fruit{name = "Aplle",color = "Green"}
8> NewColor.
"Green"

Declaring Erlang records in a shell

Erlang records are typically declared in a header file. If you want to experiment with records at the command line, you’ll have to use a shell command.

rd is an erl shell command that you can remember as standing for record definition

Let’s try that in the erlang shell tool, erl.

Erlang/OTP 21 [erts-10.1] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe] [dtrace]

Eshell V10.1  (abort with ^G)
> rd(fruit, {name, color}).
fruit

And then you can declare a record the same way you would in Erlang.

> Apple = fruit#{name="Apple", color="Grren"}.
#fruit{name = "Apple",color = "green"}

And to inspect that variable in erl, just declare the variable and put a . after it to conclude the expression.

> Apple.
#fruit{name = "Apple",color = "green"}

You can find other shell commands that deal with records and other things here.

IO.inspect Label

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

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

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

And here’s the output in our server log:

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

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

telemetry handler detaches automatically on error

Telemetry handlers should be designed to run efficiently over and over again without making a noticeable performance impact on your production system. But what happens if an occurs? Your monitoring should have no bearing on the success of your business logic.

So what happens if your monitoring has an error? With telemetry, it’s ok, the offending handler is just detached, never to run again. Business logic unaffected.

Here’s a test that demonstrates the handler being removed.

handlerFn = fn _, _, _, _ ->
  raise "something"
end

:telemetry.attach(
  :bad_handler,
  [:something_happened],
  handlerFn,
  :no_config
)

# the handler is in ets
assert [[[:something_happened]]] =
         :ets.match(:telemetry_handler_table, {:handler, :bad_handler, :"$1", :_, :_})

:telemetry.execute([:something_happened], %{}, %{})

# the handler is gone!
assert [] = :ets.match(:telemetry_handler_table, {:handler, :bad_handler, :"$1", :_, :_})

You can see the try/catch block in the telemetry source code here.

List all telemetry event handlers

Telemetry is a new library for application metrics and logging in beam applications. It was added to Phoenix in version 1.4.7 released in June 2019.

Telemetry consists of registered handler functions that are executed when specific events occur.

To see a list of what handlers are registered for which events you can call:

:telemetry.list_handlers([])

When returns a list of maps.

To see a list of handlers that have a specific event prefix, you can pass in a prefix as the only argument.

:telemetry.list_handlers([:phoenix, :endpoint])

Which returns:

[
  %{
    config: :ok,
    event_name: [:phoenix, :endpoint, :start],
    function: #Function<2.82557494/4 in Phoenix.Logger.install/0>,
    id: {Phoenix.Logger, [:phoenix, :endpoint, :start]}
  },
  %{
    config: :ok,
    event_name: [:phoenix, :endpoint, :stop],
    function: #Function<3.82557494/4 in Phoenix.Logger.install/0>,
    id: {Phoenix.Logger, [:phoenix, :endpoint, :stop]}
  }
]

`telemetry_event` Overrides Repo Query Event

Ecto gives you a single telemetry event out of the box, [:my_app, :repo, :query], where the [:my_app, :repo] is the telemetry prefix option for ecto.

This event is called whenever any request to the database is made:

  handler = fn _, measurements, _, _ ->
    send(self(), :test_message)
  end

  :telemetry.attach(
    "query",
    [:test_telemetry, :repo, :query],
    handler,
    %{}
  )

  Repo.all(TestTelemetry.Colour)

  assert_receive(:test_message)

This event is overriden when using the the :telemetry_event option, a shared option for all Repo query functions.

  handler = fn _, measurements, _, _ ->
    send(self(), :test_message)
  end

  custom_handler = fn _, measurements, _, _ ->
    send(self(), :custom_message)
  end

  :telemetry.attach(
    "query",
    [:test_telemetry, :repo, :query],
    handler,
    %{}
  )

  :telemetry.attach(
    "custom",
    [:custom],
    custom_handler,
    %{}
  )

  Repo.all(TestTelemetry.Colour, telemetry_event: [:custom])

  assert_receive(:custom_message)
  refute_receive(:test_message)

Which means for any given query you can only broadcast one event. If you have a system that keeps track of expensive queries but you also need to debug a particular query in production, you will take that query out of the system to track expensive queries.

Proposing new time on Google Calendar invitations

Today I learned that we can respond to an invitation using google calendar proposing a new time. Check this out:

First when we open an invitation on gmail I can hit the link more options:

image

This will open the event on google calendar. Then we can expand more options with the caret down and hit Propose a new time.

image

Finally choose a time and send it back to the event owner. And that’s how they will receive our request to change the event time:

image

Telemetry Attach and Execute

The telemetry api is simpler than the name tends to imply. There are only two primary functions, attach/4 and execute/4. Check out the telemetry docs to see the full api.

Attach is simple. Essentially, you want a function to be called when a certain event occurs:

handler = fn [:a_certain_event], _measuremnts, _metadata, _config ->
  IO.puts("An event occurred!!")
end

:telemetry.attach(
  :unique_handler_id,
  [:a_certain_event],
  handler,
  :no_config
)

The first argument is handler_id and can be anything be must be unique. The last argument is config and can also be anything. It will be passed along, untouched, to the handler function as the last argument.

Execute is simple. When the program calls execute, the handler that matches the event is called and the measurements and metadata are passed to the handler.

measurements = %{}
metadata = %{}
:telemetry.execute([:a_certain_event], measurements, metadata)

It’s important to note that the event name must be a list of atoms.

A simple test for attach and execute would look like this:

test "attach and execute" do
  handler = fn _, _, _, _ ->
    send(self(), :test_message)
  end

  :telemetry.attach(
    :handler_id,
    [:something_happened],
    handler,
    :no_config
  )

  :telemetry.execute([:something_happened], %{}, %{})

  assert_receive :test_message
end

Where in with multiple values in postgres

Postgres has a record type that you can use with a comma seperated list of values inside of parenthesis like this:

> SELECT pg_typeof((1, 2));

 pg_typeof
-----------
 record
(1 row)

What is also interesting is that you can compare records:

> select (1, 2) = (1, 2);

 ?column?
----------
 t
(1 row)

And additionally, a select statement results in a record:

> select (1, 2) = (select 1, 2);

 ?column?
----------
 t
(1 row)

What this allows you to do is to create a where statement where the expression can check to see that 2 or more values are contained in the results of a subquery:

> select true where (1, 2) in (
  select x, y
  from
    generate_series(1, 2) x,
    generate_series(1, 2) y
);

 bool
------
 t
(1 row)

This is useful when you declare composite keys for your tables.

Accumulating Attributes In Elixir

Typically, if you declare an attribute twice like this:

@unit_of_measure :fathom
@unit_of_measure :stone

The second declaration will override the first:

IO.inspect(@unit_of_measure)
# :stone

But by registering the attribute by calling register_attribute you get the opportunity to set the attribute to accumulate. When accumulating, each declaration will push the declared value onto the head of a list.

defmodule TriColarian do
  @moduledoc false

  Module.register_attribute(__MODULE__, :colors, accumulate: true)

  @colors :green
  @colors :red
  @colors :yellow

  def colors do
    @colors
  end
end

TriColarian.colors()
# [:yellow, :red, :green]

At compile time, perhaps when executing a macro, you have the opportunity to dynamically build a list.

I learned this when Andrew Summers gave a talk on DSLs at Chicago Elixir this past Wednesday. You can see his slides here

Set Splits Strings

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

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

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

const text = 'India';

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

Enjoy those extra keystrokes!

docs

Keeping an SSH connection alive

Do you get disconnected from your SSH session often? I do… but I’ve found a solution that helps.

An SSH configuration that can be made on the server or client side but in my instance it makes more sense for the update to be on the client side.

In your ~/.ssh/config we’ll utilize the ServerAliveInterval declaration.

ServerAliveInterval
             Sets a timeout interval in seconds after which if no data has
             been received from the server, ssh(1) will send a message through
             the encrypted channel to request a response from the server.  The
             default is 0, indicating that these messages will not be sent to
             the server.  This option applies to protocol version 2 only.

This declaration informs the client to send a keep alive packet at a certain interval to the server, ensuring the connection stays open.

Host example
  Hostname example.com
  ServerAliveInterval 30

That declaration will send a packet every 30 seconds if the connection goes idle. Now this is the desired funcationality that I’d like to see for all of my SSH connections so we can add it to the host wildcard like so:

Host *
  ServerAliveInterval 120

GitHub Insert a Suggestion ☝

Today I learned that GitHub has allows you to insert a one-line suggestion while conducting a pull request review. Click on the button circled in red, and you’ll get a suggestion fenced code block, as shown.

image

Inside the code block is the current code; replace it with your proposed change. GitHub will present your suggestion in a nice diff format.

When the pull requester views your suggestion, they can accept the change with one click. Efficient!

Multiple-lines are not yet supported, according to this GitHub blog post it is a frequently requested feature.

h/t Jed and Raelyn

Pivotal Tracker Advanced Search by Owner

On a big project, Pivotal Tracker contains a wealth of data. Let’s use it!

Today I filtered all the stories assigned to my teammate with the owner keyword:

owner, owned_by
owner: “Obi Wan Kenobi”
Search using the full name, initials, the username, user id or part of the user’s name.

This filtered out hundreds of stories, leaving the four in progress that I care about.

Here’s the official advanced search guide. Try a new keyword today!

https://www.pivotaltracker.com/help/articles/advanced_search/

Change PostgreSQL psql prompt colors

Today I learned how to change psql prompt to add some color and manipulate which info to show:

$ psql postgres
postgres=# \set PROMPT1 '%[%033[1;32m%]@%/ => %[%033[0m%]%'
@postgres => \l
                                           List of databases
            Name            |   Owner    | Encoding |   Collate   |    Ctype    |   Access privileges
----------------------------+------------+----------+-------------+-------------+-----------------------
 postgres                   | postgres   | UTF8     | en_US.UTF-8 | en_US.UTF-8 |
 template0                  | postgres   | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
                            |            |          |             |             | postgres=CTc/postgres
 template1                  | postgres   | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
                            |            |          |             |             | postgres=CTc/postgres
(3 rows)

image

Check this documentation if you want to know more.

Tuples are never inferred in TypeScript

If I have a function that takes a number tuple:

type Options = {
  aspect: [number, number],
  ...
}

const pickImage = (imageOptions: Options) => (
  ...
)

This will give a type error:

const myOptions = {
  aspect: [4, 3],
};

// ❌ Expected [number, number], got number[]
pickImage(myOptions);

I must use type assertion when passing tuples:

const myOptions = {
  aspect: [4, 3] as [number, number],
};

pickImage(myOptions);

Research Software Alternatives

Today I discovered AlternativeTo, which provides ‘crowdsourced software recommendations’. It’s available here:

https://alternativeto.net/

With this resource you can find alternatives to websites, tools, operating systems, and more, and learn about each alternative you find.

For reference, I checked out the results for open source alternatives to Ruby. The list includes no-brainers like Python, JavaScript, and Java, but also Go, C, and Lua. If I were a CTO who didn’t know Ruby and needed to quickly understand its position in the ecosystem, this would be a pretty useful starting point.

image

Tmux Kill All Other Sessions

Ok, you can kill a session in Tmux from the command line with tmux kill-session -t <session-name>. Did you know you can add a flag to kill every session other than your target? Here’s that command.

$ tmux kill-session -a -t <session-name>
$ tmux kill-session -at <session-name> # short version

All sessions but the target will die. This is my ‘clear the desk’ operation when I come back to my computer after some time away and want to shut down a bunch of random servers and processes.

`sleep` is just `receive after`

While using sleep in your production application might not be for the best, it’s useful in situations where you’re simulating process behaviour in a test or when you’re trying to diagnose race conditions.

The Elixir docs say this:

Use this function with extreme care. For almost all situations where you would use sleep/1 in Elixir, there is likely a more correct, faster and precise way of achieving the same with message passing.

There’s nothing special about sleep though. The implementation for both :timer.sleep and Process.sleep is equivalent. In Elixir syntax, it’s:

receive after: (timeout -> :ok)

So, it’s waiting for a message, but doesn’t provide any patterns that would successfully be matched. It relies on the after of receive to initiate the timeout and then it returns :ok.

If you’re building out some production code that requires waiting for a certain amount of time, it might be useful to just use the receive after code so that if later you decide that the waiting can be interrupted you can quickly provide a pattern that would match the interrupt like:

timeout = 1000

receive do
  :interrupt -> 
    :ok_move_on_now
  
  after
    timeout -> :ok_we_waited
end

Assert one process gets message from another

Erlang has a very useful-for-testing function :erlang.trace/3, that can serve as a window into all sorts of behaviour.

In this case I want to test that one process sent a message to another. While it’s always best to test outputs rather than implementation, when everything is asynchronous and paralleized you might need some extra techniques to verify your code works right.

pid_a =
  spawn(fn ->
    receive do
      :red -> IO.puts("got red")
      :blue -> IO.puts("got blue")
    end
  end)

:erlang.trace(pid_a, true, [:receive])

spawn(fn ->
  send(pid_a, :blue)
end)

assert_receive({:trace, captured_pid, :receive, captured_message})

assert captured_pid == pid_a
assert :blue == captured_message

In the above example we setup a trace on receive for the first process:

:erlang.trace(pid_a, true, [:receive])

Now, the process that called trace will receive a message whenever traced process receives a message. That message will look like this:

{
  :trace,
  pid_that_received_the_message,
  :receive, # the action being traced
  message_that_was_received
}

This in combination with assert_receive allows you to test that the test process receives the trace message.

Make dry run

make has an great option to validate the commands you want to run without executing them. For that just use --dry-run.

#!make
PHONY: test
test:
    echo "running something"

Then:

$ make test --dry-run
echo "running something"
$ make test
echo "running something"
running something

Thanks @DillonHafer for that tip!

Git Log Relative Committer Date 📝

Git log format strings are endlessly interesting to me. There are so many different ways to display the data.

Today I learned a new one, %cr. This formats your commit from the committer date, relative to now. After pulling from the remote, use it like this to see how long ago the latest commmit was committed:

$ git log -1 --format=%cr
8 hours ago

I use this command when surveying a Github organization, or an old computer with lots of dusty projects laying around.

How to setup VS Code for Ruby development

After some trial and error with the various extensions available for Ruby, I’ve found the following combination to work well:

Ruby for debugging, syntax highlighting and linting. I use these VS Code User Settings:

"ruby.useLanguageServer": true,
"ruby.lint": {
  "ruby": true
}

Solargraph for intellisense and autocomplete.

endwise for wisely adding end to code structures. (Inspired by tpope’s endwise.vim)

Prettier and plugin-ruby for formatting.

Prettier plugin support is on the way, but for now we have to do this

Bonus for Rails: PostgreSQL for writing queries within the editor.

Apollo-React hooks can easily refetch queries

React-apollo hooks allow you to easily refetch queries after a mutation, which is useful for updating a list when you have create/update/delete mutations.

useMutation takes an argument called refetchQueries that will run queries named in the array.

import React from "react";
import { useMutation } from "@apollo/react-hooks";
import gql from "graphql-tag";
import { Button } from "react-native";
import { Item } from "./types";

const ITEM_DELETE = gql`
  mutation ItemDelete($id: ID!) {
    itemDelete(id: $id) {
      id
    }
  }
`;

interface Props {
  item: Item;
}

const DeleteItemButton = ({item}: Props) => {
  const [deleteItem] = useMutation(ITEM_DELETE, {
    variables: { id: item.id },
    refetchQueries: ["GetItemList"],
  });

  return (
    <Button title="Delete" onPress={() => deleteItem()} />
  )
}

Assert Linked Process Raised Error

Linked processes bubble up errors, but not in a way that you can catch with rescue:

test "catch child process error?" do
  spawn_link(fn -> 
    raise "3RA1N1AC"
  end)
rescue 
  e in RuntimeError ->
    IO.puts e
end

This test fails because the error wasn’t caught. The error bubbles up outside of normal execution so you can’t rely on procedural methods of catching the error.

But, because the error causes on exit on the parent process (the test process) you can trap the exit with Process.flag(:trap_exit, true). This flag changes exit behavior. Instead of exiting, the parent process will now receive an :EXIT message.

test "catch child process error?" do
  Process.flag(:trap_exit, true)

  child_pid = spawn_link(fn -> 
    raise "3RA1N1AC"
  end)

  assert_receive {
    :EXIT,
    ^child_pid,
    {%RuntimeError{message: "3RA1N1AC"}, _stack}
  }
end

The error struct is returned in the message tuple so you can pattern match on it and assert about.

This method is still subject to race conditions. The child process must throw the error before the assert_receive times out.

There is a different example in the Elixir docs for catch_exit.

Assert Test Process Did or Will Receive A Message

The ExUnit.Assertions module contains a function assert_receive which the docs state:

Asserts that a message matching pattern was or is going to be received within the timeout period, specified in milliseconds.

It should possibly in addition say “received by the test process”. Let’s see if we can send a message from a different process and assert that the test process receives it:

test_process = self()

spawn(fn ->
  :timer.sleep(99)
  send(test_process, :the_message)
end)

assert_receive(:the_message, 100)
# It Passes!!!

In the above code, :the_message is sent 1 millisecond before the timeout, and the assertion passes.

Now let’s reverse the assertion to refute_receive, and change the sleep to the same time as the timeout.

test_process = self()

spawn(fn ->
  :timer.sleep(100)
  send(test_process, :the_message)
end)

refute_receive(:the_message, 100)
# It Passes!!!

Yep, it passes.

Firefox Built-in JSON Tools ⛏

Recent versions of Firefox (I’m on 67.0.1) have built-in tools to explore JSON.

Here’s a screenshot of a JSON file from the React Native docs, viewed in Firefox:

image

We get syntax highlighting, the ability to save, copy, expand, or collapse the JSON, right in the browser, with no extra plugins or tools required. Another great Firefox feature!

Override Markdown Listing 📝

Markdown parsers have a neat feature: a list of any numbers tends to be turned into an ordered lists.

I write:

99. First thing (?)
1. Second thing (??)
50. Third thing (??)
1. Fourth thing (????)

And TIL’s markdown parser (Earmark) produces this as HTML:

  1. First thing (?)
  2. Second thing (??)
  3. Third thing (??)
  4. Fourth thing (????)

Pretty cool! Sometimes I want to do my own thing, though. This Stack Overflow question elicits a bunch of techniques; the kind I learned today and used with success is:

99\. First thing (?)
1\. Second thing (??)
50\. Third thing (??)
1\. Fourth thing (????)

Escape the pattern; break the system! This perserved my unordered numbering. Now, I may have other problems, like losing automatic ol and li tags, but the hack works.

Are All Values True in Postgres

If you have values like this:

chriserin=# select * from (values (true), (false), (true)) x(x);
 x
---
 t
 f
 t

You might want to see if all of them are true. You can do that with bool_and:

chriserin=# select bool_and(x.x) from (values (true), (false), (true)) x(x);
bool_and 
---
 f

And when they are all true:

chriserin=# select bool_and(x.x) from (values (true), (true), (true)) x(x);
bool_and 
---
 t

Push git branch to another machine

Whenever I’m working in the same git repo on multiple machines, and I need to work on a branch on both machines I usually push the branch to a shared remote for the sole purpose of pulling it down on the other machine. This third machine can be avoided by push directly between machines:

$ myproject(feature-branch): git remote add machine2 ssh://machine2:/Users/dillon/dev/myproject
$ myproject(feature-branch): git push machine2 feature-branch

Over on machine2:

$ myproject(master): git branch
* master
  feature-branch       <= 😯

Hiding and Revealing Struct Info with `inspect`

There are two ways to hide information when printing structs in Elixir.

Hiding by implementing the inspect protol.

defmodule Thing do
  defstruct color: "blue", tentacles: 7
end

defimpl Inspect, for: Thing do
  def inspect(thing, opts) do
    "A #{thing.color} thing!"
  end
end

So now in iex I can’t tell how many tentacles the thing has:

> monster = %Thing{color: "green", tentacles: 17}
> IO.inspect(monster, label: "MONSTER")
MONSTER: A green thing!
A green thing!

Note that iex uses inspect to output data which can get confusing.

NEW IN ELIXIR 1.8: You can also hide data with @derive

defmodule Thing do
  @derive {Inspect, only: [:color]}
  defstruct color: "blue", tentacles: 7
end

And now you won’t see tentacles on inspection

> monster = %Thing{color: "green", tentacles: 17}
> IO.inspect(monster)
#Thing<color: "green", ...>

In both cases, you can reveal the hidden information with the structs: false option:

> monster = %Thing{color: "green", tentacles: 17}
> IO.inspect(monster)
#Thing<color: "green", ...>
> IO.inspect(monster, structs: false)
%{__struct__: Thing, color: "green", tentacles: 17}

Custom Validation in Ecto

Sometimes the standard validation options aren’t enough.

You can create a custom validator in Ecto using the validate_change function.

In this particular case, I want to validate that thing has an odd number of limbs. I can pass the changeset to validate_odd_number.

def changeset(thing, attrs) do
  thing
  |> cast(attrs, [
    :number_of_limbs
  ])
  |> validate_odd_number(
    :number_of_limbs
  )
end

And then define validate_odd_number like this:

def validate_odd_number(changeset, field) when is_atom(field) do
  validate_change(changeset, field, fn (current_field, value) ->
    if rem(value, 2) == 0 do
      [{f, "This field must be an odd number"}]
    else 
      []
    end
  end)
end

We pass a function to validate_change that takes the field atom and the value for that field. In that function we test for oddness and return a keyword list that contains the field name and an error message.

Remember that when f is :number_of_limbs:

    [{f, "hi"}] == [number_of_limbs: "hi"]
    # true, these data structures are equal

Parallel xargs fails if any of its children do

We like to write about xargs. In addition to all that, turns out xargs is a great tool for easily parallelizing tests, linters or anything where some may pass, and some may fail. If any of the processes that xargs spawns fail, the xargs call will also fail.

All child processes exit zero:


% echo "0\n0\n0" | xargs -Icode -P4 sh -c 'exit code'; echo exit code: $?
exit code: 0

And so does xargs! If any exit non-zero:

echo "0\n1\n127" | xargs -Icode  -P4 sh -c 'exit code'; echo exit code: $?
exit code: 1

xargs follows suit.

Ecto's `distinct` adds an order by clause

When using distinct on you may encounter this error:

select distinct on (color) id, color from fruits order by id;
-- ERROR:  SELECT DISTINCT ON expressions must match initial ORDER BY expressions

This is because distinct on needs to enounter the rows in a specific order so that it can make the determination about which row to take. The expressions must match the initial ORDER BY expressions!

So the above query works when it looks like this:

select distinct on (color) id, color from fruits order by color, id;

OK, now it works.

Ecto’s distinct function helps us avoid this common error by prepending an order by clause ahead of the order by clause you add explicitly.

This elixir statement:

Fruit |> distinct([f], f.color) |> order_by([f], f.id) |> Repo.all

Produces this sql (cleaned up for legibility):

select distinct on (color) id, color from fruits order by color, id;

Ecto added color to the order by!

Without any order by at all, distinct does not prepend the order by.

Read the docs!

Find File Case-Insensitively 🔎

When using the find command, consider the -iname flag. It works like -name:

True if the last component of the pathname being examined matches pattern.

But with case insensitivity:

-iname pattern
  Like -name, but the match is case insensitive.

Here’s a sample command, which will match utils.js and Utils.js.

$ find . -iname Utils.js

See man find for more information. h/t Raelyn.