Hardscrabble 🍫

By Maxwell Jacobson

See also: the archives and an RSS feed

todo_lint: a new ruby gem to help prevent comments from stagnating

July 8, 2015

I made another gem! Here it is: https://github.com/maxjacobson/todo_lint

Last week, I wrote about required_arg, my new gem for adding required keyword arguments to Ruby 2.0.0. I actually made that, quickly, while making this one, which took several hours longer.

What does it do?

It analyzes your code and warns you about TODO comments. You can run the script automatically as part of your continuous integration (CI) build process, and it will fail your build if your TODOs are troublesome. It suggests a workflow whereby your TODO comments must be annotated with a due date, and that due date must be in the future. So you can write little notes to self in your code, but you cannot forget them, because one day your build will start failing. At that point, you can do what you’ll do; maybe you’ll snooze the todo due date into the future; maybe you’ll pull the idea out into your feature/ bug tracker; maybe you’ll just delete it in acknowledgment that you’re never gonna do it. Up to you.

It’s going to be very annoying, and hopefully that will be a good thing.

Adding it to a Ruby project is pretty simple. Here’s what it looks like to add it to a gem: https://github.com/maxjacobson/film_snob/pull/85

At work, I’m coordinating a gaggle of interns working on a new project, and I asked them to be guinea pigs for me and include this gem in their project and CI workflow. They obliged, but unfortunately it immediately didn’t work at all. I didn’t realize it, but our CI service was bundling all dependencies into the same folder as the app, and then todo_lint was checking every file from every Ruby dependency for todos. We don’t want to check all those files, because they’re out of our control. I realized we would need some kind of configuration to allow excluding by folder or maybe even pattern, so I jotted it down in a GitHub issue and told the intern to forget about it; the guinea pig was dead!

Or … was it? Awesomely, she took the time to make a pull request to todo_lint, making it user-configurable; specifically, users can now exclude file patterns like vendor/**. Excellent! The guinea pig lives.

If you’d like to help improve the project, take a look at the remaining open issues and feel free to claim one or add your own. I want my projects to be friendly toward contributors. Awesomely, bundler now suggests including a code of conduct when you create a skeleton gem with, eg, bundle gem todo_lint, and I’ll do my best to uphold that.

Join me in being a scold. It’s fun.

required keyword arguments in Ruby 2.0.0

June 29, 2015

TLDR: I made a gem, required_arg which offers a workflow for requiring keyword arguments in Ruby 2.0.0, which doesn’t support them on the language level.

In March, we looked at Ruby keyword arguments, and noted a curious tension.

Sometimes you want to use keyword arguments, and you don’t want to come up with a default value for that keyword. You kind of want to require the keyword. You can in Ruby 2.1+, but Ruby 2.0.0 is in the awkward position of having keyword arguments but not being able to require them.

Here’s what you can do in Ruby 2.1:

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

Dog.new(name: "Milo") #=> #<Dog:0x007fc404df9f10 @name="Milo">
Dog.new #=> an exception is raised: ArgumentError: missing keyword: name

That’s great! You don’t need to write any additional code, and Ruby will enforce that your method is called with the keyword arguments you require. This gives you flexibility to design interfaces which take advantage of the flexibility and clarity of keyword arguments, but still establish some expectations for how the method will be called.

Here’s what happens when you do the same in Ruby 2.0.0:

class Dog
  def initialize(name:)
    @name = name
  end
end
# dog.rb:2: syntax error, unexpected ')'
# dog.rb:5: syntax error, unexpected keyword_end, expecting end-of-input

Syntax error!

Here’s what I suggest doing now:

  1. Upgrade to a newer version of Ruby
  2. If you can’t, try this:
# gem install required_arg
require "required_arg"

class Dog
  def initialize(name: RequiredArg.new(:name))
    @name = name
  end
end
Dog.new(name: "Milo") #=> #<Dog:0x007fc404df9f10 @name="Milo">
Dog.new #=> an exception is raised: missing keyword: name (ArgumentError)

Close enough!

If your app is stuck on Ruby 2.0.0 or you’re making a library which supports Ruby 2.0.0, maybe you’ll find this useful. Let me know if you do.

Here’s the entire source for the gem:

class RequiredArg
  def initialize(name = nil)
    msg = name.nil? ? "missing keyword" : "missing keyword: #{name}"
    raise ArgumentError, msg
  end
end

Pretty simple, and kind of fun. It’s just a little cherry bomb class. The moment you instantiate it, it blows up. Make it the default value for a keyword argument, and the moment you forget a keyword argument, the default will be used and the expression will be evaluated for the first time. It’s cool that the default values are lazily evaluated because it allows for things like this.

Check out the gem: https://github.com/maxjacobson/required_arg

assigning values to multiple variables in one line

June 27, 2015

Why would you write this:

a = 1
b = 1

When you could write:

a = b = 1

A few reasons:

  1. Maybe you don’t know about this syntax
  2. Maybe you don’t mind writing out two lines
  3. Maybe you’re concerned about having two references to the same data, as explained in this StackOverflow post

I recently saw code that looked like this, which was disabling some loggers:

Something.logger = OtherThing.logger = nil

And I was kind of confused and amazed. I know about this multiple assigning syntax, but this looked kind of different. In the earlier example, we were assigning a value to a simple local variable, but in this case we were calling a setter method instead.

Something like:

class Dog
  attr_reader :name, :family

  def initialize(name)
    @name = name
  end

  def family=(family_name)
    @family = family_name
  end
end

milo = Dog.new("Milo")
lola = Dog.new("Lola")

milo.family = lola.family = "The Jacobsons"
p [milo, lola]
# [#<Dog:0x007faf6115b158 @name="Milo", @family="The Jacobsons">, #<Dog:0x007faf6115b108 @name="Lola", @family="The Jacobsons">]

This works because Ruby gives you this syntactic sugar when you write a something= method, it lets you put a space before the = when calling the method. And that applies in this context too. Kind of neat.

order of operations

June 16, 2015

Last month, we looked at Ruby operators, and I complained about how I wish I could define my own operators. Today I’m looking at them a little more, and thinking about how Ruby handles expressions made up of multiple operations.

Let’s say you have this Ruby code:

sum = a + b + c

What are a, b, and c? They could be

  1. variables containing numbers; that’s what they kind of look like they want to be
  2. invocations of methods which return numbers
  3. variables or methods that contain/return absolutely anything else; let’s not worry about this
  4. maybe they’re not even defined at all; let’s not worry about this possibility either

Let’s look at how option 1 plays out:

a = 1
b = 1
c = 1
puts a + b + c
# 3

So far, so good.

Let’s see how option 2 plays out:

def a; 1; end
def b; 1; end
def c; 1; end
puts a + b + c
# 3

Sort of funky-looking, but also sort of straight-forward. Here’s the question though: if Ruby is calling those 3 methods to get those 3 values, what order are they being called in? Let’s find out:

def a
  puts "a"
  1
end

def b
  puts "b"
  1
end

def c
  puts "c"
  1
end

puts a + b + c
# a
# b
# c
# 3

It kind of makes sense. It’s just going from left to right, like English.

One cool thing about Ruby is that (almost) everything is an object, and even core things like math operations are implemented as methods. This means the above could be written like this:

puts a.+(b).+(c)
# a
# b
# c
# 3

This rendition makes it clear that this is a chained sequence of method calls. Let’s make it even more clear, by refining the plus method and adding some logging:

module MathLogger
  refine Fixnum do
    alias_method :original_plus, :+

    def +(other)
      original_plus(other).tap do |sum|
        puts "#{self} + #{other} = #{sum}"
      end
    end
  end
end

using MathLogger

def a
  puts "a"
  1
end

def b
  puts "b"
  1
end

def c
  puts "c"
  1
end

puts a.+(b).+(c)
# a
# b
# 1 + 1 = 2
# c
# 2 + 1 = 3
# 3

Now it’s not as simple as “left to right”. We start at the left and call the a method. But the next method we call is b, not +. Before we can add two values, we need to know what the values are, and Ruby will evaluate the expression in parentheses (here it’s calling a method, but it could be calling multiple methods and they would all be evaluated before the + method is called).


A brief digression about defined?

This rule doesn’t apply to the defined? method, which ships with Ruby and behaves like this:

msg = "Hello"
defined?(msg) #=> "local-variable"
OMG           #=> NameError: uninitialized constant OMG
defined?(OMG) #=> nil
OMG = 4
defined?(OMG) #=> "constant"

The third line of this excerpt demonstrates that referencing an uninitialized constant normally raises a name error, so it would be normal to expect the same to happen on the fourth line, because we just saw that Ruby normally evaluates the arguments to a method. Here it just totally doesn’t, which feels kind of weird and inconsistent. It might be helpful to think of defined? as a language keyword and not a method. See also the alias method.


Back to math. Remember PEMDAS? When evaluating an arithmetic expression, we’re not supposed to just read from left to right, evaluating operations as we go; we’re supposed to prioritize some operations above others:

  • Parentheses
  • Exponents
  • Multiplication
  • Division
  • Addition
  • Subtraction

With this acronym memorized, children are able to evaluate complicated math expressions.

Can Ruby? Let’s see:

4 + 3 * 5   #=> 19

Well… yeah! Seems right! But let’s take a look into the order that methods are being called:

module MathLogger
  refine Fixnum do
    alias_method :original_plus, :+
    alias_method :original_times, :*

    def +(other)
      original_plus(other).tap do |sum|
        puts "#{self} + #{other} = #{sum}"
      end
    end

    def *(other)
      original_times(other).tap do |product|
        puts "#{self} * #{other} = #{product}"
      end
    end
  end
end


using MathLogger

def four
  puts 4
  4
end

def three
  puts 3
  3
end

def five
  puts 5
  5
end

puts four + three * five
# 4
# 3
# 5
# 3 * 5 = 15
# 4 + 15 = 19
# 19

Interesting! So, Ruby takes a look at four, takes a look at three, and then skips the addition, then takes a look at five, and performs the multiplication. Only then does it double back and perform the addition, inlining the product of three and five.

That’s great! And surely, if all of these operations are just methods, it will behave the same when I change it to this?

puts four.+(three).*(five)
# 4
# 3
# 4 + 3 = 7
# 5
# 7 * 5 = 35
# 35

Hm, nope. When we call the methods directly, the order of operations breaks.

I always thought it was just “syntactic sugar” that I could omit the dot when calling the + method (and its siblings) but it’s doing slightly more than just inlining the dots: it’s also, more or less, inlining the parentheses, so it looks something like this:

puts four.+(three.*(five))

How does it choose where to put the parentheses? It has a precedence table which Ruby references when deciding which operations to evaluate before others. This means that if I were able to define my own operators, I would need to be able to insert them somewhere in this hierarchy, and this hierarchy would also be cluttered with all the operators added by the gems included in my project.

Naturally, my operator would be at the top of the list.

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)