Today I Learned

A Hashrocket project

Compare Dates in Neo4j.rb

Neo4j.rb stores dates as timestamps so you will have to convert your date object into a timestamp.

To convert a date object into a timestamp first convert to utc time and then to integer:

Date.current.to_time(:utc).to_i

And in your cypher query you are safe to use the comparison operators:

where('post.published_at <= ?', Date.current.to_time(:utc).to_i)

Copy Some Data From The Chrome Console

Sometimes you have some data that you are playing around with in the console, something you logged from an API response. You then want to share it, so you try to copy the whole thing into your system copy buffer. There are a couple hacky ways of doing this, but Chrome supports a really smooth way.

Use the copy function.

characters
> (8) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
copy(characters[1])

My system copy buffer now contains the entire object that makes up the second entry in that list. I can then paste it into Slack or wherever.

source

Secure Passwords With Rails And Bcrypt

If you are using bcrypt (at least version 3.1.7), then you can easily add secure password functionality to an ActiveRecord model. First, ensure that the table backing the model has a password_digest column. Then add has_secure_password to your model.

class User < ActiveRecord::Base
  has_secure_password

  # other logic ...
end

You can now instantiate a User instance with any required fields as well as password and password_confirmation. As long as password and password_confirmation match then an encrypted password_digest will be created and stored. You can later check a given password for the user using the authenticate method.

user = User.find_by(email: user_params[:email])

if user.authenticate(user_params[:password])
  puts 'That is the correct password!'
else
  puts 'That password did not match!'
end

Examining the closure

Python is the first language I’ve encountered that avails you the meta information about the defining closure of a function.

After you get the reference of a function, there is a lot of meta information available via the __code__ attribute. __code__ has many attributes and one of them is co_freevars which is all the variables defined outside of the function, but available through the closure to the function. It returns a tuple. The order of the values in this tuple is important.

The values of those co_freevars are in another dunder (__) method that is called __closure__. It also returns a tuple. The order is the same order as the co_freevars tuple. The tuple holds cell objects with one attribute, cell_contents. cell_contents holds the current co_freevar value.

def get_fn():
    a = 1
    b = 2
    def get():
        print(a)
        print(b)
        return (a, b)
    return get

gfn = get_fn()
gfn.__code__.co_freevars
# ('a', 'b')
gfn.__closure__[0]
# <cell at 0x10849c4f8: int object at 0x1081907c0>
gfn.__closure__[0].cell_contents
# 1
gfn.__closure__[1].cell_contents
# 2

Rails protects production database

Rails has a mechanism to protect production databases to be dropped (and other destructive commands). In order to do that rails database tasks use a private database rake task check_protected_environments. Here’s a db task code sample from rails code databases.rake:

task drop: [:load_config, :check_protected_environments] do
  db_namespace["drop:_unsafe"].invoke
end

Under the hood it checks the database environment from a metadata table ar_internal_metadata created by rails on the first load schema attempt

SELECT * FROM ar_internal_metadata;
     key     |  value 
-------------+---------
 environment | staging 

Access Secrets In A Rails 5.2 App

For a long time the access chain for getting at secrets in your Rails app stayed the same. For instance, getting at the secret_key_base value looked something like this:

Rails.application.secrets.secret_key_base

In the world of Rails 5.2, secrets are no longer secrets. They are now credentials. This means they are under the credentials key instead of the secrets key. Here is how you can access secret_key_base now:

Rails.application.credentials.secret_key_base

source

Configure cd To Behave Like pushd In Zsh

The Zsh environment has a setting that allows you to make the cd command behave like the pushd command. Normally when you use cd the remembered directory stack is not effected. However, if you add the following setting to your ~/.zshrc file:

setopt auto_pushd

then using cd to navigate directories will cause those directories to be added to the dirs stack.

This is the default in the oh-my-zsh configuration of zsh.

Python global closure scoping oddity

Beware closuring in global variables.

world = 'Endor'

def world_name():
    def world_knower():
      print(world)
    world = 'Hoth'
    return world_knower

knower = world_name()
knower()
# Hoth

In the above example, the reference the local world was closured in to world_knower, and the value was changed after the world_knower declaration.

What if we use the global keyword to let python know we want to use the global version of this variable?

world = 'Endor'

def world_name():
    global world
    def world_knower():
      print(world)
    world = 'Hoth'
    return world_knower

knower = world_name()
knower()
# Hoth

Yikes, the inner function still uses the outer functions local reference. I guess if we truly want to ignore the local reference, we need to declare that world is global in the inner function.

world = 'Endor'

def world_name():
    def world_knower():
      global world
      print(world)
    world = 'Hoth'
    return world_knower

knower = world_name()
knower()
# Endor

Lambdas can only be one line

Unfortunately, lambdas in Python are limited. They can be only one expression.

This works:

print_twice = lambda word: print(word * 2)
# prints: "wordword"

But you can’t assign the intermediate value to a variable.

print_twice = lambda word: result = word * 2; print result;
# Syntax error

White space is significant is this language, so there are no () {} or keywords that would help you out here.

lambdas are the only way to define anonymous functions in python, but you can still define a named function in any context.

def build_fn(a):
    def adder(b):
        return b + a
    return adder

add3 = build_fn(3)
add3(4)
# 7

Annotate Args with Anything

Python annotations don’t do anything. Annotations are just meta information about the arguments of your method. You can apply this metadata in any way that you see fit.

Let’s check out a function with no annotations:

def talk(a, b, c):
    pass

talk.__annotations__
# {}

Makes sense, an empty dictionary. Now lets say that a should be an str.

def talk(a: str, b, c):
    pass

talk.__annotations__
# {'a': <class 'str'>}

What’s unique about python is that its primitive types are objects/classes. This allows for annotations to be accomodating of any object/class.

def talk(a: str, b: 'hi', c):
    pass

talk.__annotations__
{'a': <class 'str'>, 'b': 'hi'}

Any type or instance? What about declaring a variable outside of the method and using that as an annotation.

birds = {'corvids': True}
def talk(a: str, b: 'hi', c: birds):
    pass

talk.__annotations__
# {'a': <class 'str'>, 'b': 'hi', 'c': {'corvids': True}}

Yeah you can do that!! Crzy!!

Check out how argument annotations can be used as a type system with mypy

Scripting With RVM

Because of how RVM works under the hood, you have to do a couple things to get it to work in a script.

First, you need to ensure that your script is using bash instead of sh, so add this to the top of your scripts:

#!/bin/bash

You’ll then want to make sure that RVM is sourced. Their docs recommend sourcing in a script like this:

# Load RVM into a shell session *as a function*
if [[ -s "$HOME/.rvm/scripts/rvm" ]] ; then

  # First try to load from a user install
  source "$HOME/.rvm/scripts/rvm"

elif [[ -s "/usr/local/rvm/scripts/rvm" ]] ; then

  # Then try to load from a root install
  source "/usr/local/rvm/scripts/rvm"

else

  printf "ERROR: An RVM installation was not found.\n"

fi

After that, you can utilize any of the capabilities of RVM in your script as you’d like.

Install node modules in subdir without a CD

So yea you don’t need a friend to send you a CD-ROM anymore to install node modules. You can use the World Wide Web! Pretty exciting.

On a more serious note, if your front-end is stored in a sub directory of your project, for example:

❯ tree -d -L 2
.
├── assets
|   ├── package.json
|   └── package-lock.json
└── app

Normally you would cd into assets, run npm i, and cd back out to the project root so you can go back to doing important things:

cd assets
npm i
cd -

Or you can push and pop, cause you’re kinda smart

pushd assets && npm i && popd

Or if you’re a really cool kid you’d use a sub-shell

(cd assets && npm i)

But wait! There’s another option - use the prefix CLI option in NPM!

npm i --prefix assets

It works really well for those long Dockerfile RUN statements.

List The Stack Of Remembered Directories

When you open a new Unix shell, you start in some directory, probably your home (~/) directory. If you use pushd to navigate to different directories, there is a paper trail of your movements, a listing of where you’ve been. You can view this listing of directories with the dirs command.

$ dirs
~/
$ pushd code
$ dirs
~/code ~/
$ pushd /usr/bin
$ dirs
/usr/bin ~/code ~/

Each time you pushd, the directory you have moved to is pushed onto the stack of visited directories. Alternatively, you can use the popd command to return to the previous directory, removing the current directory from the stack.

source

Change DOS to Unix text file format in VIM

The last few times I had to use a .txt file as an input, I’ve run into difficult-to-troubleshoot parsing errors. What could be wrong? I check and re-check the text file, and I can’t find any mistakes!

If the text file came from a Windows machine, this may due to a difference in line-ending between DOS and Unix text files. You can check and change this file format in Vim.

Open your file in Vim and, in normal mode, type :set ff? to see what the file format is. If it is DOS, then type :set ff=unix to change it to Unix.

for...in Iterates Over Object Properties

I don’t reach for for loops very often, so when I needed one recently I thought I’d check out the newer for...in construct. It didn’t behave quite how I was expecting. I thought it would iterate over the values in the target list, instead it seemed to be iterating over the indices.

The MDN docs explain what is going on:

The for...in statement iterates over all non-Symbol, enumerable properties of an object.

An array is an object whose properties are the indices of the values stored in the array.

const fruits = ["apple", "banana", "orange"];
for (let fruit in fruits) {
  console.log(fruit, fruits[fruit]);
}
// => "0" "apple"
// => "1" "banana"
// => "2" "orange"

The iteration value wasn’t what I was looking for, but in this case I can use it to access the value from the list. I’d be better off using a standard for loop though.

Parallel shell processing with xargs

Today I learned how to parallel run a slow command on my shell. We can use xargs combined with the flags -n and -P flags. Let’s see how this works:

find . -type f | xargs -n1 -P8 slow_command
  • slow_command your slow command that receives a file as the first arg
  • -n to specify how many arguments are passed to the slow_command
  • -P how many parallel workers xargs will spawn to run the slow_command

Check this out watch -d -n 0.1 "seq 10 | xargs -n2 -P8 echo":

watch-xargs

On this example xargs are spawning up to 8 workers to run the echo command and for each echo execution xargs will pass 2 arguments. The arguments are produced by a seq 10 and as multiple executions of echo runs in parallel we can highlight the output changes with watch.

Quit When There Is An Argument List

To start a Vim session with multiple files in the argument list, name multiple files when invoking Vim:

$ vim README.md LICENSE

The first file in the argument list, and the current buffer, is README.md. The last file in the argument list is LICENSE.

At this point if you try to quit, Vim will prevent you saying 1 more file to edit. If we look at the docs for :q and :wq, we see something along the lines of:

This fails when the last file in the argument list has not been edited.

Vim wants to ensure that you’ve paid attention to every file that you loaded up into your argument list. If you’d like to quit regardless. then this is where the :q! and :wq! variants come in handy. This commands will skip the argument list check.

Pattern match against Dates in Elixir using struct

A recent TIL by my coworker Ryan reminded me of an alternative to pattern matching on dates (and other structs) by matching on their Name. Using __struct__ to grab the name allows us to use a guard and only match on struct types we want:

def foo(%{__struct__: struct_name} = datetime)
  when struct_name in [Date, DateTime] do
    Timex.to_naive_datetime(datetime) |> foo
end

def foo(%NaiveDateTime{} = datetime) do
  IO.inspect({"My Naive Datetime", datetime})
end

Show Only Commits That Touch Specific Lines

When you run git log, you are listing all commits in reverse-chronological order for the current branch. There are ways of filtering the commits that get output from git-log. As of Git 1.8.4, git-log output can be filtered by commits that touch a range of line numbers.

This is done with the -L flag.

For instance, if I want to see all commits that touched the 13th line of my README.md file, then I can do this:

$ git log -L13,13:README.md

I can alter the command to show commits that touched a range of lines like so:

$ git log -L19,45:README.md

I used the -L flag recently to find when a dependency was added to my package.json file even though the most recent changes to that line were version bumps.

source

Remotely control your desktop over ssh on macOS

Using ssh port forwarding and vnc you can connect to your remote desktop using the Screen Sharing application.

First connect to your machine over ssh and port forward 5900.

ssh user@machine.somehwere -L 5900:localhost:5900

Then in another terminal, on your local machine, open Screen Sharing by passing a open a vnc url.

open 'vnc://localhost'

Screen Sharing should open and ask you for credentials for the remote machine. And then you do cool things on your remote desktop!

Read more about VNC here in this wikipedia article.

Hat Tip to Dorian Karter!

Capture and View screenshot on macOS remotely

First, wake up the desktop with caffeinate.

caffeinate -u -t 2 # assert that the user is active

Then switch to the application you want to have focus on the desktop with open

open -a Google\ Chrome

Then call MacOS’s screencapture command.

sudo screencapture /Users/dev/Desktop/FullScreen.png

Finally, if you are daring, using iTerm2, have downloaded imgcat from the iTerm imgcat site, have chmod +x that file, and have copied that file to /usr/local/bin, then view the captured image in your terminal with imgcat.

imgcat /Users/dev/Desktop/FullScreen.png

Call an object like a function with `__call__`

Using __call__ you can make an object behave like a function.

class HiyaPerson:
     def __init__(self, person_name):
         self.person_name = person_name
     def __call__(self):
         print("Hiya there, " + self.person_name)

hiya = HiyaPerson("Bob")
hiya()
# Hiya there, Bob

A side effect is that now a “function” can have state. Interesting!

class Counter:
    def __init__(self):
        self.count = 0
    def __call__(self):
        self.count += 1
   
count = Counter()
count()

import inspect 
dict(inspect.getmembers(count))['count']
# 1
count()
dict(inspect.getmembers(count))['count']
# 2

Show Changes In The Compose Commit Message View

When you execute git commit, you’ll be dropped into your default editor and prompted to compose a commit message. By default you’ll only see the status and names of the files involved in the commit.

To also see the line-by-line-changes in this view, you’ll want to commit in verbose mode.

$ git commit --verbose

You can also set verbose mode as the default by updating your ~/.gitconfig file.

[commit]
    verbose = true

source

Open Slack's Keyboard Shortcuts Reference Panel

Slack has a ton of keyboard shortcuts, but you might only be familiar with some of the more obvious ones. When I started using Slack, I quickly discovered that Cmd+} and Cmd+{ allow you to navigate forward and backward through your different Slack workspaces.

But there is a whole world of Slack keyboard shortcuts that I didn’t know about. By hitting Cmd+/ a Keyboard Shortcuts reference panel will be toggled open. This lists all of the keyboard shortcuts you didn’t know you needed.

Ad block is hiding your selector

Why is .ad-inner set to display: none !important? It’s because I’m using uBlock Origin, a fantastic ad blocker. It makes the internet tolerable. But it completely breaks the site I’m working on because a previous dev on the project chose ad-inner as a class name.

It turns out, there are a lot of class names that you shouldn’t use. Class names, ids, even certain dimensions applied as inline styles. uBlock Origin sources its rules from about 8 different lists, and the list that contained a rule for .ad-inner is EasyList. EasyList is hosted on github and the particular file with selector rules is easylist_general_hide.txt

Here are all the class names in the list that begin with .ad-i

##.ad-icon
##.ad-identifier
##.ad-iframe
##.ad-imagehold
##.ad-img
##.ad-img300X250
##.ad-in-300x250
##.ad-in-content-300
##.ad-in-post
##.ad-in-results
##.ad-incontent-ad-plus-billboard-top
##.ad-incontent-ad-plus-bottom
##.ad-incontent-ad-plus-middle
##.ad-incontent-ad-plus-middle2
##.ad-incontent-ad-plus-middle3
##.ad-incontent-ad-plus-top
##.ad-incontent-wrap
##.ad-index
##.ad-index-main
##.ad-indicator-horiz
##.ad-inline
##.ad-inline-article
##.ad-inner
##.ad-inner-container
##.ad-innr
##.ad-inpage-video-top
##.ad-insert
##.ad-inserter
##.ad-inserter-widget
##.ad-integrated-display
##.ad-internal
##.ad-interruptor
##.ad-interstitial
##.ad-intromercial
##.ad-island
##.ad-item
##.ad-item-related

A good rule of thumb is to not start a class name with .ad. This survey says that 30% of users are using ad blockers.

range() v slice()

A range is not a slice and a slice is not a range. But they look the same.

slice(1, 10)
# slice(1, 10, None)
range(1, 10)
# range(1, 10)

They both take step as a third argument.

slice(1, 10, 3)
# slice(1, 10, 3)
range(1, 10, 3)
# range(1, 10, 3)

But one is iterable and the other is not.

list(slice(1, 10))
# TypeError: 'slice' object is not iterable
list(range(1, 10))
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

One can be used as a list indices, one cannot.

[1, 2, 3, 4, 5][range(1, 2)]
# TypeError: list indices must be integers or slices, not range
>>> [1, 2, 3, 4, 5][slice(1, 2)]
# [2]

They both conform to the start, stop, step interface.

s = slice(1, 10)
s.start, s.stop, s.step
# (1, 10, None)
r = range(1, 10)
r.start, r.stop, r.step
# (1, 10, 1)

You can slice a range but you can’t range a slice.

range(1, 10)[slice(2, 8)]
# range(3, 9)
slice(1, 10)[range(2, 8)]
# TypeError: 'slice' object is not subscriptable

Gesture To View All Windows Of Current Mac App

I use a Mac as my primary development machine. When working on a web application, I often end up with a couple Chrome windows open and sometimes even a couple terminal windows open. I generally use the Cmd+~ key binding to toggle through them. This can occasionally get confusing though. To get the fuller picture, I can get a birds-eye view of all windows for the current app using a track pad gesture.

Swiping down with three fingers on the track pad will provide a zoomed out view of all windows. Click on the window you care about to view that or swipe back up with three fingers to dismiss it.

source

Counting is as easy as...

Python has a specialized dict data structure for a common task, counting. Counter can process and store the counts of items you pass it.

Initialized like this with chars, and then keys:

from collections import Counter

char_count = Counter('xyxxyxyy')
# Counter({'x': 4, 'y': 4})

keys_count = Counter({'apple': 2, 'banana': 5, 'pear': 3})
# Counter({'banana': 5, 'pear': 3, 'apple': 2})

Then updating the Counter is easy with update:

chars_count.update('abxyabxy')
# Counter({'x': 6, 'y': 6, 'a': 2, 'b': 2})

keys_count.update({'apple': 1, 'banana': 2, 'fruit': 3})
# Counter({'banana': 7, 'apple': 3, 'pear': 3, 'fruit': 3})

Then figure out which items are the most common:

chars_count.most_common(2)
# [('x', 6), ('y', 6)]
keys_count.most_common(2)
# [('banana', 7), ('apple', 3)]

Read more about some really useful things you can do with counter objects in the Python docs

Pattern matching with `Kernel.match`

Pattern matching is powerful, but when iterating over a list with an Enum function you must allow all variants of the list to be processed. So this fails:

sample = [{1, "A"}, {2, "B"}]
 > Enum.filter(sample, fn ({_, "B"}) -> true end)
** (FunctionClauseError) no function clause matching in :erl_eval."-inside-an-interpreted-fun-"/1

    The following arguments were given to :erl_eval."-inside-an-interpreted-fun-"/1:

        # 1
        {1, "A"}

    (stdlib) :erl_eval."-inside-an-interpreted-fun-"/1
    (stdlib) erl_eval.erl:826: :erl_eval.eval_fun/6
    (elixir) lib/enum.ex:2898: Enum.filter_list/2

Instead of using pattern matching here we can just use an anonymous function that takes all args and makes a comparison.

sample = [{1, "A"}, {2, "B"}]
Enum.filter(sample, fn ({_, letter}) -> letter == "B" end)
# [{2, "B"}]

But the cool way to do it is with Kernel.match?. Which according to the docs is:

A convenience macro that checks if the right side (an expression) matches the left side (a pattern).

What that looks like:

sample = [{1, "A"}, {2, "B"}]
Enum.filter(sample, &match?({_, "B"}, &1))
# [{2, "B"}]

H/T Taylor Mock

Set Vim Filetype or Syntax with Modeline

Here’s a problem I faced today: I’m writing a Thor CLI. The convention for that project is a file called cli, written in Ruby but with no .rb extension. Vim highlights it and otherwise treats it like a conf file, but it’s Ruby. I want my editor to progamatically recognize that and act accordingly.

One solution is Vim’s modeline. With modeline enabled, either of these settings will enable syntax highlighting on buffer read. They can both be used at the same time as shown.

# vi: syntax=ruby
# vi: filetype=ruby

def ruby_here
end

Find The Date That A File Was Added To The Repo

The git log command has a bunch of flags that you can use to filter commits and format their output.

We can get git log to only show the date for a commit in the short format with the following flags:

$ git log --pretty=format:"%ad" --date=short

We can also get git log to filter commits to just those that have files being added:

$ git log --diff-filter=A

Like many git commands, we can restrict the output to those that match a path or file.

$ git log -- README.md

If we put all of these together, then we have a one-line command for getting the date a specific file was added to the repository:

$ git log --pretty=format:"%ad" --date=short --diff-filter=A -- README.md
2015-02-06

See man git-log for more details.

Enable Keyboard Shortcuts In Gmail

In these modern times of asynchronous communication and paperless receipts, a person’s email inbox can get mighty full. Keeping that influx of emails at bay is a challenge. If you’d like to start unburying yourself and get on the path to inbox zero — Gmail’s keyboard shortcuts can help.

Keyboard shortcuts are not enabled by default, so you’ll need to turn them on in settings. Click the gear icon, select Settings and then scroll down under the General tab until you find the Keyboard shortcuts section. Select the Keyboard shortcuts on radio button and then Save changes.

You’ll now have access to a variety of shortcuts, such as using the j and k keys to move up and down the list of emails in your inbox. Find the one you want and hit o to open it up.

Keep exploring — there is a whole world of keyboard shortcuts out there.

h/t Jake Worth

Show better image diff on git

Today I learned how to improve my git diff with images. For context check this TIL first.

I gave a step further on my git config to allow a better diff of my images using imagemagick compare features.

git config --global diff.image.textconv 'imgcat'
git config --global diff.image.command 'imgdiff'

So textconv will be used by git show commands and it’s using iTerm2 imgcat.

And command will be used by git diff command and it uses my new shell script imgdiff added to my PATH:

#!/bin/bash

if [[ -f "$1" ]] && [[ -f "$2" ]]; then
  compare "$2" "$1" png:- | montage -geometry +4+4 "$2" - "$1" png:- | imgcat
else
  if [[ -f "$1" ]]; then
    echo "+ Image Added"
    imgcat "$1"
  else
    echo "- Image Removed"
    imgcat "$2"
  fi
fi

exit 0

With that I can have a diff like that:

git diff

So previous image to the left, new to the right and imagemagick comparison in the middle.

Gmail 'o'

In my quest to learn all the Gmail hotkeys, today I learned ‘o’.

‘o’ opens the focused email in your inbox. Combine this with ‘gi’ (go to inbox) and Vim-style JK (down/up throught the inbox list), and you’re cruising. 🏁

Hotkeys must be enabled in your settings.

Navigate With State Via @reach/router

With @reach/router, you can programmatically change your route using the navigate function. This utilizes the Context API, so its available anywhere nested under your router. To provide some data to the destination location, include a state option in the navigate call.

const onSubmit = ({ data }) => {
  /* submit logic ... */

  navigate(nextPath, { state: { data }});
}

The component that renders in response to this navigation will have access to this state.

const NextComponent = ({ location }) => {
  const { data } = location.state;

  return (
    /* ... */
  )
}

Prevent reach/router Redirect Error Screen In Dev

When using @reach/router’s <Redirect> with tools like create-react-app and Gatsby, you’ll get those tools’ development-mode error screen overlays whenever a redirect happens. This has to do with how @reach/router utilizes componentDidCatch to change the path without a render. That error screen overlay can get annoying though. Prevent it with the noThrow prop.

return (
  <Redirect to={anotherPath} noThrow />
);