Today I Learned

A Hashrocket project

Custom Validation in Ecto

Sometimes the standard validation options aren’t enough.

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

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

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

And then define validate_odd_number like this:

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

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

Remember that when f is :number_of_limbs:

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

Parallel xargs fails if any of its children do

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

All child processes exit zero:


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

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

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

xargs follows suit.

Ecto's `distinct` adds an order by clause

When using distinct on you may encounter this error:

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

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

So the above query works when it looks like this:

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

OK, now it works.

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

This elixir statement:

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

Produces this sql (cleaned up for legibility):

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

Ecto added color to the order by!

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

Read the docs!

Find File Case-Insensitively 🔎

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

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

But with case insensitivity:

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

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

$ find . -iname Utils.js

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

Transactions can timeout in Elixir

In Ecto, transactions can timeout. So this type of code:

  Repo.transaction fn -> 
    # Many thousands of expensive queries
    # And inserts
  end

This type of code might fail after 15 seconds, which is the default timeout.

In Ecto you can specify what the timeout should be for each operation. All functions that make a request to the database have the same same shared options of which :timeout is one.

Repo.all(massive_query, timeout: 20_000)

The above query now times out after 20 seconds.

These shared options apply to a transaction as well. If you don’t care that a transaction is taking a long time you can set the timeout to :infinity.

  Repo.transaction(fn -> 
    # Many thousands of expensive queries
    # And inserts
  end, timeout: :infinity)

Now this operation will be allowed to finish, despite the time it takes.

Timing A Function In Elixir

Erlang provides the :timer module for all things timing. The oddly named function tc will let you know how long a function takes:

{uSecs, :ok} = :timer.tc(IO, :puts, ["Hello World"])

Note that uSecs is microseconds not milliseconds so divide by 1_000_000 to get seconds.

microseconds are helpful though because sometimes functions are just that quick.

:timer.tc(IO, :puts, ["Hello World"])
# {22, :ok}

You can also call :timer.tc with a function and args:

adding = fn (x, y) ->  x + y end

:timer.tc(adding, [1,3])
# {5, 4}

Or just a function:

:timer.tc(fn -> 
    # something really expensive
    :ok
    end)
# {1_302_342, :ok}

Ack ignores node_modules by default

When searching through your JavaScript project it doesn’t make sense to search through your node_modules. But if your are on a spelunking journey into the depths of your dependencies, you may want to search through all your node_modules!

ack ignores node_modules by default, and ack being ack you can ack through ack to check it out:

> cat `which ack` | ack node_modules
--ignore-directory=is:node_modules

This is different behaviour from ag and rg which also ignore node_modules but not explicitly. They both ignore node_modules by ignoring all entries in the .gitignore file.

rg claims to implement full support for the .gitignore file while also claiming other search tools do not. The open issues list for ag bears that out.

With each of these tools, explicitly stating the directory to search through overrides the ignore.

> ack autoprefix node_modules
> rg autoprefix node_modules
> ag autoprefix node_modules

`user-select:none` needs prefixes for each browser

The user-select css property governs if text is selectable for a given element. user-select: none means that it is not selectable.

What’s interesting about this property is that while each browser supports it, they each require their own prefix, except Chrome, which does not need a prefix.

In create react app, what starts out as:

user-select: none;

Gets expanded to:

-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;

But the default browserList configuration for development in your package.json file is:

"development": [
    "last 1 chrome version",
    "last 1 firefox version",
    "last 1 safari version"
]

And so in development, it gets expanded to:

-webkit-user-select: none;
-moz-user-select: none;
user-select: none;

Sorry Micrsoft.

How does create react app know which prefixes to render? The caniuse-lite npm package has up-to-date support data for each property and user-select:none is defined here.

That data is compressed. Here’s how to uncompress it using the node cli to see what it represents:

const compressedData = require('caniuse-lite/data/features/user-select-none');
const caniuse = require('caniuse-lite');
const unpackFunction = caniuse.feature;
unpackFunction(compressedData);

This is accomplished in create react app by the npm package autoprefixer;

Reduce Depth of an Existing Git Repo ⚓️

git pull --depth works on an existing repo to set the depth of references retrieved. To quote the --depth docs:

Limit fetching to the specified number of commits from the tip of each remote branch history.

So, what happens when you run this? Here’s me experimenting with the Elixir repo:

$ git clone https://github.com/elixir-lang/elixir.git
$ cd elixir
$ git log --oneline | wc -l
   15670 # 15670 entries!
$ git pull --depth=1
# ...pulling the shallow repo
$ git log --oneline | wc -l
   1 # 15670 to 1... woah!
$ git log
# ...output from just one commit

Is .git/ a lot smaller now? Not yet, because there are many dangling references. This Stack Overflow answer shows you how to cleanup that directory. After setting a depth of one and following its instructions, I reduced the Elixir repo’s .git/ size by 90%.

Check out man git-pull for more information.

Zoom Hotkeys to Toggle Audio and Video 🎛

Zoom users, two new hotkeys for you on Mac: CMD-SHIFT-A to toggle audio and CMD-SHIFT-V to toggle video. The ability to control my A/V presentation in long video calls makes these hotkeys worth the muscle memory investment.

Zoom has another handy audio feature in preferences: temporarily unmute by pressing the spacebar. This is perfect for standups, where I mostly want to be muted, but need to be able to unmute quickly for short periods of time.

Dash Docset Keywords 🗝

Dash has a customizable keyword for each Docset. Here are the defaults for a random Hashrocket collection*:

image

These keywords scope search results to one Docset; use one in the Dash search bar like so:

elixir:String.split

And from Alfred:

dash elixir:String.split

This is useful when you have many Docsets, and are sure where you want to look, which should be true almost all the time. It’s nice when using two complementary technologies like Elixir and Elm that share a function namespace (such as String.split).

* Also note: this list order can be changed, as noted in the table header. Move libraries you use often above those you use rarely.

Dash Find in Page 🔎

To build upon my earlier post, Integrate Alfred and Dash: Dash supports find-in-page search via a whitespace. To search on a docs page, add a space after the function or keyword name, and then enter your search query.

Here’s a command you could run to find JavaScript’s Array.prototype.unshift() and search on that docs page for the ‘specification’ header, where the associated ECMAScript standards for unshift are found.

unshift specification

This command from Alfred could look like:

dash unshift specification

Integrate Alfred and Dash 🤝

Today I’m testing an intergration between Alfred, the powerful alternative to Finder, and Dash, the local-documentation tool for Mac. My goal is a single command, run from anywhere on a Mac, that searches one or many sets of docs for a named function.

This tutorials showed me how to do it. TL;DR, it’s a one-click setup in Dash:

https://github.com/Kapeli/Dash-Alfred-Workflow

Once complete, I can trigger Alfred (with CMD + SPACE, or any key combo that’s not assigned elsewhere), type dash List.reverse, hit enter, and Alfred loads all the List.reverse docs I’ve downloaded in Dash.

Custom React Hook Must Use `use`

You can build your own hooks by composing existing hooks.

Here, I create a custom hook useBoolean by wrapping useState:

const useBoolean = () => useState(true);

Which I can then use in my component:

function Value() {
  const [value, setValue] = useBoolean();

  return <div onClick={() => setValue(!value)}>Click me {String(value)}</div>;
}

The react documentation very politely asks that you start the name of your hook with use. This is isn’t strictly necessary, and it will still work if you call it:

const doBoolean = () => useState(true);

But that violates the Rules of Hooks.

You can include an eslint plugin that will prevent you from breaking the rules. This plugin is installed by default in create-react-app version 3.

Aggregate Arrays In Postgres

array_agg is a great aggregate function in Postgres but it gets weird when aggregating other arrays.

First let’s look at what array_agg does on rows with integer columns:

select array_agg(x) from (values (1), (2), (3), (4)) x (x);
-- {1,2,3,4}

It puts each value into an array. What if are values are arrays?

select array_agg(x)
from (values (Array[1, 2]), (Array[3, 4])) x (x);
-- {{1,2},{3,4}}

Put this doesn’t work when the arrays have different numbers of elements:

select array_agg(x)
from (values (Array[1, 2]), (Array[3, 4, 5])) x (x);
-- ERROR:  cannot accumulate arrays of different dimensionality

If you are trying to accumulate elements to process in your code, you can use jsonb_agg.

select jsonb_agg(x.x)
from (values (Array[1, 2]), (Array[3, 4, 5])) x (x);
-- [[1, 2], [3, 4, 5]]

The advantage of using Postgres arrays however is being able to unnest those arrays downstream:

select unnest(array_agg(x))
from (values (Array[1, 2]), (Array[3, 4])) x (x);
--      1
--      2
--      3
--      4

Send a Command's Output to Vim (Part II) ↪️

In a Hashrocket blog post, 10 Vim Commands for a Better Workflow, I wrote about :.! <command>, which replaces the output of <command> with your current line.

Today I learned what this technique is called: filtering. From the docs:

filter is a program that accepts text at standard input, changes it in some way, and sends it to standard output. You can use the commands below to send some text through a filter, so that it is replaced by the filter output.

An even shorter version is just !!<command> in normal mode. A use case for this would be writing docs, where command-line output (ls, curl, etc.) can help demonstrate an idea.

Check out :help !! to see all the permutations of this interesting command.

ALL CAPS SQL

A while ago I read The Mac Is Not a Typewriter by Robin Williams. In it, the author claims:

Many studies have shown that all caps are much harder to read. We recognize words not only by their letter groups, but also by their shapes, sometimes called the “coastline.” —pg. 31, The Mac Is Not a Typewriter

I’ve found this to be true. When we teach SQL, students are often surprised that we don’t capitalize PostgreSQL keywords, preferring this:

select * from posts limit 5;

To this, which you might see in an SQL textbook:

SELECT * FROM posts LIMIT 5;

My arguments against the latter syntax: it’s practically redundant in PostgreSQL, it’s harder to type, and it’s unnecessary because any good text editor highlights the keywords. Now I have another: such writing has been, in typesetting, shown to be harder to read. WHERE and LIMIT look similar from a distance in all-caps, but they mean and do different things.

It’s a style opinion each developer gets to refine for themselves. To quote Williams: “Be able to justify the choice.”

Clean stopped containers & dangling images #docker

Today I learned how to clean stopped containers in Docker. Starting in Docker 1.13 a new prune command has been introduced.

docker container prune

(docs)

No one likes dangling images…

To list the numeric ids of dangling images dangling images use the filter with the dangling flag and -q to surpress anything but IDs:

dangling_images=$(docker images -qf dangling=true)

(docs)

Then delete the images

docker rmi $dangling_images

(docs)

You can add those to a script and run it from time to time to reclaim hard drive space and some sanity.

How to write a render prop

Hi my name is Matt. This is how to write a dependecy-inverted React component using the render prop pattern. It’s useful when you want to encapsulate and share common logic without knowing how it will be used or what children it should render. The render prop pattern is the successor to higher-order components and solves HoC’s problems with naming collisions.

If you’re on the latest version of React (>= 16.8) you should probably use a custom hook instead.

function FullName({ children, firstName, lastName }) {
    const fullName = firstName + ' ' + lastName
    return children(fullName)
}

// Usage:
function App() {
  return (
    <FullName firstName="Thor" lastName="Odinson">
        {fullName => <h1>Hello {fullName}!</h1>}
    </FullName>
  )
}

How to expose entire Swift class to Objective-C

Use the @objcMembers annotation in your Swift class. When working on a project that is migrating from Objective-C to Swift you will most likely be sharing all Swift functions with Objective-C, but that could start to look ugly:

class MyClass: NSObject {
  @objc func fancy() -> String {
    return "fancy"
  }
  
  @objc func tooFancy() -> String {
    return "🤵"
  }
}

But if everything needs to be available to Objective-C, we simply do:

@objcMembers
class MyClass: NSObject {
  func fancy() -> String {
    return "fancy"
  }
  
  func tooFancy() -> String {
    return "🤵"
  }
}

How to remove NotificationCenter observer in Swift

Use the method deinit. In Objective-C classes I would always remove NSNotificationCenter observers in the -dealloc method, but a Swift class doesn’t have a -dealloc method. Instead, Swift has a deinit method.

Here is an example of Objective-C:

@implementation MyClass
  - (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
  }
@end

And the equivilant in Swift:

class MyClass {
  deinit {
    NotificationCenter.default.removeObserver(self)
  }
}

Open iOS simulator app data directory

If you need to quickly open an app’s document directory on the iOS Simulator, you can quickly get the path from the xcrun CLI.

xcrun simctl get_app_container booted ${bundle_id} data

Here’s some ruby you can throw into a Rakefile of your iOS app 😉

# Rakefile
desc "Open the simulator document directory"
task :docs do
  bundle_id = File.read("MyAppName/MyAppName.xcodeproj/project.pbxproj")
    .scan(/PRODUCT_BUNDLE_IDENTIFIER = "(.*)"/)
    .flatten.first

  app_directory = `xcrun simctl get_app_container booted #{bundle_id} data`

  puts "Opening simulator directory: #{app_directory}"
  `open #{app_directory}`
end

Delete a Command from ZSH history 📚

A while ago, I restored this site’s production database to a backup captured 24 hours earlier (the reason isn’t important). Now in my terminal history, heroku pg:backups:restore a719 DATABASE_URL -rproduction is just hanging out, ready for me to accidentally smash, sending our production database hurtling back into the past. How do I remove this destructive command from my history?

In my terminal, ZSH, there’s a file called ~/.zsh_history, and a similar one for Bash. To remove the command, open that file and remove the entry from the list.

cat somefile
heroku pg:backups:restore a719 DATABASE_URL -rproduction # delete me!
ls

Open a new terminal window, and the bad command is gone.

To avoid this situation, consider the following setting (thanks Dillon!):

# ~/.zshrc
setopt HIST_IGNORE_SPACE

With this, any command preceded by a space is excluded from history. One could alias a destructive command to itself, preceded by a space, and save themselves a headache. Note a weird bug here: the last command appears in history, even if it should be excluded, until another command is entered. Banish it to the ether by running just an empty space as a command.

Count true values with postgres

I can try to count everything that is not null in postgres:

select count(x.x)
from (
  values (null), ('hi'), (null), ('there')
) x (x);
# 2

But if I try to count everything that is true in postgres, I don’t get what I want:

select count(x.x)
from (
  values (false), (true), (false), (true)
) x (x);
# 4

I can, however, take advantage of the postgres ability to cast boolean to int:

select true::int;
# 1
select false::int;
# 0

Using ::int I get:

select count(x.x::int)
from (
  values (false), (true), (false), (true)
) x (x);
# 4

Postgres is still counting everything that is not null, but what if use sum instead?

select sum(x.x::int)
from (
  values (false), (true), (false), (true)
) x (x);
# 2

Because everything is either a 0 or a 1, sum behaves like count.

Now you can do something like this:

select
  sum((status = 'Awesome')::int) as awesomes,  
  sum((status = 'Terrible')::int) as terribles
from statuses;

Print the current stacktrace in Elixir

Stacktrace, backtrace, callstack, in Elixir its stacktrace and it’s available via Process.info/2 using the :current_stacktrace item:

Process.info(self(), :current_stacktrace)

And to print it:

IO.inspect(Process.info(self(), :current_stacktrace), label: "STACKTRACE")

I’m also learning that Process.info/2 takes a pid and an item as arguments. When you call Process.info/1 with just the pid you only get a subset of the info available, not everything.

The items available via Process.info/1 are listed in the erlang documentation here.

The additional items available via Process.info/2 are listed in the erlang documentation here.

You may note that backtrace is also an item that is available via Process.info but it contains more information than you are might need to figure out where you are in the code.

What's the Trailing Underscore in Elm?

Variables such as model_, with a trailing underscore, are allowed and conventional in Elm. If you’re familiar with a language where _model can mean an unused variable, this can cause a double-take. The trailing underscore is a nod to Haskell, telling us the variable is related, or similar, to a prior variable.

Here’s an example: model_ is the argument of the update function in the Elm architecture, and model is the updated model we’ll return:

> model_ = { start = "now" }
{ start = "now" } : { start : String }
> model = { model_ | start = "tomorrow" }
{ start = "tomorrow" } : { start : String }

This Stack Overflow answer summarizes the convention:

https://stackoverflow.com/a/5673954/2112512

A single quote (model') was used similarly in the past; that syntax was deprecated in Elm 0.18. Here’s a GitHub issue describing that decision:

https://github.com/elm-lang/elm-plans/issues/4

Give a commit a new parent

Given I have these logical commits on two branches:

normalbranch: A - B - C - D

funkybranch: Z - Y - X
git co normalbranch
git rebase --onto X C

Then the logical commits of normalbranch will now be:

normalbranch: Z - Y - X - C - D

We’ve given commit C the new parent of X. C’s hash will change and D’s hash will change.

I use this when I build on top of a branch that I’ve already submitted for a PR. That branch will get merged into the new root branch, and then I’ll need the new parent on the root branch for the commits that I’m currently working on.

PostgreSQL Triggers and Views 🐘

Today I learned a lot about PostgreSQL.

  1. Views can have triggers!
  2. Deleting such a view also deletes the trigger!

To demonstrate, let’s create a table and record, and a view that looks at our table.

create table some_table (name varchar);
insert into some_table values ('some name');
create view some_view as select name from some_table;

Now, we need a test function:

create or replace function always_null() returns trigger as $always_null$
  begin
    return null;
  end;
$always_null$ language plpgsql;

Let create a trigger for our function:

create trigger some_table_trigger
  instead of delete on some_view
  for each row execute procedure always_null();

Here’s our view… with a trigger attached!

backup=# \d some_view
                   View "public.some_view"
 Column |       Type        | Collation | Nullable | Default
--------+-------------------+-----------+----------+---------
 name   | character varying |           |          |
Triggers:
    some_table_trigger INSTEAD OF DELETE ON some_view FOR EACH ROW EXECUTE PROCEDURE always_null()

Our trigger can be inspected (lots of interesting info omitted):

backup=# select * from information_schema.triggers;
-[ RECORD 1 ]--------------+--------------------------------
trigger_name               | some_table_trigger

Drop the view, and lose the trigger:

backup=# drop view some_view;
DROP VIEW
backup=# select * from information_schema.triggers;
(0 rows)

Flunk Your ExUnit Tests ❌

Today I got to use the flunk/1 function in an ExUnit test. I like everything about this function, from its name to its signature.

Here’s how we used it:

case result do
  "bad" ->
    flunk("Your result is bad, and you should feel bad.")

  "good" ->
    assert result_passes_other_tests(result)
end

It fit well into a helper function that should fail if my result ever comes back a certain way.

flunk docs

`mix phx.digest` creates the manifest

mix phx.digest creates production ready assets: hashed, zipped and compressed.

In production, when you call:

Endpoint.static_path('asset_name.css')

This will look for a file in the priv/static directory and return the path for that file. But what you want is the hashed version of that file, because modern browsers are greedy cachers and will you use the use to bust that cache.

The static_path function can return a path that represents the cached version, but it needs to read the manifest, which maps the file to it’s hashed, zipped and compressed versions.

mix phx.digest creates the manifest along with the hashed, zipped and compressed versions of all the files in the priv/static directory.

PostgreSQL: Table or View?

I’m doing some database exploration today and needed to find out if a collection of tables are all tables, or if some of them are views. By querying the information schema via the following: select table_name, table_type from information_schema.tables;, I learned more about each table and its type:

> select table_name, table_type from information_schema.tables;
              table_name               | table_type
---------------------------------------+------------
 cats                                  | BASE TABLE
 dog                                   | BASE TABLE
 dogs_and_cats                         | VIEW

Update Map Syntax

There is a special syntax for updating a map in elixir.

thing = %{a: 1, b: 2, c: 3}
updated_thing = %{thing | b: 4}
# %{a: 1, b: 4, c: 3}

But be careful, it throws an error if you try to update a key that doesn’t exist!!

thing = %{a: 1, b: 2, c: 3}
# ** (KeyError) key :x not found in: %{a: 1, b: 2, c: 3}

Skip Pending Tests in ExUnit

In ExUnit you have the ability to tag a test with any atom:

@tag :awesome
test "my awesome test" do
end

@tag :terrible
test "my terrible test" do
end

And then you can exclude those tags at the command line so that your terrible test does not run:

mix test --exclude terrible

So you can make your own tag :pending and exclude those. If you don’t want to have to set the flag at the command line everytime, you can call ExUnit.configure. This is typically placed in the test/test_helper.exs file before ExUnit.start().

ExUnit.configure(exclude: :pending)
ExUnit.start()

Now your pending tests will not run.

That is how you can use custom tags to skip tests, but you can also just use the built in skip tag to skip tests.

@tag :skip
test "my terrible test" do
end

Timex `between?` is exclusive but can be inclusive

Timex.between? is a great function for determining if a time is in a specific time period, but it’s exclusive, so if you are testing for a time at the boundary the result will be negative.

iex> end_time = Timex.now()
iex> start_time = Timex.shift(end_time, days: -7)
iex> time = start_time
iex> Timex.between?(time, start_time, end_time)
false

Never fear, you can pass an inclusive option:

iex> Timex.between?(time, start_time, end_time, inclusive: true)
true

But you don’t have to be inclusive on both sides! Here, I pass :end so that I am only inclusive at the end of my time period.

iex> Timex.between?(time, start_time, end_time, inclusive: :end)
false

And of course I can be only inclusive at the beginning of the period if I prefer:

iex> Timex.between?(time, start_time, end_time, inclusive: :start)
true

Use `reset_column_information` to Migrate Data

If you’re generating a Rails migration, chances are you might need to facilitate migrating data to a new column. You can use reset_column_information in a migration file to pick up your changes and immediately do something with those new columns.

Assuming we have 2 models, DraftPost and Post -

  class AddColumnDraftToPosts < ActiveRecord::Migration[5.2]
    def change
      add_column :posts, :draft, :boolean, default: true
      Post.reset_column_information
      DraftPost.all.each do |draft_post|
        Post.create(content: draftPost.content)
        draft_post.delete
    end
  end

asdf Global Versions 🌏

Spend a bit of time with asdf, and you might see an error like this:

$ npm install
asdf: No version set for command npm
you might want to add one of the following in your .tool-versions file:

nodejs 10.15.3
nodejs 8.9.1

The project I’m trying to set up via npm install doesn’t specify a Node version in .tool-versions, and since I have multiple Nodes on my machine, asdf isn’t sure which to use.

I don’t want to edit .tool-versions in this project; I’d rather asdf had a global default.

Here’s how I made that happen:

$ asdf global node 10.15.3   

How to clear a Mac terminal and its scroll-back?

Just type this: clear && printf '\e[3J'

Or even better create an alias for that, here’s mine:

alias clear='clear && printf "\e[3J"';

Here’s what I’ve learned today:

On Mac a regular clear is pretty much the same as typing Control + L on iTerm2. This clears the screen what’s good but sometimes I want to clear all the scroll-back to clean the noise and find things faster.

In order to clean the scroll-back I was performing a Command + K. This cleans the screen and the scroll-back. That’s great, except that it messes up with tmux rendering and tmux holds all the scroll-back per pane, so it won’t work at all.

So my new alias solves that as after clear the screen it also sends a terminal command to reset the scroll back through printf '\e[3J' and this keeps tmux working just fine!

Print Calendar With Week Number 📅

I use the week number (1-52) in my notetaking. How do I know what week number it is? ncal.

$ ncal -w
    May 2019
Mo     6 13 20 27
Tu     7 14 21 28
We  1  8 15 22 29
Th  2  9 16 23 30
Fr  3 10 17 24 31
Sa  4 11 18 25
Su  5 12 19 26
   18 19 20 21 22

Though not shown in the output above, today’s date (the 10th) is highlighted in my terminal output. At the bottom of the column containing today’s date is the week number (19).

Friendly Zoom Personal Meeting URL ➡

If you have a Zoom account, you have a Personal Meeting URL— a permanent video conferencing room tied to your account. It looks like this:

https://zoom.us/j/5551112342

When another person with Zoom installed visits this link in a browser, Zoom starts a call in your room.

A pro move is to permenantly redirect a subdomain to this URL, like so:

chat.tomcruise.com

Now you have a memorable link you can share in online and offline conversation.

Match across lines with Elixir Regex `dotall` (s)

Elixir Regex is PCRE compliant and Ruby Regex isn’t in at least one specific way. The m (multiline) flag behaves differently in Elixir and Ruby.

Without any modifiers, Regex does not match across new lines:

iex> Regex.scan( ~r/.*/, "a\nb")
[["a"], [""], ["b"], [""]]
iex> Regex.scan( ~r/.*/, "ab")
[["ab"], [""]]

With the m (multiline) modifier, Regex will match the beginning of each line when using the ^ char.

iex> Regex.scan( ~r/.*/m, "a\nb")
[["a"], [""], ["b"], [""]]
iex> Regex.scan( ~r/^.*/, "a\nb")
[["a"]]
iex> Regex.scan( ~r/^.*/m, "a\nb")
[["a"], ["b"]]

The s (dotall) modifier is the right way in Elixir to match across newlines.

iex> Regex.scan( ~r/.*/s, "a\nb")
[["a\nb"], [""]]
iex> Regex.scan( ~r/^.*/s, "a\nb")
[["a\nb"]]

In ruby, you can match across lines with the m (modifier) and the s is ignored.

irb> "a\nb".scan(/.*/)
=> ["a", "", "b", ""]
irb> "a\nb".scan(/.*/m)
=> ["a\nb", ""]
irb> "a\nb".scan(/.*/s)
=> ["a", "", "b", ""]

Read about the history of dotall here