Today I Learned

A Hashrocket project

356 posts by chriserin @mcnormalmode

Open devtools when running a Selenium Chrome test

The Network tab in Chrome devtools doesn’t record requests unless devtools is open. This makes debugging specific issues in tests much harder. It’s great being able to see which api requests were made and what payloads they returned.

You can start Chrome with devtools open though with the the chrome option --auto-open-devtools-for-tabs.

If you are using Selenium with Chrome in a Ruby integration test, you can pass the option

opts = {
  browser: :chrome,
  options: Selenium::WebDriver::Chrome::Options.new(
  args: %w(--auto-open-devtools-for-tabs --window-size=2400,2400)
)
}

Capybara.register_driver :chrome do |app|
  Capybara::Selenium::Driver.new(app, opts)
end

Opening devtools automatically may restrict your window size enough to disrupt some of your tests in which case you can set -window-size to a value that accomodates your website.

Don't rerender if nothing changed in React 16.6.0!

React 16.6.0 came out today and React now provides a handy function to create a component that won’t rerender if it doesn’t get new props, React.memo.


const BlueComponent = () => {
  return <div>no props don't rerender</div>;
}

const MemoComponent = React.memo(BlueComponent);

BlueComponent is a component that will re-render every time it’s parent re-renders. It doesn’t take props though, so it won’t look any different based on new props. MemoComponent is a component created by passing BlueComponent to React.memo. It will not re-render when it’s parent re-renders.

Check out another example in the code sandbox below.

Edit znw4wjn914

Read more about React 16.6.0 here.

Catching errors in React (16 and up)

If an error is thrown while rendering React, React unmounts the entire tree.

In production, this might not be behaviour you want. The behaviour might be inconsequential to the user’s current path and why stop the user cold due to an unanticipated state?

React provides a function componentDidCatch to help manage exceptions and keep the consequence of the error localized to a specific part of your component tree.

This blog post describes the concept of an ErrorBoundary which can look like this:

class ErrorBoundary extends Component {
  componentDidCatch(error, {componentStack}) {
    console.log("error", error)
    console.log("componentStack", componentStack)
  }

  render() {
    return this.props.children;
  }  
}

Using the componentDidCatch lifecycle function this component will catch any error thrown by its children. If an error is thrown it will not render and none of it’s children will render, but all components in different sections of the component tree will render.

The second argumunent to componentDidCatch is an object containing a key called componentStack which is a nice stack provided by React.

H/T Josh Branchaud

Outer join with ActiveRecord `references` method

I want to join posts to comments regardless if comments exist or not.

You can use includes for that:

Post.includes(:comments).all

But that results in 2 queries, one to get all the posts, and one to get all comments that have the relevant post_id.

With references you can turn this into an outer join:

Post.includes(:comments).references(:comments).all

Now we’re getting all the information we need with just 1 query.

Check out the Active Record guides here

Return value of snapshot in componentDidUpdate

React has a rarely used lifecycle method getSnapshotBeforeUpdate where you get the opportunity to look at your current DOM right before it changes.

The return value of this method is the third parameter of componentDidUpdate.

getSnapshotBeforeUpdate(prevProps, prevState) {
    return "value from snapshot";
}

componentDidUpdate(prevProps, prevState, snapshotValue) {
  console.log(snapshotValue);
}

The above code will output value from snapshot in the log.

The purpose for getSnapshotBeforeUpdate given in the React documentation is for making sure a value that can’t be set with rendering - like the scroll position - is exactly where you want it based on the state it was before the rerender.

My code example is here.

Group dates by week in Postgres

Timestamps are everywhere in our postgres tables. To group them together you can use date_trunc to normalize the timestamp by minute, hour, day, etc.

You can also normalize the date by week.

> select date_trunc('week', now());
2018-10-08 00:00:00+00

The above example returns the first day of the week for the current moment which is a Monday. Postgres truncates dates to Monday rather than Sunday.

To group dates by week just use the truncated value in both the select clause and the group clause.

select count(*), 
  date_trunc('week', request_time) 
from requests 
group by 
  date_trunc('week', request_time) 
order by date_trunc desc ;

Ignore just one statement with Prettier

Prettier works great for formatting your javascript. In general, it makes formatting something that you don’t have to think about anymore, but occasionally you’ll run across something that you want to format in your own custom way.

You can include a prettier-ignore comment to achieve this goal.

// prettier-ignore
const minesweeperMap = [
    'B', ' ', ' ',
  ' ', 'B', ' ',
  'B', ' ', ' ',
  ' ', ' ', 'B',
];

const bombs =     4;

When you run prettier on the above code, the declaration of bombs line will be changed to remove unneeded spaces, but the minesweeperMap declaration will be left unchanged.

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.

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.

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.

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

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.

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

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.

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.

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
        []
]

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

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

Be specific in styled components with `&`

input[type="number"] has styles applied at a global level. I want to override some of those styles

a more specific selector takes precedence over a less specific one

So if I just define some css that is:

.myCoolInput {
  background-color: green;
}

It won’t override the more specific input[type="number"] selector’s background-color: pink.

So this styled component I have is wrong.

const GreenInput = styled.input`
    background-color: green;
`

render (
  <GreenInput type=["number"]/>
);

I need to use the & and move the className attribute to get more specificity for my style.

const GreenInput = styled(NumberInput)`
  input& {
      background-color: green;
  }
`

This outputs:

input.<GreenInputClassId> {
  background-color: green;
}

This selector has the same specificity as input[type="number"] but is declared later, so takes precedence.

Don't forget the `className` prop!!

So this is normal styled-component stuff:

const RedDiv = styled.div`
  color: red;
`

which outputs

<div class='<someClassId>'>
</div>

.someClassId { color: red; } 

And then you can wrap that div

const BlueDiv = styled(RedDiv)`
  color: blue;
`

which outputs:

<div class='<someClassId>'>
</div>

.someClassId { color: blue; } 

And you can also style existing components. If I have the component:

const CoolComponent = (props) => {
  render(
    <div></div>;
  )
};

const PurpleDiv = styled(CoolComponent)`
  color: purple; 
`

That outputs

<div></div>

It’s not purple!!

That’s because if you want to style non-styled-component components with styled-components then you have to use the className prop to set the class onto your element.

const CoolComponent = ({className}) => {
  render(
    <div className={className}></div>;
  )
};

Which outputs

<div class='<someClassId>'>
</div>

.someClassId { color: purple; } 

`classList.toggle()` 2nd arg doesn't work in IE11

Months and months ago I faced a situation where I had to remove an element’s class outside of the react render tree.

Because toggle was being used to add the class in the code previously I used to toggle to remove it, and to ensure that it was removed and not added I used the second argument which would force it to be removed.

Today I learned that the second argument does not work in IE11.

In general, using toggle is an anti-pattern because it’s non deterministic, it depends on state that is unavailable to you when writing the code.

There are methods add and remove for classList, they have some IE11 edges too, but are more explicit about their intention.

See more info here.

Preserve whitespace while joining in Vim

I have this text:

abc
   def

There are 3 spaces on the line before “def” and I want to make sure that space is preserved.

I usually join with J in normal mode. There is, however, a :join command that behaves the same way except you can follow it with an optional !.

By using the abbreviation it is shortened to:

:j!

And the result I get is:

abc   def

Space preserved!

See :help :join for more information.

Reasonml Interpolation

Reasonml doesn’t support string interpolation in it’s primary string type, but for javascript interop they expose a

special tag quoted string interpolation

Using the {j| |j} operator and a $ for the variable.

It looks like this:

let name = "Chris";
let greeting = {j|Hi there $name|j};

Parens around the value also works:

let greeting = {j|Hi there $(name)|j};

Play with it more here

Another pipe operator, the fast pipe `|.`

Reasonml has a pipe operator |> that places a value into the first positional argument, like so:

> let result = 4 |> String.sub("abcdefg", 1)
"bcde"

This is different than the same operator in Elixir, but I get it. I just learned however that Reasonml has another pipe operator, the fast pipe |. that places the value into the first argument of the function, like this:

> let result = "abcdefg" |. String.sub(2, 4)
"cdef"

This seems to be evolving functionality with some special cases that you can learn more about in the bucklescript docs.

No-op reducer in Reason React

Generally in ReasonReact if you have a reducer component that component will have a reducer function that looks like this:

reducer: (action, state) => {
    switch(action) {
    | Change(newValue) =>
        ReasonReact.Update({value: newValue})
  }
}

ReasonReact.Update is a variant that constructs with a state value.

Another variant you can return from the reducer function is ReasonReact.NoUpdate, allowing you to not update the state if circumstances do not warrant it.

reducer: (action, state) => {
    switch(action) {
    | Change("UghWat") =>
        ReasonReact.NoUpdate
    | Change(newValue) =>
        ReasonReact.Update({value: newValue})
  }
}

Not if the user enters “UghWat” we won’t update the state with that useless value.

Change Styled Component via Parent state

Styled Components has been changing the way I think about CSS and styling. Including the css in with the component makes sense, you don’t have to hunt down styles or wonder what unravels when you start changing styles in a heavily nested scss document.

Today I learned that you can reference styled components in other components to allow parents to change the state of their children.

<Parent>
    <Thing/>
</Parent>

When a user hovers over Thing’s parent, I want to change it’s color from blue to red. I can do that by interpolating Thing into Parent.

const Thing = styled.div`
  color: blue;
`
const Parent = styled.div`
  &:hover {
    ${Thing} {
      color: red 
    }
  }
`

Reformat Reason code with the `--in-place` option

The ability to format code automatically and in a standardized way is an accepted part of writing code today. I use a format tool in javascript (w/prettier), in golang, and in Elixir.

Reasonml has it’s own format tool, refmt which is installable via npm:

npm install -g reason-cli@3.2.0-darwin

At the command line you should use the --in-place option to overwrite the specified file with the formatted code output by the tool.

> refmt --in-place src/App.re

Otherwise refmt writes to stdout, but rerouting that stdout to the same file will just truncate the file.

Single arg pattern matching with the fun operator

Reasonml has pattern matching in specific syntaxes and one of those syntaxes is the fun operator which helps you define multiple patterns for single argument functions.

let something = 
  fun
  | "hello" => "world"
  | "busta" => "rhymes"
  | x => "something else"

when called:

something("hello")
/* results in "world" */

This doesn’t work for multiple arguments however, so when you see something like this:

let add =
  fun
  | (1, 1) => 3
  | (x, y) => x + y;

just remember that the single argument in this case is a tuple, called like this add((1, 3)).

Render a list of jsx elements with ReasonReact

In javascript/jsx I can just create a list of jsx elements and place that list into the jsx.

const thingDivs = things.map((thing) => (
    <div>{thing.name}</div>
)

return (<div>
  {thingDivs}
</div>)

But ReasonReact expects the variable to be of type ReasonReact.reactElement, and so we have to convert the list of jsx nodes we create to an element with the function ReasonReact.array.

let thingDivs = List.map((thing) => 
  <div>ReasonReact.string(thing.name)</div>
, things)

<div className="parentContainer">
  (ReasonReact.array(Array.of_list(thingDivs))
</div>

ReasonReact.array returns a value of type ReasonReact.reactElement.

Output Emojis 🔥 with ReasonReact

I’m using ReasonReact on top of ReasonML and I’m trying to output some emojis like this:

      <div>(ReasonReact.string("Fire 🔥"))</div>

but the output is:

Fire 🔥

The solution I found is to use the funky looking “Js string” instead of double quotes. The Js string in ReasonML has curlies and pipes with a js in the middle {js| Fire 🔥 |js}

In context it looks like this:

<div>(ReasonReact.string({js| Fire 🔥 |js}))</div>

And now I can see some fire:

Fire 🔥 

Execute command from register

Here’s a cool command

:nmap <leader>s :smile<CR>

If you read the above in vim, how would you execute it? You can use the system buffer or tmux copy+paste and paste it to the command line, but that seems very not-vim.

Vim has a :@ command that will execute registry contents. Just put the line into your registry with yy and then call:

:@"

This executes the contents of the default register

`yo` has been replaced by `]op`

vim-unimpaired is a fantastic vim plugin full of utility mappings, many to do with toggling. I have relied heavily on yo to enter insert mode with the paste option set when I want to use the system buffer for pasting.

Recently, the yo mapping has been repurposed. Read the github issue here.

Instead, ]op is the new mapping to put you in insert mode with the paste option set.

The documentation now looks like this:

                                                *[op* *]op* *yop*
A toggle has not been provided for 'paste' because the typical use case of
wrapping of a solitary insertion is inefficient:  You toggle twice, but
you only paste once (YOPO).  Instead, press [op, ]op, or yop to invoke |o|,
|O|, or |0||C| with 'paste' already set.  Leaving insert mode sets 'nopaste'
automatically.

`nil.&to_s` evaluates to false

ruby 2.3 introducted the Safe Naviation Operator &. intended to make nil checks less verbose, simulating the functionality of the Rails introduced try method.

This helps to prevent unwanted NoMethodErrors

> nil.do_something
NoMethodError (undefined method `do_something' for nil:NilClass)
> nil&.do_something
nil

What happens when you type the & on the right side of the .?

> nil.&do_something
NameError (undefined local variable or method `do_something' for main:Object)

Normally you’d get an error, because do_something isn’t defined, but what if you are calling a method available on everything like to_s?

> nil.&to_s
false

This breaks expectations. This statement is equivalent to nil & to_s.

> nil & to_s
false

Ruby defines & as a method on nil.

> nil.method(:&)
#<Method: NilClass#&>

This method in the documentation is defined as:

And—Returns false. obj is always evaluated as it is the argument to a method call—there is no short-circuit evaluation in this case.

So with nil.&to_s you’re calling the & operator as a method and passing the result of to_s called on the main object, but it doesn’t matter because nil.& always evaluates to false.

Array concatenation with the spread operator

The spread operator in ES6 javascript is a swiss army knife of wonders. Previously in javascript if you wanted to concatenate two arrays you could use the concat method of an array.

let a = [1, 2, 3]
let b = [4, 5, 6]
a.concat(b) //concat though is not mutative, you have to assign the result
let c = a.concat(b) // we have concatenated

Whether or not Array.prototype.concat is mutative has always been something I get wrong. Some Array methods are mutative some are not! By using the spread operator, I never get this wrong (it’s not mutative).

let c = [...[1, 2, 3], ...[4, 5, 6]]
console.log(c) // [1, 2, 3, 4, 5, 6]

Each line in a Dockerfile is a layer in an image

What has helped me grok docker a bit better is knowing that every line in a Dockerfile has a corresponding hash identifier after the image has been built. Here is a sample Dockerfile:


FROM alpine

RUN echo 'helloworld' > helloworld.txt

CMD ["cat", "helloworld.txt"]

I create the image with:

docker build -t helloworld .

I can now examine each layer in the Dockerfile with docker history helloworld

IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
1e5d27ca20a8        13 hours ago        /bin/sh -c #(nop)  CMD ["env"]                  0B
84f489011989        13 hours ago        /bin/sh -c echo "Hello World" > helloworld.t…   12B
3fd9065eaf02        2 months ago        /bin/sh -c #(nop)  CMD ["/bin/sh"]              0B
<missing>           2 months ago        /bin/sh -c #(nop) ADD file:093f0723fa46f6cdb…   4.15MB

Three commands and four layers. The FROM alpine command is actually 2 layers that have been squashed together. You can see the <missing> hash for the initial command because it has been squashed into 3fd9065.

The command that creates the helloworld.txt file has a size of 12 bytes because thats the size of the file that was created.

Async/Await UnhandledPromiseRejectionWarning

When an await promise is rejected when using async/await you get an UnhandledPromiseRejectionWarning.

promise13 = () => {
  return new Promise((resolve, reject) => { reject(13)})
}

(async () => {
  let num = await promise13(); // UnhandledPromiseRejectionWarning
  console.log('num', num);
})();

There are two ways to properly handle the promise reject. The first is with a try catch block.

(async () => {
  try {
    let num = await promise13();
    console.log('num', num);
  } catch(e) {
    console.log('Error caught');
  }
})();

The second is by handling the error on the promise itself.

(async () => {
  let num = await promise13().catch((err) => console.log('caught it'));
  console.log('num', num);
})();

Both ways will allow you to avoid the UnhandledPromiseRejectionWarning and also properly handle your rejections. Beware the deprecation message that comes with this warning.

Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

xargs substitution

Output piped to xargs will be placed at the end of the command passed to xargs. This can be problematic when we want the output to go in the middle of the command.

> echo "Bravo" | xargs echo "Alpha Charlie"
Alpha Charlie Bravo

xargs has the facility for substituion however. Indicate the symbol or string you would like to replace with the -I flag.

> echo "Bravo" | xargs -I SUB echo "Alpha SUB Charlie"
Alpha Bravo Charlie

You can use the symbol or phrase twice:

> echo "Bravo" | xargs -I SUB echo "Alpha SUB Charlie, SUB"
Alpha Bravo Charlie, Bravo

If xargs is passed two lines, it will call the the command with the substitution twice.

> echo "Bravo\nDelta" | xargs -I SUB echo "Alpha SUB Charlie SUB"
Alpha Bravo Charlie Bravo
Alpha Delta Charlie Delta