Today I Learned

A Hashrocket project

Animate Smoothly Between Two Background Colors

CSS animations allow you to set up simple rules that the rendering engine can then apply to create smooth transitions between style states.

To smoothly transition between two background colors, we can create a keyframes at-rule with a fitting name (e.g. pulse).

@keyframes pulse {
  0% {
    background-color: red;
  }
  50% {
    background-color: blue;
  }
  100% {
    background-color: red;
  }
}

Over the course of a single animation, this set of rules will start the background color at red, transition to blue 50% of the way through, and then back to red again.

We can then apply this animation within any of our CSS class definitions.

.square1 {
  animation: pulse 2s infinite;
  width: 100px;
  height: 100px;
}

Anything with a class of square1 will have a width and height of 100px as well as a pulsing background color.

Notify your application when browser goes offline

At JS Camp this past weekend I saw Josh Beckman give a talk about the appropriate time to trigger a page refresh when the single page application has received some updates.

A key component of that is knowing whether you have an internet connection or not.

Fortunately there is a browser event, offline, that will help you keep track of your offline status.

window.addEventListener('offline', () => console.log('is offline'))

When I turn the wifi off, then is offline is logged to the console.

You can also take advantage of the navigator.onLine (yes a capital L) property to determine whether your application currently has an internet connection.

Reference rejected values on conflict in postgres

I have a table of fruits and I have their quantity:

create table fruits (name text primary key, quantity int);

In that table I have a row for apples:

insert into fruits (name, quantity) values ('apple', 10);

So generally, when I try to insert another apples row, because name is the primary key, I’ll get a duplicate key error:

insert into fruits (name, quantity) values ('apple', 11);
duplicate key value violates unique constraint "fruits_pkey"

So if I don’t know wether to insert or update I can use the on conflict functionality in postgres to set the quantity even if apples is already there.

insert into fruits (name, quantity) values ('apple', 13) on conflict (name) do update set quantity = excluded.quantity;

I can use the excluded special table to reference the row that was rejected by postgres and which contains the quantity that I want to update the row quantity to.

Parameter filtering in Elixir Phoenix logs

Sometimes you want to filter out parameters that are being logged (think GDPR compliance). Enter Phoenix’s handy config filter_parameters :

config :phoenix, :filter_parameters, ["password", "birthday"]

Or if you want to be extra safe, you can filter all parameters and only whitelist ones you want to see. For example: id and order:

config :phoenix, :filter_parameters, {:keep, ["id", "order"]}

Find The Process Using A Specific Port On Mac

The netstat utility is often recommended for finding the PID (process ID) bound to a specific port. Unfortunately, Mac’s version of netstat does not support the -p (process) flag. Instead, you’ll want to use the lsof utility.

$ sudo lsof -i tcp:4567

Running this will produce a nicely formatted response that tells you several pieces of information about the process bound to :4567 including the PID.

source

Animate ReactNative in ClojureScript with Reagent

Reagent uses ratoms to refresh components. When the state of a ratom is changed, components that deref that state re-render. ReactNative Animation uses a similar technique: changes to an Animated.Value cause a re-render. I was afraid these concepts would collide, and I’d have to bypass Reagent using it’s low-level api to use animations. But much to my joyful surprise, Animated.Value changes trigger a re-render in normal Reagent components.

(ns my-app.animation
  (:require
    ["react-native" :as ReactNative]
    [reagent.core :as r]))

(def animated (.-Animated ReactNative))
(def text (r/adapt-react-class (.-Text ReactNative)))
(def animated-value (.-Value animated))
(def animated-view (r/adapt-react-class (.-View animated)))

(defn testview []
  (let [bounce-value (new animated-value 0)]
    (.setValue bounce-value 1.5)
    (-> bounce-value
        (animated.spring #js {:toValue 0.8 :friction 1})
        (.start))
    (fn [] [animated-view
            {:style {:flex 1
                     :transform [{:scale bounce-value}]
                     :background-color "red"
                     :border-radius 10
                     :shadow-color "#000000"
                     :shadow-opacity 0.7
                     :shadow-radius 2
                     :shadow-offset {:height 1 :width 0}}}
            [text "test"]])))

animation

This may look complex, but compare it to the low level Reagent api used in other examples.

Enable gzip for all phoenix responses

Enabling gzip for static assets in phoenix couldn’t be simpler. In lib/myapp_web/endpoint.ex change gzip from false to true:

 plug(Plug.Static, at: "/", from: :tilex, gzip: true, only: ~w(assets ...))

But why stop there? We can compress our dynamic document bodies just as easily. In config/prod.exs, add compress: true to the http config of the endpoint.

config :my_app, MyAppWeb.Endpoint,
  http: [port: {:system, "PORT"}, compress: true]

Using vimscript lambdas with map

Vimscript has lambda functions, check them out with :help lambda.

You don’t have to reference an argument with the a: prefix and returns are implicit.

Generally they take the form of:

:let Add = {a, b -> a + b}
:echo Add(1, 2)
 3

You can also pass a lambda to the map func:

:let fruits = ['apple', 'orange', 'banana']
:echo map(fruits, {key, val -> "key: " . key . " val: " . val})
['key: 0 val: apple', 'key: 1 val: orange', 'key: 2 val: banana']

Alwyas be careful with vim’s map() though. It Mutates

To make sure you don’t mutate the list you are mapping over, use copy().

:echo map(copy(fruits), {key, val -> "key: " . key . " val: " . val})

What is that chäräcter ?

If you are in vim and you encounter a weird looking unicode character, and you want to know what the codepoint(s) for that character is/are you can use ga

If my cursor is over ä and I use ga I get output:

<ä> 228, Hex 00e4, Octal 344

If my cursor is over and I use ga I get output:

<a>  97,  Hex 61,  Octal 141 < ̈> 776, Hex 0308, Octal 1410

The first character is a precombined Unicode character, the a with the umlaut already has its own unicode character.

The second character is an a combined with a diacrital mark, and the output of ga reflects that by listing each utf codepoint that composes the character.

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.

🔲

Find a Capybara node with regex

My pair and I faced a situation yesterday where we had to find a node with two separated pieces of text.

<section>
    <div>Something</div>
    <div>Some Other Text</div>
    <div>Apple</div>
</section>
<section>
  <div>Different</div>
  <div>Some Other Text</div>
  <div>Apple</div>
</section>
<section>
  <div>Something</div>
  <div>Some Other Text</div>
  <div>Orange</div>
</section>

We wanted to find a node with text “Something” and text “Orange” in our Capybara test.

The find method has a text option that you can pass a regex to.

find("section", text: /Something.*Orange/)

And initially this wasn’t working because of a line break and so we had to use the multiline flag (m).

find("section", text: /Something.*Orange/m)

The five values that define cursor position in vim

We generally think of a cursor having two coordinates, x and y, row and column, but when I call getcurpos() I get a list with 5 values in it.

:help getcurpos()
:echo getcurpos()
[0, 4124, 8, 0, 57]

Here are the definitions of those numbers:

bufnum - the number of the buffer when calling getpos("'A") to get the position with a mark. Always 0 with getcurpos()

lnum - The line number

col - The number of chars used to go this far to the right. is 2. 10 spaces is 10.

off - Is the number of chars past the end of the line. 0 unless using virtualedit.

curswant - Is the column you started on when starting to navigate with j and k. You might start on col 20, and go down to a line with only 10 columns in which case the cursor would be on col 10, but curswant would still 20. The next navigation to a line with more than 20 characters would put you back on col 20.

With virtualedit turned on curswant will always be the column position of the cursor.

Rendering Emojis With Unicodes in Javascript

Ordinarily you can render an emoji in Javascript by using its four-character Unicode code point as follows:

(React JS [JSX] Sample)

<span>{'\u263B'}</span> => <span>☻</span>

Sometimes, however, the Unicode code point for an emoji is more than four characters long and the above method for rendering doesn’t work. In ECMA6, the following syntax will work for emojis whose Unicode code point length is more than four (1):

<span>{'\u{1F4A9}'}</span> => <span>💩</span>

Note:

  1. This has only been tested with a five-character Unicode code point.

Sort numerically

The sort command :sort in vim sorts by the string representation by default. For numbers this is weird. If you have 2, 12, and 1 on separate lines they end up sorted like this:

1
12
2

To sort them numerically you can pass the n argument to the sort command, like this :sort n which gives you what you want:

1
2
12

Speed up webpacker by excluding dev dependencies

In our latest project, we were experiencing some long build times after accreting features for a few monhts.

By default webpacker pulls in all of your node_modules for parsing and optimization by babel, which can be quite unneccessary. In order to exclude your devDependencies from that process, you can add the folling code to your development.js config:

...

var package = require('../../package.json');
var excluded = Object.keys(package.devDependencies).map(function(dep){
  return new RegExp("node_modules/" + dep);
});

module.exports = merge(environment.toWebpackConfig(), customConfig, {
  module: {
    noParse: excluded
  }
});

The noParse option can possibly lead to errors when some packages are excluded from parsing (notably, css-loader), you can tweak which dependencies reside in dependencies vs devDependencies in your package.json in order to avoid these issues.

Making virtualedit a local option

virtualedit is a global option. This means that when you call setlocal virtualedit it’s not set just for this buffer but for all windows and all buffers. This is confusing, but only options labeled local to buffer in help can be set to the local buffer. virtualedit is labeled as global.

However there is a hack. You can simulate this as a buffer local option by setting it on BufEnter and unsetting it on BufLeave.

In my .vimrc.local I have

autocmd BufNewFile,BufRead,BufEnter *.part setlocal virtualedit+=all
autocmd BufLeave *.part setlocal virtualedit-=all

Set it when you enter, unset it when you leave, and now the setting is confined to the buffer you’d like to use it in.

Client Connection Vars with Ecto

Postgres has dozens of connection variables it will take, a couple of my favorite ones are statement_timeout and application_name.

Ecto takes a parameters connection option, which is a keyword list of connection parameters.

# dev.exs

...

# Configure your database
config :myapp, Myapp.Repo,
  adapter: Ecto.Adapters.Postgres,
  database: "myapp_dev",
  socket_dir: "/var/run/postgresql",
  parameters: [application_name: "My App Development", statement_timeout: "5000"],
  pool_size: 10



Example of statement_timeout being respected in Ecto:

Ecto.Adapters.SQL.query!(Myapp.Repo, "select pg_sleep(86400)")

** (Postgrex.Error) ERROR 57014 (query_canceled): canceling statement due to statement timeout
    (ecto) lib/ecto/adapters/sql.ex:200: Ecto.Adapters.SQL.query!/5


Client Connection Variables references: https://www.postgresql.org/docs/current/static/runtime-config-client.html

Use a unix socket with Ecto

Ecto allows the use of a unix socket to connect to postgres, instead of TCP. In order to use a unix socket in a exs file, you should remove the hostname list item, and provide the socket_dir list item.

# dev.exs

...

# Configure your database
config :myapp, Myapp.Repo,
  adapter: Ecto.Adapters.Postgres,
  database: "myapp_dev",
  socket_dir: "/var/run/postgresql",
  pool_size: 10

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.

Two ways to write lists in OCaml

The :: operator in OCaml is used to create head tail lists.

[1; 2; 3;]

Can also be written as:

1 :: (2 :: (3 :: []))

And in fact, the AST of the first example is a nested data structure joined with the :: operator.

You can read more about lists here

The first way is convenient, but the second way is important because lists are pattern matched with the :: operator.

let pat_match_func numbers =
  match numbers with
  | first_number :: rest_of_numbers ->
    # do something with first number

Pass arguments through to wrapped function

If you want to have a function that wraps another function it’s convenient to not worry about the details of the arguments being passed.

I have this:

sendMessage = (name, num) => () {
  console.log(name, num);
}

And I want to wrap it with this:

wrapper = (func, name, num) => () {
  func(name, num);
}

Not all functions I want to wrap have the arguments name and num. To genericize this I can use ...args in the signature to turn all the remaining args into an array and then use ...args again to spread the array into the argument positions of the function call.

wrapper = (func, ...args) => () {
  func(...args);
}

To have the same operator (...) do opposite things based on the context is a little bit weird to me, but that’s ES6!

Splitting a string with `Js.String.splitByRe`

In ReasonML you are not always in a JS context, but when you are, you can use Js.String.splitByRe for splitting.

let regex = [%re "/\|/"];

let results = Js.String.splitByRe(regex, "Apple|Bird|Turtle");

Js.log(results);

You can play around with it here.

As a sidenote, if you read the docs on the Str module it looks like there are Reason ways to do this, but I can’t get anything in that module to work.

In a ReasonML “Try” window here I try calling:

Str.regexp("", "");

But just get the error

The module or file Str can't be found.
Are you trying to use the standard library's Str?
If you're compiling to JavaScript, use Js.Re instead.
Otherwise, add str.cma to your ocamlc/ocamlopt command.

Pretty confusing :/.

Variadic args in ReasonML with JS Interop

I have this Javascript function in my utils file.

const add = (...args) => { return args.reduce((x, a) => a + x, 0) }

export add;

I’d like to use it in my ReasonML program, but it has variadic arguments, and ReasonML is a typed language. As long as all the variadic arguments are of the same type, however, I can import it into ReasonML with the [@bs.splice] attribute.

[@bs.module "utils"] [@bs.splice] external add : (array(int)) => int = "add";

[@bs.splice] will transform the last argument from an array into a list of arguments.

In ReasonML

let a = add([|1, 2, 3|]);

In Javascript

var a = add(1, 2, 3);

Enable Breadcrumbs For VS Code 1.26 Release

The latest release of Code (Version 1.26) brings about a lot of exciting new features — including file breadcrumbs at the top of each file editor view.

Breadcrumbs feature in action

By default this feature is not enabled. You can enable it from User Settings (Cmd+Shift+P, ‘User Settings’). From the User Settings view, you can search for breadcrumbs and you’ll see the following item:

  "breadcrumbs.enabled": false,

Use the pencil to override it to true and you’ll have that trail of breadcrumbs waiting for you.

Rename a file in git with different casing

On MacOS git doesn’t handle file name casing changes very well.

If I have a committed file Something.txt I can mv it and git doesn’t recognize the change:

> mv Something.txt something.txt
> git status
On branch master
nothing to commit, working tree clean

Git will recognize the change if you perform the move with git mv.

> git mv Something.txt something.txt
> git status

renamed: Something.txt -> something.txt

There is a configuration regarding this:

git config core.ignorecase false

This is set to false by default. Setting this to true may provide the behaviour you want.

On Linux, this is not an issue. The filesystem recognizes files with different casing as different files and git likewise.

Grep For Files With Multiple Matches

The grep utility is a great way to find files that contain a certain pattern:

$ grep -r ".class-name" src/css/

This will recursively look through all the files in your css directory to find matches of .class-name.

Often times these kinds of searches can turn up too many results and you’ll want to pare it back by providing some additional context.

For instance, we may only want results where @media only screen also appears, but on a different line. To do this, we need to chain a series of greps together.

$ grep -rl "@media only screen" src/css |
    xargs grep -l ".class-name"

This will produce a list of filenames (hence the -l flag) that contain both a line with @media only screen and a line with .class-name.

If you need to, chain more grep commands on to narrow things down even farther.

See man grep for more details.

Zsh file name without the extension

Zsh provides a weird way to get the different parts a of a file name.

If you want the full path without the extension:

> myfile=/path/to/story.txt
> echo ${myfile:r}
/path/to/story
> myfile=story.txt
> echo ${myfile:r}
story

If you want just the file name minus the path:

> myfile=/path/to/story.txt
> echo ${myfile:t}
story.txt

Check this out you can combine those two symbols!

> myfile=/path/to/story.txt
> echo ${myfile:t:r}
story

Syntactically correct OCaml AST at the cmd line

I wrote a til about a week ago where I used refmt to convert reasonml to AST but the output is this:

[
  structure_item ([1,0+0]..[1,0+19])
    Pstr_module
    "Something" ([1,0+7]..[1,0+16])
      module_expr ([1,0+17]..[1,0+19])
        Pmod_structure
        []
]

While this is a good clue, it’s not something I can copy and paste into my OCaml ppx file. It is not OCaml.

What’s better is using the dumpast tool that comes with ppx_tools (installable with opam install ppx_tools).

Given a reason file:

module Something {}

When I run:

> cat target.re | refmt --parse re --print ml > target.ml 
> ocamlfind ppx_tools/dumpast ./target.ml

It returns:

[{pstr_desc =
   Pstr_module
    {pmb_name = {txt = "Something"};
     pmb_expr = {pmod_desc = Pmod_structure []}}}]

Each of the records it returns is missing a location field and an attributes field, but you should use Ast_helper to produce Parseetree records with the location and attributes fields defaulted for you.

Match ocaml versions with Reasonml with `opam`

This week I was trying to write a ppx in ocaml use it in my reasonml project but I was getting an error about mismatching Ocaml versions.

Ast_mapper: OCaml version mismatch or malformed input

When I checked my versions sure enough there was a mismatch:

> bsc
BuckleScript 4.0.0 (Using OCaml4.02.3+BS )
> ocaml -version
The OCaml toplevel, version 4.07

Reasonml and Bucklescript use an older version of ocaml, version 4.02.3. I had compiled my ppx binary however with 4.07.

Fortunately it is rather easy to switch ocaml versions using opam, the Ocaml package manager. If you have opam installed (on mac brew install opam) then you can use the switch command.

opam switch 4.02.3

Running opam switch without an argument will show you all the available versions.

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

Print The Relative Path Of The Current File

As a project grows and there are many directories and long path names, Vim will not always have enough room to display the full relative path of the current file. It may have to cut off the initial directories which can make it hard to know where you are.

You can hit Ctrl-g to quickly display the relative path of the current file below the status bar.

example of using ctrl-g

See :help Ctrl-g for more details.

Aborting Git Commits And Rebases Within Vim

When you are amending a commit or doing an interactive rebase of a series of commits, Vim will be open to a buffer full of content related to the respective action. Normally, you’ll make some changes, save the buffer, and then quit — Git will take over from there by processing the commit or rebase.

What if you find yourself in this situation and you want to cancel the commit or rebase? Simply quitting with text already in the buffer will be interpreted by Git as a signal to go ahead and process the commit/rebase.

So, how do we quit without confirming the action?

Vim allows you to quit with an error code.

:cq

This means that irrespective of the content of the buffer, Vim will signal to Git with an error code to not process the commit or rebase, effectively aborting the action.

See :help cq for more details.

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.

How to check Rails migration statuses

You can check the status of your migrations in Rails by running rails db:migrate:status

This command returns your database name, as well as a list of all your migrations, with their name and status

database: my-database-dev

Status | Migration ID | Migration Name
--------------------------------------
  up   | 201803131234 | Create users
  up   | 201803201234 | Create blogs
 down  | 201804031234 | Create posts

Convert Reasonml to Ast at the command line

I’m curious what module Something {} looks like after being translated to the Ocaml AST.

I can use the Reasonml tool refmt to generate the ast for me at the command line with the --print ast command line flag.

echo 'module Something {}' | refmt --parse re --print ast

Which outputs:

[
  structure_item ([1,0+0]..[1,0+19])
    Pstr_module
    "Something" ([1,0+7]..[1,0+16])
      module_expr ([1,0+17]..[1,0+19])
        Pmod_structure
        []
]

Copy files with progress in terminal w/rsync

When you need to transfer a lot of files from one location to another it’s sometimes useful to have some progress indication and maybe even a speed measure, or time remaining.

I recently had to transfer a few gigabytes of data from one computer to another. For this task I chose to use Rsync, since it is a command line utility that can preserve file metadata (permissions) and easily resume in case of an error.

Rsync ships with macOS by default, but if you want to get a more recent version, you can install it from homebrew.

There are two options for showing progress:

If you are transferring a few really big files you can use the --progress flag.

rsync -ah --progress source destination

This will list each file as it being transferred and show you the progress and speed in which the file is being transferred.

In my case I had a lot of small files so I chose to use --info=progress2.

rsync -ah --info=progress2 source destination

This will output something like this

2.26G  16%    6.13MB/s    0:05:51 (xfr#375313, to-chk=0/1165396)

Which represents the progress, speed and estimated time remaining for the entire transfer.

Assigning, Mutating, and Freezing a JS object

I’ve been using Object.assign to merge two objects in javascript. That typically looks like this:

> let o = Object.assign({a: 1, b: 2}, {a: 3})
{a: 3, b: 2}

The key/values in the second argument override the key/values in the first object to produce a new object with those the combined keys and values.

Does it actually produce a new object? or does it just mutate the first argument:

> foo = {a: 1, b: 2}
> bar = Object.assign(foo, {a: 3})
> foo == bar
true
> foo
{a: 3, b: 2}

Ahh… it mutates. If you prefer something not to mutate you can freeze it:

> foo = {a: 1}
> bar = Object.freeze(foo)
> Object.assign(bar, {a: 2})
TypeError: Cannot assign to read only property 'a' of object '#<Object>'

Ok, so now Object.assign can’t mutate the first argument, because that argument is frozen. But be careful, freeze mutates too.

> Object.assign(foo, {a: 2})
TypeError: Cannot assign to read only property 'a' of object '#<Object>'

Is This A Directory Or A File -- ReasonML

When compiling ReasonML natively, we have access to a variety of additional modules including the Unix module. We can interact with directories and files using functions on Unix.

let current_dir = Unix.opendir(Unix.getcwd());
let first_file = Unix.readdir(current_dir);
/* is first_file a directory or a file? */
Unix.closedir(current_dir);

Here we open the current working directory, grab the first thing out of that directory — maybe it’s a file, maybe it’s a directory, maybe it is something else. Lastly, we close the directory.

let current_dir = Unix.opendir(Unix.getcwd());
let first_file = Unix.readdir(current_dir);

switch(Unix.stat(first_file)) {
| Unix.stats({ st_kind: Unix.S_REG }) => print_endline("Regular File")
| Unix.stats({ st_kind: Unix.S_DIR }) => print_endline("Directory")
| Unix.stats({ st_kind: Unix.S_LINK }) => print_endline("Link")
| Unix.stats({ st_kind: Unix.S_SOCK }) => print_endline("Socket")
| _ => print_endline("Something else")
};

Unix.closedir(current_dir);

There are a variety of kinds of files to switch on. Here, we are switching on Regular Files, Directories, Links, and Sockets. Everything else falls through.

See the Unix module docs for more details.

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 |
+------------------------+

Suppress warnings from bucklescript compiler

The bsconfig.json file has a configuration called bsc-flags that are sent to the bucklescript compiler (bsc). That looks like this by default:

"bsc-flags": ["-bs-super-errors"],

This are a host of flags you could send to the bsc compiler, and you can see them all with:

> bsc -warn-help
...
  6 Label omitted in function application.
  7 Method overridden.
  8 Partial match: missing cases in pattern-matching.
  9 Missing fields in a record pattern.
 10 Expression on the left-hand side of a sequence that doesn't have type
    "unit" (and that is not a function, see warning number 5).
...

Note the numbers that correspond with each warning. The bsc command takes a -w flag and you can explicitly tell the compiler to ignore a warning by using a minus sign in front of the warning number, like this:

"bsc-flags": ["-w -8", "-bs-super-errors"],

To ignore all warnings, use -w -A.

To turn all warnings into errors use -w @A.

Per the bsc -help the default setting is:

+a-4-6-7-9-27-29-32..39-41..42-44-45-48-50-102

Use a Lodash function in ReasonML w/Interop

This is my attempt to get into javascript interop in ReasonML. Really, you probably have enough tools in ReasonML to avoid using any Lodash functions but I’m using it to learn.

[@bs.module "lodash"] external myMin : array('a) => 'a = "min";

let result = myMin([|1, 2, 3|]);
/* result is 1 */

The bs.module syntax is not very well documented and a little obtuse.

[@bs.module "lodash"] will turn into the require statement in JS.

external myMin is where you name the function you’ll be using in Reason.

array('a) => 'a declares the type signature and return value.

= "min" is where we declare what the function is on the javascript side.

There are some parentheses missing that might help you read and parse this differently. Here is what the same statement looks like with added parentheses.

[@bs.module("lodash")] external myMin : (array('a) => 'a) = "min";

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