Today I Learned

A Hashrocket project

573 posts by joshbranchaud @jbrancha

Destructured Access To Nested Value & Parent Value

A destructuring pattern that I often see (especially in React code) is to peel off a nested value in the argument declaration of a function.

const Component = ({ data: { name: displayName }}) => {
  return (
      <SubComponent />

On its own this works quite well, but what happens when you need access to the full set of data as well as the nested name value? I often see this.

const Component = ({ data }) => {
  const { name: displayName } = data;
  return (
      <SubComponent data={data} />

ES6 destructuring is flexible. You can skip the const line and keep everything in the argument declaration.

const Component = ({ data: { name: displayName }, data }) => {
  return (
      <SubComponent data={data} />

You can re-reference the data value after the nested destructuring.

Submit A Form With A Button Outside The Form

You can tie a submit button to a form that the button doesn’t live inside of. The trick is to give the form an id and then reference that id with the button’s form property.

  <form id="my-form">
    <label for="name">Name:</label>
    <input type="text" name="name"></input>

  <!-- ... -->

  <button type="submit" form="my-form">Submit</button>

With this setup, clicking the Submit button will cause the form to be submitted.

See the MDN Button docs for more details.

Matching A Computed Property In Function Args

The computed property name feature of ES6 allows you to reference a variable in object assignments and destructurings. This syntax is flexible enough that it can be used in the arguments portion of a function declaration. In fact, it can even be matched against another argument — allowing the creation of some handy, yet terse functions.

const get = (key, { [key]: foundValue }) => foundValue;

Notice that the first argument, key, will match against the computed property name in the second argument. The foundValue will correspond to whatever key maps to in the given object.

This get function can then be used like so.

const stuff = { a: 1, b: 2, c: 3 };

console.log("Get a:", get("a", stuff)); // Get a: 1
console.log("Get d:", get("d", stuff)); // Get d: undefined

h/t @sharifsbeat

Check The Type Of A Child Component

There is a simple way to check the type of a child component.

import React from 'react';

const Hello = () => <h1>Hello</h1>;

const Greeting = ({ children }) => {
  let hello;
  React.Children.forEach(children, child => {
    if(child.type === Hello) {
      hello = child;

  return hello;

This is a comparison of the child’s type to the component constant we are looking for.

This comparison is not the most robust. For instance, Gatsby does something internally that throws off this comparison. Here is a more robust comparison.

if(child.type === Hello || child.type === <Hello />.type)


Wrap The Root Of A Gatsby App In A Component

Each component that is defined in the pages directory of a Gatsby app will be generated into a separate static page. Each of these pages is meant to stand on its own. Nevertheless, there is still a behind-the-scenes root component above all of these pages. There are cases where’d you like to wrap this root component with some other component, such as a Redux Provider.

This can be done using the wrapRootElement hook from the Browser API in the gatsby-browser.js file.

// gatsby-browser.js
import React from 'react';
import { Provider } from 'react-redux';

import store from './src/store';

export const wrapRootElement = ({ element }) => {
  return (
    <Provider store={store}>{element}</Provider>

Each page and each component in your Gatsby app will now be downstream from a Redux provider meaning that they can connect to the Redux store as needed. You can use this technique for any top-level component that need to be wrapped around the entire app.


Create A Map Of Strings In ReasonML

ReasonML has the Map.Make functor in its standard library which allows you to create a Map module with a specific key type. Here is how we can make a map module with string keys.

module StringMap = Map.Make(String);

We can then use that module to to create an empty map followed by adding key-value pairs to it.

|> StringMap.add("Morty", "Smith")
|> StringMap.add("Rick", "Sanchez")
|> StringMap.add("Scary", "Terry")
|> StringMap.iter((first, last) => {
  print_endline(Printf.sprintf("%s %s", first, last));
Morty Smith
Rick Sanchez
Scary Terry

See the live example.

@reach/router Renders To A Div

Check out the following snippet that uses @reach/router.

import { Router } from '@reach/router';

const Home = () => <h1>Home</h1>;

const App = () => {
  return (
    <div className="main">
        <Home path="/home" />

When you visit ‘/home’, this will render in the DOM as:

<div class="main">
  <div tabindex="-1" role="group" style="outline: none;">

Notice the extra div — that is what <Router> renders to as part of @reach/router’s accessibility features. This may throw off the structure or styling of your app. This can be fixed. Any props that you give to <Router> will be passed down to that div. For instance, you could remove the most outer div and put className="main" on the <Router>.


Accessing Location Within @reach/router

The API of @reach/router departs a bit from react-router in a couple ways. The location prop which you may be used to having access to automatically is instead available through the Location component.

import React from 'react';
import { Location } from '@reach/router';

const MyComponent = () => {
  return (
      {({ location }) => {
        return <p>Current Location: {location.pathname}</p>;

This is a contrived example, but you can imagine how you’d use it to access state or even create an HOC similar to withRouter.

Creating A 2D Array

In most languages if I wanted to create a two-dimensional array, I would utilize some nested looping construct to generate columns of rows. The ReasonML Array module abstracts this away.

let grid = Array.make_matrix(10, 10, 0);

|> Array.iter(column => {
  |> Array.iter(cell => {


The make_matrix function allows you to specify dimensions of a two-dimensional array with all positions initialized to the same value — that third argument.

Modifying A String With blit_string

ReasonML’s Bytes module has a function called blit_string. This function allows you to copy portions of a string into a destination byte sequence. It is a fairly low-level operation, so you have to provide a source string and provide an offset of that source string to start copying from. You then have to provide a properly sized byte sequence as well as the destination’s starting offset and length of bytes to be copied.

Here is an example of how we can use blit_string to create a copy of the string with the first character removed.

let remove_first_char = (str: string): string => {
  let copy_len = String.length(str) - 1;
  let dst = Bytes.create(copy_len);
  Bytes.blit_string(str, 1, dst, 0, copy_len);

Notice that once the byte sequence has been copied over, we then need to convert it back into a string.

Generate A Native ReasonML Project With Pesy

Pesy is a CLI utility available from NPM that you can use to generate a ReasonML project that is ready for native compilation. It uses esy for the management of opam packages. It uses Dune for building your library code with the ReasonML and OCaml dependencies.

Assuming you already have pesy installed globally, create a directory for your project and then run:

$ pesy

A project will be generated that is out-of-the-box ready to compile native executables.

Using Optional Labeled Function Args In ReasonML

If you are constructing a function that takes some arguments, but one of those arguments has a reasonable default value, then you can use an optional labeled argument. Labeled arguments are those arguments prefixed with a ~. If you give the argument a default value, then it becomes optional.

let thing = (~a=1, b: int, c: int) => {
  a + b + c;

In this case ~a is a labeled argument. It is also optional and will default to 1 if not specified. The other two arguments, b and c, are positional arguments and thus required in order for the function to evaluate.

Here are two ways of using this function either by specifying ~a or excluding it so that it defaults to 1.

thing(~a=2, 1, 1)
|> string_of_int
|> print_endline /* 4 */

thing(1, 1)
|> string_of_int
|> print_endline /* 3 */

See more details here.

Using vim-surround With A Visual Selection

The vim-surround plugin allows you to do a variety of actions that have to do with the surrounding characters of text objects.

The S keystroke allows you to surround a visual selection with the following character.

First, make a visual selection. Then hit S. Then hit a surround character such as ( or [ and the area of text that has been visually selected will be wrapped with the respective surround characters.

Duplicate The Current Tab In Chrome

Sometimes when viewing a page in Chrome, you realize you want to keep that page open but also go back to the previous page to view something else. An easy way of achieving this is to duplicate the current tab and then go back.

To duplicate the current tab hit Cmd+Enter while the focus is on the URL bar.

If the URL bar is not in focus, then first hit Cmd+L to focus followed by Cmd+Enter.

Two Ways To Find An Item In A List With ReasonML

The List module has the typical find function that you’d expect any enumerable type to include. It has a very similar find_opt function as well. The difference is in the return types.

When using List.find you’ll have to deal with the possibility of a Not_found exception.

switch (List.find(item => == id, my_list)) {
| exception Not_found => print_endline("Not found!")
| item => print_endline("Found it: " ++

The List.find_opt function has a more familiar interface that doesn’t require you to know the details of what exceptions could arise. All you want to know is if it was found or not. This is achieved by having an option('a) return type.

switch (List.find_opt(item => == id, my_list)) {
| None => print_endline("Not found!")
| Some(item) => print_endline("Found it: " ++

See the List module for more details.

Style A Background With CSS Linear Gradient

The linear-gradient function in its simplest form can be used to style the background of an element with a vertical, linear gradient between two colors.

gradient example See the Pen pQpypW by Josh Branchaud (@jbranchaud) on CodePen.

Here is what the CSS looks like:

.container {
  background: linear-gradient(#00449e, #e66465);

The background of any element with the container class will be styled with a linear gradient that transitions from #00449e to #e66465.

Check The Password Confirmation With Yup

The Yup library makes it easy to validate individual values in a JavaScript object. A common situation when implementing a Sign Up form is asking the user to input their password twice and then the app can make sure they match.

To do this, we need the validation of our passwordConfirmation value to reach outside of itself to make a comparison with the password value. This can be done with Yup’s ref function.

import * as Yup from 'yup';

validationSchema: Yup.object({
  password: Yup.string().required('Password is required'),
  passwordConfirmation: Yup.string()
     .oneOf([Yup.ref('password'), null], 'Passwords must match')

We are able to reference the value of password with ref. We use the oneOf function to ensure that passwordConfirmation either matches password or if it is left blank and matches null then it passes the validation for the time being. The second argument to oneOf is a custom validation message when this validation fails.


Using BCrypt To Create And Check Hashed Passwords

The BCrypt library is used under the hood by gems like Devise in order to work with passwords securely. You can use it to salt and hash a plain text password. You can also use it to check whether an encrypted password matches some input password.

> include BCrypt
=> Object

> encrypted_pass = Password.create('password')
=> "$2a$10$te3Y8wdSXf8/gWDeSP5z9eut7alThnuTvq1SvgQyJ1C57F.qit1uq"

> == "not_my_pass"
=> false

> == "password"
=> true

The Password.create method will salt and hash the given password. The resulting encrypted password, if it is an instance of Password, can be directly compared to a string. For good measure, in case the encrypted password is a string, you can wrap it in a call to to ensure you are working with a Password instance.

Generate Ruby Version and Gemset Files With RVM

RVM, the ruby version manager, is a fairly flexible tool that supports a number of workflows. The rvm utility can be used to generate both a .ruby-version file and a .ruby-gemset file for a given project.

$ rvm --ruby-version use 2.5.3@my_project

This will generate a .ruby-version file in your current project directory that points RVM to the 2.5.3 version of Ruby. It will also create a .ruby-gemset file that RVM will use for managing this project’s gemset.

Get Random Images From Unsplash

Here is an image from

random images

I don’t know what image I am showing you though. That’s because the URL being sourced for the above image is This tells unsplash to randomly serve us a 1200x600 image. Try refreshing the page and you’ll see that it is different each time. Cool!

This is a bit of a novelty, but could be useful on occasion. The Gatsby docs use it to great effect in a tutorial so as to not get caught up with the details of serving a specific image.

Easy Date Comparison With DayJS

Let’s say my application fetches dates from the server which come back in string form as "YYYY-MM-DD" and I’d like to know if those dates already passed. This can be done easily by wrapping dates in DayJS and using its comparison functions.

import dayjs from 'dayjs';

const today = dayjs(new Date());
const pastDate = dayjs("2018-10-22");
const futureDate = dayjs("2022-01-01");

// => true
// => false

The dayjs() function can be used to construct DayJS date objects from Date objects and strings. These can then be compared with functions like isBefore() and isAfter().

Make A Block Of Text Respect A New Line

Generally when we fill a div tag full of text, it will display it one long strand irrespective of any line breaks that are included. This is a great default, but not necessarily what we want when we are displaying text from another source, such as our users.

We can convince a block of text to respect new lines by adding a couple CSS properties.

.multiline-text {
  word-wrap: break-word;
  white-space: pre-line;

The first rule, word-wrap: break-word, ensures that long lines of text uninterrupted by new lines respect the boundaries of our wrapping element. The second rule, white-space: pre-line, handles squashing of extra white space and respecting of new lines.

See a working example here.

Formik's Validation Schema As A Function

The most straightforward way to use Formik’s validationSchema is to provide it with a Yup object defining your form’s validations.

const MyComponent = withFormik({
  // ...

  validationSchema: yup.object().shape({
    email: yup.string().required(),
    feedback: yup.string().required(),
  // ...

There may be a point at which you need access to the props being passed to MyComponent in order to construct the proper set of validations. Formik supports this by allowing validationSchema to be a function.

const MyComponent = withFormik({
  // ...

  validationSchema: (props) => {
    let emailSchema;
    if(props.allowAnonymous) {
      emailSchema = yup.string();
    } else {
      emailSchema = yup.string().required();

    return yup.object().shape({
      email: emailSchema,
      feedback: yup.string().required(),
  // ...

When validationSchema is a function, its first argument is the set of props passed to that component.

Convert A String To A Timestamp In PostgreSQL

If you have a string that represents a point in time, there are a couple ways that you can convert it to a PostgreSQL timestamptz value.

If the string is in ISO 8601 format, then it can be simply cast to timestamptz.

> select '2018-10-24'::timestamptz;
 2018-10-24 00:00:00-05

A more general purpose approach is to use the to_timestamp function.

> select to_timestamp('2018-10-24', 'YYYY-MM-DD');
 2018-10-24 00:00:00-05

The first argument is our string-to-be-converted in whatever format. The second argument is another string describing in what format that string is.

Note: Both of these approaches produce a timestamptz value.

Compile ReasonML With An OCaml Package Using Dune

In Compile Reason To Native With Dune, I showed how to compile a basic ReasonML file as a native executable using Dune.

Any non-trivial program will likely involve pulling in an OCaml dependency. For example, you may want to pull in Lwt. Assuming this package is available, whether you’ve manually downloaded it via opam or used something like esy, you’ll want to let Dune know that Lwt is an available library.

;; dune
 (name hello_reason)
 (libraries lwt lwt.unix))

The modules in the Lwt package will now be globally available to your Reason code.

let () = {
    Lwt_io.printf("Hello, Reason!\n")

When Dune builds your code, it will include and compile Lwt.

See a full example here.

Show What Is In A Git Stash

Usually when I want to inspect anything in git, I’ll use git show with a specific ref. This can even be done with stash refs.

$ git stash list
stash@{0}: WIP on ...
stash@{1}: Some commit on ...

$ git show stash@{0}
# ...

The git-stash command has a built-in way of showing stashes that will save you from having to type out the somewhat awkward stash@{n} ref.

$ git stash show 1

This will show you the stash@{1} ref. You can also omit a number which will show you the latest stash (stash@{0}).

See man git-stash for more details.

Jump Back To The Latest Jump Position In Vim

Any sort of jump motion, such as gg or 121G, will be recorded in your Vim session’s jump list. If you’d like to return to the latest position in your jump list, you can tap '' within normal mode.

You can then tap '' again and you’ll be returned to the position you were just at. This is great if you want to toggle back and forth between your current position and the previous position.

If the latest jump position is not within the current buffer, then you will be jumped to the initial cursor position at the top of the file.

You can learn more about this by reference :help jump-motions, :help jumplist, and :help ''.

h/t Jake Worth

Compile ReasonML To Native With Dune

Dune is “a composable build system for OCaml” with out-of-the-box support for ReasonML. Dune can be used for a lot of things, but in simplest terms it can be used to compile ReasonML programs into native executables.

Considering the following ReasonML program.

/* */
print_endline("Hello, Reason!")

We can then create the following Dune build file.

;; dune
 (name hello_reason))

If we then run dune build hello_reason.exe, then Dune will compile the into a hello_reason.exe executable that can be found in build/default. Run it and see the output.

Read more in the Quickstart guide.

Doing Date Math In MySQL

MySQL has an array of functions for interacting with date and datetime values. If you’d like to do math with a date to compute a date in the future or the past, you can use the DATE_ADD() and DATE_SUB() functions.

mysql> select now() Now, date_add(now(), interval 10 minute) '10 Minutes Later';
| Now                 | 10 Minutes Later    |
| 2018-10-18 15:53:29 | 2018-10-18 16:03:29 |

mysql> select now() Now, date_sub(now(), interval 9 day) '9 Days Earlier';
| Now                 | 9 Days Earlier      |
| 2018-10-18 15:54:01 | 2018-10-09 15:54:01 |

There are equivalent ADDDATE() and SUBDATE() functions if you prefer.

Check out the docs for more details.

Get The Time Zone Of The Client Computer

The resolvedOptions function on Intl.DateTimeFormat.prototype provides a number of pieces of information about the client computer. It includes information such as the locale and the numbering system. It also has the time zone for that machine.

Try running this line of JavaScript in your own browser.

$ Intl.DateTimeFormat().resolvedOptions().timeZone

When I run it, I get America/Chicago.

You can use this within your client-side code as a way of determining in which time zone your users are.

Git: Stash Everything

Running the git stash command will take all the changes to tracked files in the working directory and stash them away. You can tack on the --include-untracked flag to make sure that untracked files are also included in the stash.

You can take this a step further with the --all flag. This will stash everything included files that you’ve told git to ignore.

You probably don’t want to do this. I ran this command and realized after the command hung for about 10 seconds that I had just stashed the node_modules directory.

See man git-stash for more details.

CSS !important Is Not Supported By Inline Styles

You can get pretty far with React’s inline styling of components. There are however a few limitations. One such limitation is that the !important clause is not supported.

If you try applying !important to an inline style like so:

<div style={{ color: "red !important" }}>
  My div

You’ll be disappointed when you open up the browser and inspect that div tag. The color rule will be ignored and excluded from the output html.


Show Git Changes For Files That Match A Pattern

The git show command allows you to view the changes associated with a reference, such as a commit sha (e.g. git show 86748aacf14e).

Consider a commit that has changed a bunch of JS files as well as two CSS files. If we run git show abcd1234, we will see all of the changes to each file which can result in quite a bit of noise. What if we only want to view the changes to the CSS files?

We can instruct the command to only show changes to files that match a pattern by tacking that pattern on to the end.

$ git show abcd1234 *.css

Alternatively, we could scope the output of the command to the files that live in a certain directory.

$ git show abcd1235 src/css

Wrap A ReasonReact Component For Use In JavaScript

Consider the following ReasonReact component for displaying a greeting.

let component = ReasonReact.statelessComponent("Hello");

let make = (~name, _children) => {
  render: _self =>
    <p> {ReasonReact.string("Hello, ")} {ReasonReact.string(name)} </p>,

If we will just be using this component in a ReasonML context, then that is all we need.

If we want this component available for use in a JavaScript file, we have a little more work to do. We need to define the shape of the component’s props using a bucklescript directive and then wrap the component so that it gets appropriate exported for a JavaScript context.

Here is what that looks like.

[@bs.deriving abstract]
type jsProps = {name: string};

let default =
  ReasonReact.wrapReasonForJs(~component, jsProps =>
    make(~name=jsProps->nameGet, [||])

Our only prop is name which is a string. The wrapReasonForJs function and accompanying binding to default mean that we can import the compiled JS-equivalent like so:

import Hello from 'src/components/';

See the docs for more details on Reason/JS interop.

Format The Current ReasonML File Within Vim

I’m editing a .re file within Vim. I haven’t yet wired up refmt to something like ALE for automatic formatting on save. By the time I’m done with my changes, indentation is a mess.

I can still take advantage of refmt to clean up my file.

:!refmt --in-place %

Running that command in Vim will cause the current file to be formatted.

How does it work?

It shells-out to refmt which does all the heavy lifting. The --in-place flag means that the target file will be re-written by the formatted result. The % is a handy Vim shorthand for the path and name of the current file.

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.

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.


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.

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.

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.


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.

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? */

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")


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.

For When That Escape Key Is Hard To Reach

Using Vim to its full potential requires using just about every key on the keyboard. Of all those keys, the escape key is particularly important. It’s how you get back to normal node.

If you find the escape key hard to reach or your laptop vendor decided you don’t need it anymore, what’s the alternative?

There is a built-in alternative:


Note: If your <Esc> key is hard to hit on your keyboard, train yourself to use CTRL-[.

See :help Ctrl-[ for more details.


Stream A File Line By Line In ReasonML

We can use the Stream module in ReasonML to read a file getting each line on demand. Doing this requires two key insights. First, we can open a file as an input channel. Second, we can turn an input channel into a stream using Stream.from.

let file_in_channel = Pervasives.open_in('file.txt');

let file_stream =
  Stream.from(_i => {
    switch(Pervasives.input_line(file_in_channel)) {
    | line => Some(line)
    | exception(End_of_file) => None

file_stream |> Stream.iter(line => do_something(line));

The Pervasives module (which is open by default and is only prefixed above so as to be explicit) allows us to open the named file as an input channel with open_in. It also allows us to read lines off that file with input_line. We use Stream.from to create a custom stream that consumes the input channel line by line using input_line. We either get some line or we hit the end of the file. Lastly, we can do whatever we want with the stream, such as iterate over it.

See the docs for Pervasives and Stream for more details.

Add The VSCode CLI To Your Path

Visual Studio Code has a command line tool that can do a bunch of things. Perhaps the most common is opening up the current directory from the command line.

First, you need to add code to your path. This can be done from within Code itself.

Hit Cmd+Shift+p to pop open the command palette. Then start typing Shell Command ... until the Shell Command: Install "code" command in shell PATH option appears. Select this and Code will add code to your path.

Try code . to open the current directory or run code --help for more details on what’s available.

Making Things Mutable In ReasonML

In ReasonML, things that we create with let are immutable — which means that we can’t change them.

let num = 5;

Once num is bound to 5 it is stuck with that value for the duration of it’s scope.

ReasonML doesn’t completely restrict us to immutability though. The ref construct allows us to bind a variable to a sort of box that holds a value. We can then look in the box and change what is in the box.

let num = ref(5); /* put 5 in the box */

Js.log(num^); /* use `^` to look in the box */

num := 3; /* remove 5, put 3 in the box */

We use ref to bind our variable to a box with some initial value. The := assignment operator allows us to change what’s in the box. Anytime we want to refer to what’s in the box, we postfix our variable with ^.

Also of note: while list instances are not mutable, array instances are.