Hardscrabble 🍫

By Max Jacobson

See also: the archives and an RSS feed

designing your own extendible command line utility

June 10, 2015

I like that you or I can write command line utilities in any language, name it git-butterfly, or whatever you want, and then run it as though it were an official part of the git tool, as git butterfly.

It feels a lot like magic, but it’s actually not that complicated a thing to do. If you don’t believe me, watch this video or skip after it to the code, and make your own extendible utility, pig.

If you want your own pig command line utility, copy this code to an executable file on your $PATH called pig. Then, try running pig. Try running pig oink.

#!/usr/bin/env sh

subcommand=$1
bin="pig-$subcommand"
paths="${PATH//:/$'\n'}"

if [[ -z $subcommand ]]; then
  echo "Gimme a subcommand"
  exit 1
fi

for path in $paths; do
  pathToBin="$path/$bin"
  if [ -f $pathToBin ]; then
    $pathToBin
    exit 0
  fi
done

echo "$bin is not a pig command"
exit 1

gemfiles are ruby files

June 2, 2015

A while back I saw this cool blog post: Stay up to date with the latest github pages gem by Parker Moore, who maintains Jekyll. Jekyll is the static site tool that powers github pages, but github pages doesn’t necessarily use the latest version of Jekyll. If you’re deploying your website to github pages, you probably want to make sure your local Jekyll server behaves in the same way as the Jekyll that runs on github pages.

A Jekyll site is a Ruby project, and Ruby projects should have a Gemfile listing their dependencies. Jekyll is a gem, so you might think that you should add this to your Gemfile:

gem 'jekyll'

But actually, maybe not!

Consider this intsead:

gem 'github-pages'

This includes the exact version of Jekyll that github pages is using (and a few other things).

That’s great, because you know you can preview your website locally and know that it will look the same when you deploy it to GitHub pages.

You may be asking: what about when they upgrade the version of Jekyll they’re using to compile your site?? Well, they release a new version of the github-pages gem, which bumps its Jekyll dependency. So, ideally, before pushing to your Jekyll site on github pages, you should know that you’re using the latest version of the github pages gem.

Here’s how you can do that (so far I’m just summarizing that Parker Moore blog post):

require 'json'
require 'open-uri'
versions = JSON.parse(open('https://pages.github.com/versions.json').read)
gem 'github-pages', versions['github-pages']

Isn’t that cool? Now, when you start your local server with bundle exec jekyll serve, it will confirm that you have the appropriate version of github pages.

Happy ending? Sort of.

I did that a few months ago, and was happy for those months. Then, last weekend, I found myself somewhere without internet access and a blog post idea, but was sad to see that I was unable to run my local blog server because my Gemfile was unable to connect to the internet to confirm it had the latest dependencies.

When you’re without internet access, you can’t push changes to your blog anyway, so there’s not really any danger of seeing an offline preview of what the site looks like without confirming you have the latest versions of everything.

Now my Gemfile looks like this:

begin
  require 'json'
  require 'open-uri'
  versions = JSON.parse(open('https://pages.github.com/versions.json').read)
  gem 'github-pages', versions['github-pages']
rescue SocketError
  gem 'github-pages'
end

Nice! When the network request fails, a SocketError is raised, so we’re able to rescue that error and fallback to any old version of the gem. This might still fail; it assumes that we’ve previously successfully installed a version of the gem to fall back to, and that version is cached locally by bundler.

It’s neat that we’re able to use whatever Ruby we want to in our Gemfile, but kind of non-obvious because it doesn’t end with .rb. Well, what if it was just called something else? Turns out you can rename your Gemfile to gems.rb, and your Gemfile.lock to gems.locked since Bundler 1.8.0, and this will be the new normal in Bundler 2.0.

Neat! Now my Gemfile looks like the above, but it’s now my gems.rb file.

operators as self expression

May 26, 2015

EDIT June: I’ve followed-up this post: order of operations

NOTE: this post seems to have a ton of code samples, but it’s pretty much just the same one over and over with some small variations to play with an idea.

Suppose you were writing a program to help you write a novel, and you start out with something like this:

class Novel
  def initialize(title)
    @title = title
    @chapters = []
  end
end

class Chapter
  def initialize(text)
    @text = text
  end
end

moby_dick = Novel.new("Moby Dick")
first_chapter = Chapter.new("Call me Ishmael...")

After you write this, you pause, because how are you going to define the interface for adding a new chapter to a novel?

Something like this works fine:

class Novel
  def initialize(title)
    @title = title
    @chapters = []
  end

  def add_chapter(chapter)
    chapters << chapter
  end

  private

  attr_reader :chapters
end

class Chapter
  def initialize(text)
    @text = text
  end
end

moby_dick = Novel.new("Moby Dick")
moby_dick.add_chapter Chapter.new("Call me Ishmael...")
moby_dick #=> #<Novel:0x007fdabc81c1f0 @title="Moby Dick", @chapters=[#<Chapter:0x007fdabc81c178 @text="Call me Ishmael...">]>

Writing methods is good, and that method has a perfectly adequate name. But some clever ducks will be dissatisfied by it, because they know there’s a more fun, or maybe a more expressive way:

class Novel
  def initialize(title)
    @title = title
    @chapters = []
  end

  def <<(chapter)
    chapters << chapter
  end

  private

  attr_reader :chapters
end

class Chapter
  def initialize(text)
    @text = text
  end
end

moby_dick = Novel.new("Moby Dick")
moby_dick << Chapter.new("Call me Ishmael...")
moby_dick #=> #<Novel:0x007fdabc81c1f0 @title="Moby Dick", @chapters=[#<Chapter:0x007fdabc81c178 @text="Call me Ishmael...">]>

The << “shovel” operator is familiar to most Ruby programmers, and chapters are a natural thing to shovel into a novel, so it feels kind of natural to use it here.

<< is the idiomatic operator to use, but sometimes I don’t want to be idiomatic, I want to be weird. Maybe I feel like this version suits me better:

class Novel
  def initialize(title)
    @title = title
    @chapters = []
  end

  def <=(chapter)
    chapters << chapter
  end

  private

  attr_reader :chapters
end

class Chapter
  def initialize(text)
    @text = text
  end
end

moby_dick = Novel.new("Moby Dick")
moby_dick <= Chapter.new("Call me Ishmael...")
moby_dick #=> #<Novel:0x007fdabc81c1f0 @title="Moby Dick", @chapters=[#<Chapter:0x007fdabc81c178 @text="Call me Ishmael...">]>

For me, <= is a more visually stimulating, writerly operator.

I probably shouldn’t do this. It’s a totally weird interface! <= means “less than or equal to”, not append..!

In fact, I’m only allowed to even do that because <= is on a list of acceptable operators1. You can’t just name your operator whatever. Let’s try:

class Novel
  def initialize(title)
    @title = title
    @chapters = []
  end

  def ✏️(chapter)
    chapters << chapter
  end

  private

  attr_reader :chapters
end

class Chapter
  def initialize(text)
    @text = text
  end
end

moby_dick = Novel.new("Moby Dick")
moby_dick ✏️ Chapter.new("Call me Ishmael...") #=> undefined method `✏️' for main:Object (NoMethodError)

It totally blows up. This works, though:

moby_dick = Novel.new("Moby Dick")
moby_dick.✏️ Chapter.new("Call me Ishmael...")
moby_dick #=> #<Novel:0x007fdabc81c1f0 @title="Moby Dick", @chapters=[#<Chapter:0x007fdabc81c178 @text="Call me Ishmael...">]>

Surprisingly, this does too:

moby_dick = Novel.new("Moby Dick")
moby_dick . ✏️ Chapter.new("Call me Ishmael...")
moby_dick #=> #<Novel:0x007fdabc81c1f0 @title="Moby Dick", @chapters=[#<Chapter:0x007fdabc81c178 @text="Call me Ishmael...">]>

There are so many spaces on that second line, but it totally works.

It sucks that the period is necessary for this to be syntactically valid. I think. I don’t know what the consequences would be of allowing programmers to define arbitrary operators. Maybe they’re vast?

  1. here’s a stack overflow post about which operators are overloadable. It may not be up-to-date with Ruby 2, though, so overload at your own risk. 

time zones are still the worst

April 25, 2015

After publishing my last post, a few minutes ago, I of course triggered refreshes until the reminder ticked down to “0 days and 0 hours”, but… it didn’t work.

Instead, I saw: “0 days and 4 hours”. What the hell?

My first instinct was to blame the script and feel a little embarrassed for sharing a faulty script.

After a little digging, I realized it was worse than that: it was actually my RSS feed that was faulty! This commit fixed the problem: 642cd54.

Because I wasn’t supplying a time zone in the metadata for the post, Jekyll (my blog generator) had to make an assumption, and it assumed UTC, which is currently 4 hours ahead of New York, from where this blog emanates, and from where I anxiously remind myself to update it.

By stating that I was publishing a post at 15:53 UTC as opposed to 15:53 EDT, I was effectively backdating it, which makes it sort earlier in RSS feeds. One of my favorite blogs, The Setup, doesn’t supply times at all, only dates, so whenever a new interview arrives, it arrives buried below all of the day’s posts, which I find mildly inconvenient. It pains me to know I’ve caused something of the same, and I apologize.

But at least the script is fine!

my new menu bar guilt trip

April 25, 2015

I just discovered TextBar via this article and it’s a pretty sweet Mac app.

You provide it a script and an interval, and it runs the script over and over, and prints the result to your Mac menu bar.

It comes with a few neat starter scripts which tell you things like how full your disk is and which wifi network you’re attached to.

For some reason, my instinct was to make a script that told me how long it’s been since I updated this blog.

I tried writing it as a shell script but gave up halfway through and switched to Ruby because, as much as I enjoy a challenge, parsing dates with the Mac date utility was making me sad.

#!/bin/sh

function latestPost {
  local xml=$(curl http://www.hardscrabble.net/feed.xml 2>/dev/null)
  echo $xml > /tmp/feed.xml
  local lastPost=$(xmllint /tmp/feed.xml --xpath "//item[1]/pubDate/text()")
  echo $lastPost | ruby -rdate -e "
    def pluralize(number, word)
      %{#{number} #{word}#{'s' unless number == 1}}
    end
    diff = (DateTime.now - DateTime.parse(STDIN.read)).to_f
    days = diff.to_i
    hours = ((diff * 24) % 24).round
    STDOUT.write %{#{pluralize days, 'day'} and #{pluralize hours, 'hour'}}"
}

latestPost

This is kind of a Frankenstein script (it even has a little Rails in it) but it works so 🤵🏻‍♂️.

To use it with TextBar, I put this in a file and made it executable, and then just referenced the path to the file as the “Script”:

TextBar UI screenshot

I’m having it refresh hourly, because the script is only specific to the nearest hour, so it’ll always be more-or-less right.

Here’s what my menu bar currently looks like:

menubar screenshot

(Tweetbot, this script via textbar, postgres, 1password, dropbox with some notification?, google drive, alfred, caffeine, and then some native Mac stuff)

How to easily post to your Jekyll blog from your iPhone or iPad

April 3, 2015

Caveats:

  • This solution doesn’t support Octopress, only Jekyll
  • This solution assumes you’re hosting your blog on GitHub

Steps

  • One-time setup
    • Download Editorial
    • Install the Publish Jekyll Post workflow I’ve just created
    • Tap the wrench to see the list of workflows
    • Find the newly installed “Publish Jekyll Post” workflow
    • We need to configure the workflow with your info. Try running it, and it will complain that you haven’t provided a GitHub API access token. It will offer to open Safari on the page where you can create a new access token. Do that, and copy it to your clipboard. Note: the only necessary permission is “public_repo”, assuming your repo is public, which it almost certainly is. You can revoke this token at any time to cut off the workflow.
    • Return to Editorial
    • Tap the “i” info button for the workflow
    • Tap “Edit Workflow”
    • Find the step called “Configure Access Token” and tap to expand it. There’s a text box there where you can paste in your access token.
    • Scroll down to the “Configure Repo” step and tap to expand that one as well. There, write in your GitHub username and the name of the repo you’d like to add posts to.
  • Now that configuration is done, just create a new document in Editorial and write your post. You are responsible for providing the YAML front matter (the block at the top with the title and date)
  • Run the workflow.
    • You will be asked what the file name should be. The workflow makes a smart guess: _posts/2015-04-02-whatever-the-file-name-is.md, but you can change it.
    • You will be asked what the commit message should be.
    • The workflow will then create the file in your repo and, upon success, offer to open that file on GitHub.

If you have any problems or ideas, please open an issue on the project’s GitHub repo: https://github.com/maxjacobson/github-pages-editorial (I deleted the repo)

analytics

April 2, 2015

A few months ago I installed Google Analytics on hardscrabble, and a few weeks ago I installed Clicky, a competing service.

I felt a little skeezy, a little Not Punk, when I did that.

Aren’t I supposed to not care what people think and write from the heart?

Well, to be honest, I do. I check the stats sometimes. And I’m letting it affect what I do and write.

But hopefully in a good way!

For example: I learned, much to be my surprise, that this is consistently my most popular post. It’s not a mega hit or anything, but it gets a few visits every day. People want a good solution to that particular problem, and there aren’t that many solutions at all.

Unfortunately, my solution from January 2014 is pretty bad. I feel bad for those people. I want to help them. Maybe analytics can tell me who on this Earth I can help, and maybe that’s beautiful.

Anyway, I’m writing this on Editorial on my iPad (with a bluetooth keyboard; I’m not crazy), and I’m about to publish it using a MUCH IMPROVED, lighter-weight workflow. I want to battle-test it a little bit more before I share it. Maybe this won’t even

ruby keyword arguments aren't obvious

March 29, 2015

Since Ruby 2.0, methods can be defined with keyword arguments instead of the traditional ordinal arguments. I really like them. But they’re not obvious. I find myself thinking, maybe too often, “wait, how the hell do these work?”

This post is a stream of consciousness exploration through the things about keyword arguments that confuse or confused me or people I know. Wading through this post might help you emerge with a firmer understanding of how to use them. I hope it makes sense if you read it. Please let me know. I want to write about a thing I find confusing in a way that honors that confusion but is also clear and readable, which maybe isn’t a thing I can do.

Let’s start with an example of keyword arguments working as-advertised:

def email(from:, to:, subject:, body:)
  "From: #{from}\nTo: #{to}\nSubject: #{subject}\n\n#{body}"
end

That’s a kind of strange method that takes a few required keyword arguments and makes a string from them. I like using keyword arguments here because now you can call the method however you like, as long as you provide all of the keywords; the order doesn’t matter, and it’s clear which one is which.

So, for example, here’s a perfectly valid way to call that method (note the order has changed):

email(
  subject: "Thanks!",
  from: "Max",
  to: "Susan",
  body: "The soup was great!"
)

We’re able to use required keyword arguments in Ruby 2.1 and forward. What if your app is using Ruby 2.0.0? You’d still like to reap the clarity benefits of keyword arguments, but now you must provide a default value for every keyword. What default makes sense for an email? I’m not sure. I guess you can do this?

def email(from: nil, to: nil, subject: nil, body: nil)
  raise ArgumentError if [from, to, subject, body].any?(&:nil?)
  "From: #{from}\nTo: #{to}\nSubject: #{subject}\n\n#{body}"
end

Which kind of simulates the behavior of Ruby 2.1 required keyword arguments. But it’s not great, because sometimes nil is actually a value that you want to be providing. So maybe you do something heavier, like this?

class AbsentArgument
end

def email(from: AbsentArgument.new, to: AbsentArgument.new, subject: AbsentArgument.new, body: AbsentArgument.new)
  raise ArgumentError if [from, to, subject, body].any? { |arg| arg.is_a?(AbsentArgument) }
  "From: #{from}\nTo: #{to}\nSubject: #{subject}\n\n#{body}"
end

Which is kind of clunky-looking but maybe more explicit?

Let’s be happy required keyword arguments are an official thing now and not worry about that and just hope we can all always use Ruby 2.1 or newer.

Keyword arguments kind of look like hashes. Are they hashes? I don’t know. You can use hashes with them:

arguments = {
  from: "Max",
  to: "Beth",
  subject: "Thanks!",
  body: "Your soup was great!"
}
email(**arguments)

That works. That ** coerces the hash into keyword arguments, kind of like the * coerces an array into ordinal arguments:

def sum(a_number, another_number)
  a_number + another_number
end

nums = [1, 1]
sum(*nums)

Except, the ** isn’t actually necessary, this works fine too:

arguments = {
  from: "Max",
  to: "Beth",
  subject: "Thanks!",
  body: "Your soup was great!"
}
email(arguments)

So I guess they don’t do anything there?

OK so when you are calling a method you can use a pre-existing hash for the keyword arguments. What about when you’re defining a method? This probably won’t work but I just don’t know because it doesn’t feel obvious. Let’s try.

Here’s our new example method, which works fine:

def stir_fry(ingredients: [], heat: 100)
  heat.times do
    ingredients = ingredients.shuffle
  end
  ingredients
end

stir_fry(ingredients: ['broccoli', 'peppers', 'tofu'], heat: 45)

So let’s try to define the method again, but this time let’s use a hash.

arguments = {
  ingredients: [],
  heat: 100
}
def stir_fry(arguments)
  heat.times do
    ingredients = ingredients.shuffle
  end
  ingredients
end

stir_fry(ingredients: ['broccoli', 'peppers', 'tofu'], heat: 45)

Do you think it works? It doesn’t work at all. I’m sorry.

Wait, so what even is the ** thing? Let’s review * again; I showed above how to use it to coerce an array into ordinal arguments when calling a method, but it can also be used in a method definition to indicate that a method takes an arbitrary number of arguments:

def sum(*numbers)
  total = 0
  numbers.each { |num| total += num }
  total
end

sum(1, 2, 3)
sum(*[1, 2, 3])

We can do something like that with ** to indicate that we want to catch all unrecognized keyword arguments into an object:

def stir_fry(ingredients: [], heat: 100, **options)
  heat.times do
    ingredients = ingredients.shuffle
  end
  if (sauce = options[:sauce])
    ingredients.push(sauce)
  end
  ingredients
end

stir_fry(ingredients: ['broccoli', 'peppers', 'tofu'], sauce: "teriyaki", heat: 45)

In that example, sauce is an optional keyword that isn’t defined in the method definition. Normally if we provide sauce, and sauce wasn’t specifically expected, that will cause an error, so this is kind of a cool way to say: “I don’t care what keyword values you throw at me! I’ll just make a hash out of the ones I don’t recognize”. It doesn’t even care that sauce came in the middle of the expected keyword arguments. This is pretty similar to the convention in ordinal method definitions where the last argument is called options and it has a default value of an empty hash, but when you do that, the order really matters:

def ordinal_stir_fry(ingredients, heat, options = {})
  heat.times do
    ingredients = ingredients.shuffle
  end
  if (sauce = options[:sauce])
    ingredients.push(sauce)
  end
  ingredients
end

ordinal_stir_fry(["potato"], 5, sauce: 'Catsup') # This one works
ordinal_stir_fry(["shoe"], {sauce: 'Water'}, 5) # This one doesn't

What is even happening there? The curly braces become necessary to avoid a syntax error, and then the method receives the wrong values in the wrong names. But, looking at it, I think it’s clear that something is a little bit off, because the second parameter looks different from the third; it kind of feels like the hash belongs at the end, because that’s such a strong convention for ordinally-defined Ruby methods.

The **options example is neat but again, it’s not obvious. When looking at it, you don’t know which of the keyword arguments are specifically expected and which ones will land in the greedy **options bucket. You have to reference the method definition, just like with stinky ordinal methods.

Let’s look at default values in some more detail. It seems clear; you can provide a default value, which will be used when the method is called without that keyword value provided. What happens when you provide nil?

class Fish
  attr_reader :breed, :color

  def initialize(breed: "Koi", color: "Yellow")
    @breed = breed
    @color = color
  end
end

fish = Fish.new(color: nil)
fish.breed #=> "Koi"
fish.color #=> ????????

What do you feel like it should be? I guess it should be nil, because that’s the value you provided for that keyword, and yes that’s right, it’s nil. That works for me, but I know it’s not obvious because I found myself trying to defend this behavior to a friend recently, who was sad that it didn’t behave as his intuition desired, that a nil value would be replaced by the default value. To console him I attempted to write some code that would satisfy his expectations, and I came up with this:

class AbsentArgument
end

class Fish
  attr_reader :breed, :color

  def initialize(breed: AbsentArgument.new, color: AbsentArgument.new)
    @breed = validate(breed, default: "Koi")
    @color = validate(color, default: "Yellow")
  end

  private

  def validate(value, default:)
    if value.is_a?(AbsentArgument) || value.nil?
      default
    else
      value
    end
  end
end


fish = Fish.new(color: nil)
fish.breed #=> "Koi"
fish.color #=> "Yellow"

So if you want that behavior you basically can’t use Ruby keyword argument default values, because default values don’t work that way.

Oh, here’s another thing. I thing I only realized this this month, that I had been doing this:

class Disease
  attr_reader :name

  def initialize(name: name)
    @name = name
  end
end

gout = Disease.new(name: "Gout")
gout.name #=> "Gout"
rando = Disease.new
gout.name #=> nil

This was fulfilling the behavior I guess I wanted: when I provide a name, it should use that name; when I don’t provide a name, the name should be nil. It was working without error, and I’m not sure where I picked up the pattern of writing keyword arguments this way, but it actually totally makes no sense! If I wanted the default value to be nil, why not just write it like this?

class Disease
  attr_reader :name

  def initialize(name: nil)
    @name = name
  end
end

What was even happening in that earlier example? Well, when I wasn’t providing a name value, it was calling the name method which was only available because I had added the attr_reader for name, and that method was returning nil, so nil was being assigned to the @name instance variable. I had no idea that’s what was happening, I just thought that I was writing the boilerplate necessary to achieve that behavior. That feels kind of dangerous; maybe you don’t realize that your default values can call methods, and you’re calling a method that doesn’t exist? For example:

class Furniture
  attr_reader :color

  def initialize(kind: kind, color: color)
    @kind = kind
    @color = color
  end

  def description
    "#{@color} #{@kind}"
  end
end

couch = Furniture.new(kind: "Couch", color: "Grey")
couch.description #=> "Grey Couch"

You could have tests for this code and ship it to production and never realize that a bug hides within it. As long as you always provide a kind keyword value, you’ll never face it and it will work properly, because it will never attempt to call the kind method… which doesn’t exist.

So, to make it blow up, simply omit the kind keyword value:

Furniture.new(color: "Red")
# undefined local variable or method `kind' for #<Furniture:0x00000101110a38> (NameError)

Sinister!

Happily, I’m noticing now that Ruby 2.2.1 actually warns you when you write code like this. 2.0.0 does not, which is where I’ve been happily making this mistake for many months.

The warning:

def candy(flavor: flavor)
end
# warning: circular argument reference - flavor

What about when you combine ordinal arguments with keyword arguments? You can. Is it obvious how that should work? Not to me. Let’s take a look.

def stir_fry(servings = 1, zest, ingredients: [], **options)
  dish = (ingredients * servings)
  zest.times do
    dish = dish.shuffle
  end
  dish
end

stir_fry(8, ingredients: ["pepper", "seitan"], sauce: "fancy")

What the hell is happening there? Maybe it’s clear to you. it’s not to me. The first two arguments are ordinal, and the first one has a default value. So Ruby compares the arguments we provide when we call the method to the arguments in the method definition, and sees that we provided what looks like one ordinal value, and a few keyword values, so the one ordinal value must be zest, because servings has a default value and zest does not (Ruby here is smarter than I realized).

It kind of feels like Ruby is going to let us make this method definition more confusing, for example by moving the keyword arguments before the ordinal arguments, but it actually won’t let you. It will raise a syntax error:

# syntax error:
def shenanigans(amp: 11, guitar)
end

# if it were a valid method definition, I guess you would call it like this:
shenanigans(amp: 5, "Fender")
# or, omitting the non-required parameter
shenanigans("Martin")

For me it wasn’t obvious that this wouldn’t be allowed, but I’m glad it’s not, because reading those method calls feels kind of backwards.

Similarly:

# not a syntax error:
def shenanigans(amp, *outfits, **options)
end

shenanigans("Orange", "Leotard", "Leather Jacket", at: Time.now)

# but this is a syntax error:
def shenanigans(amp, style: "flamenco", *outfits, **options)
end

That one also fails because it tries to put some ordinal arguments (the *outfits bit) after some keyword arguments.

Well, I think that’s everything I can think of. Good luck out there.

my first vim macro

March 29, 2015

The time has come for me to make a vim macro. Here’s what it looks like in action:

vim macro demo

I made it because I am working on a post that will include a few ruby examples, and I got frustrated typing out Liquid’s verbose syntax for codeblocks (I wish Jekyll supported GitHub-style fenced code blocks). It wasn’t too hard to make it because it’s really simple. I don’t know how to make a smarter one, for example one that puts ruby as the default language, but let’s you start typing immediately to replace it with something else, and then hit tab to jump to the middle (a behavior I’ve seen with snippets in Sublime Text for example).

Here’s what it looks like, straight from my vimrc:

  
    nnoremap hii i```ruby<ESC>o```<ESC>O
  

I’ll translate to English:

When I’m in normal mode, and I type hii, act like I typed the following stuff, which I would’ve done if I had typed it out manually:

  • i to go into insert mode
  • type out the first line’s stuff
  • <ESC>o to exit insert mode, create a newline, go to that new line, and go back to insert mode
  • type out the second line’s stuff
  • <ESC>O to exit insert mode, create a newline above the second line, go to that new line, and go back to insert mode

It’s not much and I’m not even sure I’m using the word macro right but it’s mine.

Edit April 2015: Turns out hii was a pretty bad choice, because it starts with h, which I type all the time in normal mode. It’s the left arrow! Whenever I type h now, it doesn’t immediately move left, it hangs a moment while it waits to see if I really mean just h, or if I’m gonna continue and write hii. So, I’ve changed it from hii to <Leader>hii and now I’m happy again.

Note: the default Leader character is \.

managing your Instapaper bookmarks from the command line

March 22, 2015

I’ve previously written about extracting a gem from a web app called Layabout, but I neglected to mention that I later open sourced Layabout as well:

Today I have the opportunity to write about it, because I finished a kind of fun new feature: a command line interface for efficiently managing your bookmarks. Using it requires cloning the codebase and requesting API credentials, so it’s not a super accessible tool, but for power users it might be worth it. Here’s a quick demo:

bin/rake explore demo

Here’s the code for the CLI as of this moment: https://github.com/maxjacobson/layabout/blob/255eed15be2e55de804083bfdcf8651538af7bb0/lib/tasks/explore.rake

(I like linking to the code as of a certain commit, because who knows, maybe I’ll rename the file later, and then the link to the file on master branch won’t actually work?)

I think it’s kind of interesting code. Each action is an object that describes its help text, the commands it can handle, and how it can handle them.