Cycle an array using ES2015

ES2015 is fun and allows you to write more concise Javascript.

Here’s how to cycle an array of values. Use it to zebra stripe a table or whatever:

function cycle(...args) {
  return (i) => args[i % args.length];
}

And we can still make it shorter:

const cycle =
  (...args) =>
  (i) =>
    args[i % args.length];

Use it in React like this:

function Table({ posts }) {
  const cls = cycle("odd", "even");

  return (
    <table>
      {posts.map((post, i) => (
        <tr key={i} className={cls(i)}>
          <td>{post.title}</td>
        </tr>
      ))}
    </table>
  );
}

Compare it to regular ES5:

function cycle() {
  var args = Array.prototype.slice.call(arguments);

  return function (i) {
    return args[i % args.length];
  };
}

Not that much longer but definitely less fun. We can have fun.

Updated Elixir Phoenix 1.1.4 with Webpack and React Hot Module Reload

Updated instructions for Phoenix 1.1.4 and custom Webpack dev server

Generate your new app without brunch:

$ mix phoenix.new my_app --no-brunch
$ cd my_app

This is file that we want to be able to compile, web/static/js/index.js:

// Phoenix' dependencies
import "../../../deps/phoenix/priv/static/phoenix";
import "../../../deps/phoenix_html/priv/static/phoenix_html";

// Shiny new, hot React component
import React, { Component } from "react";
import { render } from "react-dom";

class Root extends Component {
  render() {
    return <h1>omg so hot</h1>;
  }
}

render(<Root />, document.getElementById("root"));

Install the required js dependencies using npm:

$ echo '{"private": true}' > package.json
$ npm install --save babel-core babel-polyfill babel-loader babel-preset-es2015 babel-preset-react react react-dom webpack
$ npm install --save-dev webpack-dev-middleware webpack-hot-middleware express cors babel-preset-react-hmre babel-preset-stage-0 babel-preset-es2015

A lot of stuff, right?

We need a webpack config. Here’s webpack.config.js:

var path = require("path");
var webpack = require("webpack");
var publicPath = "http://localhost:4001/";

var env = process.env.MIX_ENV || "dev";
var prod = env === "prod";

var entry = "./web/static/js/index.js";
var hot = "webpack-hot-middleware/client?path=" + publicPath + "__webpack_hmr";

var plugins = [
  new webpack.optimize.OccurrenceOrderPlugin(),
  new webpack.NoErrorsPlugin(),
  new webpack.DefinePlugin({
    __PROD: prod,
    __DEV: env === "dev",
  }),
];

if (env === "dev") {
  plugins.push(new webpack.HotModuleReplacementPlugin());
}

module.exports = {
  devtool: prod ? null : "cheap-module-eval-source-map",
  entry: prod ? entry : [hot, entry],
  output: {
    path: path.resolve(__dirname) + "/priv/static/js",
    filename: "index.bundle.js",
    publicPath: publicPath,
  },
  plugins: plugins,
  module: {
    loaders: [
      {
        test: /\.jsx?$/,
        loaders: ["babel"],
        exclude: path.resolve(__dirname, "node_modules"),
      },
    ],
  },
};

And we need a node server for development, webpack.dev.js:

#!/usr/bin/env node
var express = require("express");
var webpack = require("webpack");
var config = require("./webpack.config");

var compiler = webpack(config);
var app = express();
app.use(require("cors")());

app.use(
  require("webpack-dev-middleware")(compiler, {
    noInfo: true,
    publicPath: config.output.publicPath,
  }),
);

app.use(
  require("webpack-hot-middleware")(compiler, {
    log: console.log,
  }),
);

app.listen(4001, "localhost", function (err) {
  if (err) return console.error(err);
  console.log("dev server running on localhost:4001");
});

// Exit on end of STDIN
process.stdin.resume();
process.stdin.on("end", function () {
  process.exit(0);
});

Allow it to be executed:

$ chmod +x webpack.dev.js

Babel 6 needs a .babelrc so let’s add it:

{
  "presets": ["es2015", "react", "stage-0"],
  "env": {
    "development": {
      "presets": ["react-hmre"]
    }
  }
}

Make your app run that script as a watcher in dev. config/dev.exs:

config :speaker, MyApp.Endpoint,
  http: [port: 4000],
  debug_errors: true,
  code_reloader: true,
  check_origin: false,
  watchers: [{Path.expand("webpack.dev.js"), []}]

# ...

config :speaker, MyApp.Endpoint,
  live_reload: [
    patterns: [
      # ~r{priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$},
      ~r{priv/gettext/.*(po)$},
      ~r{web/views/.*(ex)$},
      ~r{web/templates/.*(eex)$}
    ]
  ]

And finally add this to the bottom of web/templates/layout/app.html.eex:

<%= if Mix.env == :dev do %>
  <script src='http://localhost:4001/index.bundle.js'></script>
<% else %>
  <script src="<%= static_path(@conn, "/js/index.bundle.js") %>"></script>
<% end %>

And web/templates/page/index.html.eex is just:

<div id="root"></div>

Building for production

Add lib/mix/tasks/digest.ex:

defmodule Mix.Tasks.MyApp.Digest do
  use Mix.Task

  def run(args) do
    Mix.Shell.IO.cmd "NODE_ENV=production ./node_modules/webpack/bin/webpack.js -p"
    :ok = Mix.Tasks.Phoenix.Digest.run(args)
  end
end

And in mix.exs:

defmodule MyApp.Mixfile do
  # ...
  def project do
    [ # ...
      aliases: ["phoenix.digest": "my_app.digest"]]
  end
  # ...
end

Bookmarklet to control Netflix' playback rate

Who has time to watch ANYTHING at regular speed? Not this guy.

Netflix’ player is just a HTML5 <video> element and those have a playbackRate property.

Thank God for Javascript, right: Use this bookmarklet to control Netflix’ playback rate and never look back.

NetflixSpeed ← Drag this to your bookmarks bar

Upgrading PostgreSQL data from 9.4 to 9.5 with homebrew

I got this in my server.log:

The data directory was initialized by PostgreSQL version 9.4, which is not compatible with this version 9.5.0.

So we have to upgrade our data. Luckily there’s pb_upgrade.

First we need to have a version of 9.4 installed.

# move 9.5 out of the way
# - don't worry - your data will not be removed
$ brew uninstall postgres

# the last version of the postgres bottle with 9.4
$ brew install https://github.com/Homebrew/homebrew/raw/f8509e62904a055f085579aed47fca1faa7a810f/Library/Formula/postgresql.rb

# move 9.4 away but keep it
$ brew unlink postgres

# install 9.5
$ brew install postgres

Now we can follow Keita’s instructions:

# initialize a new 9.5 db
$ initdb /usr/local/var/postgres9.5 -E utf8

# upgrade our data
$ pg_upgrade -d /usr/local/var/postgres -D /usr/local/var/postgres9.5 -b /usr/local/Cellar/postgresql/9.4.5_2/bin/ -B /usr/local/Cellar/postgresql/9.5.0/bin/ -v

# move 9.4 data away and the new data into place
$ mv /usr/local/var/postgres /usr/local/var/postgres9.4
$ mv /usr/local/var/postgres9.5 /usr/local/var/postgres

# remove 9.4
$ brew cleanup

And for good measure:

$ gem uninstall pg
$ gem install pg

Recreating DuckDuckGo's "I'm Feeling Lucky" bang method on Google

DuckDuckGo has a slew of bang methods that let you do all sorts of things with your search terms. One of them is just the bang (!) that’ll automatically go to the topmost result. Like Google’s “I’m Feeling Lucky”.

How can we do that on Google aswell? Using dotjs! Long story short, dotjs let’s you write javascript files that run after sites load eg. ~/.js/google.com.js in this instance.

(function (window, document) {
  "use strict";

  console.log("dotjs");

  // Parse the search string to an object
  var params = window.location.search
    .replace(/^\?/, "")
    .split("&")
    .reduce(function (params, kv) {
      kv = kv.split("=");
      params[kv[0]] = kv[1];
      return params;
    }, {});

  // See if the ?q param contains a bang
  if (params.q.match(/\!/)) {
    // Click the topmost result
    document.querySelector("h3.r a").click();
  }
})(window, document);

El Capitan GM update notes

UPDATE 2015-10-11: Turns out, on a clean install /usr/local is still writable – even with SIP turned on.


I’ve been running the beta of OS X 10.11 El Capitan for some months and there’ve been very few hiccups. So full sail ahead on the update I say.

Upgrading to the GM broke my homebrew though. I think the days of using /usr/local might be over as El Capitan does some stuff to enforce even stricter permissions than a simple chown can get rid of.

So I’m moving out! Someone (forgot who or where – sorry!) mentioned in a Github issue thread how he’d been running his homebrew out of /Users/Shared/Developer for some months with no problems, so that’s what I did:

Installing Homebrew outside of /usr/local

$ git clone https://github.com/Homebrew/homebrew.git /Users/Shared/Developer

Now, that directory’s bin directory isn’t in your $PATH (like /usr/local/bin is automatically) so we need to add it. Open up ~/.bashrc or ~/.zshrc – whatever your preference – and add this:

export BREW_PATH=/Users/Shared/Developer
export PATH="$BREW_PATH/bin:$PATH"

Done. Run brew doctor to confirm.

Install taglib-ruby gem with Homebrew outside /usr/local

$ brew install taglib
$ gem install taglib-ruby -- --with-tag-dir=$BREW_PATH/Cellar/taglib/1.9.1/

Use webpack-dev-server and react-hot-loader with Phoenix

NB: Here’s an updated setup.

Phoenix has built-in livereload and it works right out of the box. But if you’ve ever had the joy of working with React and react-hot-loader you know you need to have that with you anywhere.

Phoenix uses Brunch to build it’s assets so we’ll have to pull that out and jam in a webpack-dev-server wherever it was. Luckily that’s quite easy.

The completed example is available on Github.

First, let’s create a new app:

$ mix phoenix.new my_app
$ cd my_app

We could’ve generated the app without Brunch but let’s keep it in, to see what we’re actually substituting. Let’s start by pulling out Brunch and it’s dependencies and then add our new ones:

$ npm uninstall --save babel-brunch brunch clean-css-brunch css-brunch javascript-brunch sass-brunch uglify-js-brunch
$ npm install --save babel-loader react react-hot-loader webpack webpack-dev-server

Now, webpack needs to be told what to build and how, so let’s make a config file. Here’s webpack.config.js:

var path = require("path");
var webpack = require("webpack");

var env = process.env.MIX_ENV || "dev";
var prod = env === "prod";

var entry = "./web/static/js/bundle.js";
var plugins = [new webpack.NoErrorsPlugin()];
var loaders = ["babel"];
var publicPath = "http://localhost:4001/";

if (prod) {
  plugins.push(new webpack.optimize.UglifyJsPlugin());
} else {
  plugins.push(new webpack.HotModuleReplacementPlugin());
  loaders.unshift("react-hot");
}

module.exports = {
  devtool: prod ? null : "eval-sourcemaps",
  entry: prod
    ? entry
    : [
        "webpack-dev-server/client?" + publicPath,
        "webpack/hot/only-dev-server",
        entry,
      ],
  output: {
    path: path.join(__dirname, "./priv/static/js"),
    filename: "bundle.js",
    publicPath: publicPath,
  },
  plugins: plugins,
  module: {
    loaders: [{ test: /\.jsx?/, loaders: loaders, exclude: /node_modules/ }],
  },
};

I will not go into too much detail but notice the address http://localhost:4001. That’s where webpack-dev-server will be running from when we’re developing.

Next, let’s set up the dev server in webpack.devserver.js:

#!/usr/bin/env node
var webpack = require("webpack");
var WebpackDevServer = require("webpack-dev-server");
var config = require("./webpack.config");

new WebpackDevServer(webpack(config), {
  contentBase: "http://localhost:4001",
  publicPath: config.output.publicPath,
  hot: true,
}).listen(4001, "0.0.0.0", function (err, result) {
  if (err) console.error(err);
  console.log("webpack-dev-server running on port 4001");
});

// Exit on end of STDIN
process.stdin.resume();
process.stdin.on("end", function () {
  process.exit(0);
});

That last last bit is there to make the process shut down properly when Phoenix shuts down. (A big thank you to josevalim for guiding me in figuring that out, for being such a seemingly nice guy and of course for making Elixir!)

Don’t forget to make it executable:

$ chmod +x webpack.devserver.js

We need to tell Phoenix to run this instead of Brunch, so open up config/dev.exs and the change watchers: line to include our dev server instead:

config :my_app, MyApp.Endpoint,
  http: [port: 4000],
  debug_errors: true,
  code_reloader: true,
  cache_static_lookup: false,
  watchers: [{Path.expand("webpack.devserver.js"), []}]

And let’s just cut Phoenix some slack and tell it not to watch the assets:

config :my_app, MyApp.Endpoint,
  live_reload: [
    patterns: [
      # ~r{priv/static/.*(js|css|png|jpeg|jpg|gif)$},
      ~r{web/views/.*(ex)$},
      ~r{web/templates/.*(eex)$}
    ]
  ]

OK, let’s make our entry file, web/static/js/bundle.js:

import React from "react";
import App from "./App";

React.render(<App />, document.getElementById("root"));

This renders our App (that we haven’t made yet) to an element with the id root (that we also haven’t made yet). Splitting your React components into separate files let’s react-hot-loader reload them independently from each other.

Here’s a simple web/static/js/App.js:

import React, { Component } from "react";

export default class App extends Component {
  render() {
    return (
      <div>
        <h1>This app is hot!</h1>
      </div>
    );
  }
}

So far, so good. Now we just need some html document to render it in.

Edit web/templates/layout/app.html.eex:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="">
    <title>Hello Phoenix!</title>
  </head>
  <body>
    <%= @inner %>
    <%= if Mix.env == :dev do %>
      <script src='http://localhost:4001/bundle.js'></script>
    <% else %>
      <script src="<%= static_path(@conn, "/js/bundle.js") %>"></script>
    <% end %>
  </body>
</html>

Remember that our dev server is running on :4001. We want to use it’s bundle.js in dev and a built one in production.

The only thing left is the element with id root. Let’s put it in web/templates/pages/index.html.eex:

<div id="root"></div>

And we’re done! Now go open http://localhost:4000, edit App.js and behold the magic of our hot reloading gods!

Addendum: Production

Phoenix compiles all it’s assets with the task phoenix.digest which you’re supposed to run before deploying. We can just remember to run webpack beforehand — or we can make our own digest task.

Here’s lib/mix/tasks/digest.ex:

defmodule Mix.Tasks.MyApp.Digest do
  use Mix.Task

  def run(args) do
    Mix.Shell.IO.cmd "./node_modules/webpack/bin/webpack.js"
    :ok = Mix.Tasks.Phoenix.Digest.run(args)
  end
end

Let’s be fancy and override the original task so new developers or deployment scripts don’t need to know about our special setup. Open mix.exs and alias the original to our new task:

defmodule MyApp.Mixfile do
  # ...
  def project do
    [ # ...
      aliases: ["phoenix.digest": "my_app.digest"]]
  end
  # ...
end

Try mix phoenix.digest and see that webpack runs first.

Force-update text shortcuts in OS X Yosemite

My text shortcuts never synced when I recently set up my new Macbook and so I was left inserting all my emojis using ctrl+space and using my mouse like you would if you weren’t communicating primarily by thumbs-up emoji like me 👍🏼

So, to force a refresh:

  1. Turn off iCloud Drive
  2. rm -rf ~Library/Mobile Documents/com~apple~TextInput
  3. Turn iCloud Drive back on

Open every link in Safari's Reading List in tabs

Use Safari’s Reading List as an inbox.

When you come across some link or page that you would like to look into at some point just not right now, hit cmd+shift+d on your mac or use the share sheet available almost everywhere on your iOS device and add it to Reading List.

Then when the time is right explode that thing into separate tabs and purge through them.

#!/usr/bin/env ruby
# $ gem install CFPropertyList
require 'cfpropertylist'

path = File.expand_path '~/Library/Safari/Bookmarks.plist'
plist = CFPropertyList::List.new file: path

list = plist.value.value["Children"].value.select do |item|
  if title = item.value["Title"]
    title.value == 'com.apple.ReadingList'
  end
end.first.value["Children"].value

bookmarks = list.map do |item|
  item.value["URLString"].value
end.reverse

puts "Opening #{bookmarks.count} tabs "

bookmarks.each do |url|
  `osascript -e 'tell application "Safari" to tell window 1 to make new tab with properties {URL:"#{url}"}'`
  print '.'
end

puts ''

Clear all items in Reading List and just re-add any linkif you’re still undecided about it.

The script also works perfectly inside Run Shell Script in Automator if you want a .app.

foundation-grid

For years I’ve been using ZURB’s Foundation as a starting point for new sites. It’s really great — but also kind of huge. And the internals are very advanced so picking out parts isn’t as easy as it probably could be. But here’s the grid for your blocky pleasure:

screenshot

Get it: foundation-grid