DigBang: Safely unsafe Ruby hash traversal

Here’s Hash#dig!, a handy little piece of code I wrote for a project. It’s¬†similar to Ruby 2.3’s Hash#dig, but raises an exception instead of returning nil when a key isn’t found.

places = { world: { uk: true } }

places.dig  :world, :uk # true
places.dig! :world, :uk # true

places.dig  :world, :uk, :bvi # nil
places.dig! :world, :uk, :bvi # KeyError:
                              #   Key not found: :bvi

#dig is to #[] as #dig! is to #fetch

Ruby 2.3 introduces the new Hash#dig method for safe extraction of a nested value. It’s the equivalent of a safely repeated Hash#[].

#dig!, on the other hand, is the equivalent of a safely repeated Hash#fetch. It’s “safely unsafe”ūüėČ raising the appropriate KeyError anywhere down the line, or returning the value if it exists. This turns out to be very easy to implement in the functional style:

def dig!(*keys)
  keys.reduce(self) { |a, e| a.fetch(e) }

The full source code

Comparing Kanban apps with GitHub integration

I’m working on this for a client: Comparing Kanban project management apps that have very good GitHub integration. So far I’ve looked at Huboard, Waffle, Zenhub, and Blossom.

Blossom.io is the strongest for our needs due to the detailed cycle time reporting, showing where cards are spending their time. It also has some very useful¬†project management features like marking an issue as “blocked” or “ready” for moving to the next stage.

Screen Shot 2016-01-08 at 12.25.23 AM

Online at Google Docs

Web Framework Comparison Matrix

web framework comparison keyThis is¬†how¬†I evaluate frameworks for clients and my own projects. I’m doing my best to be:

  • opinionated about which features matter
  • unopinionated about the actual frameworks

So you’ll be most likely to find this¬†helpful if you value the same things I do: good CRUD support, good deployment and testing support, and an open and friendly community. Here’s the current matrix, and a link to the spreadsheet online.¬†Help me fill in¬†the remaining items by leaving comments.

web framework comparison matrix 1

web framework comparison matrix 2

I’m thinking about how to preserve the sources and reasoning for each score.

Goodbye “X for Y”: the cryptic Ruby error is becoming friendlier

Anyone who’s used Ruby has seen this message:

r.rb:1:in `name': wrong number of arguments (3 for 2) (ArgumentError)

This particular error has been driving me nuts for years. It’s just so unnecessarily difficult to interpret ‚ÄĒ especially if Ruby’s not the only language you use. I never remember which number is which.

Compare to Python:

TypeError: name() takes exactly 2 arguments (3 given)

This is better in several ways. The unambiguity; the tone (no “wrong”); the lack of line-noise characters; the plain-English sentence. Note also that the numbers are presented in the opposite order from Ruby. Not a problem in itself, but it makes the Ruby equivalent especially hard to interpret because it requires memorizing the difference.

Potentially as soon as Christmas, though, Ruby’s output look will look like this:

r.rb:1:in `name': wrong number of arguments (given 3, expected 2) (ArgumentError)

This is a great step in the right direction.

It turns out that the issue had been raised two years ago. I gave the topic a bump, and Martin D√ľrst quickly commited the improved code. I am incredibly appreciative, and happy to see that core Ruby developers value improvements like these. In fact, there’s an open Request for Comments on improvements to Ruby’s error messages.

Infographic: OS X El Capitan License in Plain English

Shortly after I posted¬†OS X El Capitan License in Plain English, I received an email from Bogdan Rauta, a Romanian infographic designer. He volunteered to create an infographic as part of a new project, Infographic Monster News. His¬†idea is to report current news stories in the form of infographics. I’d say he’s off to a good start:

OS X El Capitan License Infographic

Follow my Patreon project for news about upcoming In Plain English posts.

OS X El Capitan License: in Plain English

I decided to upgrade my Mac to El Capitan, but¬†my computer said,¬†on one condition: I must¬†“carefully” read and agree with something. It¬†even provided a tiny cozy display window for¬†viewing it:

OS X El Capitan License dialog

And so I did what anyone else would: I cleared my afternoon schedule and got right down to business; reading, carefully, the entire document. It turns out that I was much too pessimistic! I needed only 33 minutes.

I should note that I’m an attorney with a good understanding of license, trademark, and copyright law. I’m also a software developer with 20 years’ experience. So your own read-through may take more or less time, accordingly.

I thought it’d be a “fun” project to see what the “El Capitan License” actually says. Cool idea, huh? Kind of like spelunking through a cave that everyone says¬†they’ve been through, but maybe no one really¬†has. What will I find wedged¬†in a¬†wall or¬†lurking in the dark around the next turn?

Update: Now in infographic form!
Update: Now as an infographic!
  1. I¬†can’t use the Capitan with illegal copies of¬†anyone’s stuff.
  2. Apple didn’t sell me this software. They still own it, in fact. I’m just borrowing it.
  3. If I install more Apple software, those are on loan as well.
  4. I can use the Capitan in two virtual Machines, and on one computer.
  5. But these VM’s cannot be used for business. The only exception is for software developers (I guess they wouldn’t follow this rule anyways.)
  6. I’ve got to read the separate rules that came with the fonts, and obey them. (I can only borrow those too.)
  7. Those cool voices for the clock? ‚ÄĒ no remixing!
  8. Slideshows made with Photo; same deal, don’t even think about using them for some commercial purpose.
  9. I can’t sell access to my Mac via any kind of screen sharing.
  10. I gotta run it on Apple hardware (no Hackintoshes).
  11. I can’t help anyone else do that.
  12. I can make one copy as a backup.
  13. I can’t try to figure out the source code to any of this.
  14. I gotta follow all my local laws while I’m using it. (!) (Really?¬†Whereever I live?)
  15. I can leave the software on the Mac if I sell it or give it away.
  16. I better not use anyone else’s hacked version.
  17. Apple isn’t responsible for my hurt feelings for anything I see on the web.
  18. If I break any of these rules, this deal is over and I must immediately delete everything.
  19. The Capitan comes as-is.
  20. I can’t send it to Sudan.
  21. I can’t operate a nuclear power plant with it.
  22. I cannot, don’t even think about it, just plain can’t, make money from¬†MPEG/H.264/AVC videos I create. For¬†that, I need to buy another something from somebody.

There you are. I took one for the team.

UPDATE: Thank you to everyone for the great positive response and encouragement to write more.

git commit –amend: Have Your Cake and Eat it Too

For a lot of us, version control does two things which are contradictory:

  • it keeps¬†checkpoints as we work so we can easily roll back, and
  • wraps up our work into a tidy package for others to use.

git commit --amend is one tool that solves this. It will “open up” the previous commit, adding staged files and allowing you to re-edit the commit message.

  1. Make your “checkpoint” commit, e.g. with a failing spec.
  2. Get your specs working again.
  3. Stage your changes like you normally would using git add.
  4. Instead of git commit, do git commit --amend.
  5. Edit the message to describe the feature. This will be the commit’s new message, and it will contain¬†all the changes.

A related command: git rebase -i¬†¬†(“interactive”). If you didn’t use --amend, you can go¬†back and condense commits together as if you had. With this command, you can interactively rebase, using the “squash” command to combine multiple commits together.

A Benefit of Rails: Surrogate Keys

Today I helped a client wrestle with a database task which concluded:

. . . We’ll have to watch out inventing new “fake” customers because one day there may be a real customer with our made up IDūüė¶

This is a problem in lots of apps, but not in Rails.

Rails enforces the “best practice” of giving every table a¬†primary key named¬†id, which is an auto-incrementing integer. But many non-Rails apps do not do this. Instead, they use some real-world data as the primary key. This is called a natural primary key. E.g., a customer’s social security number. There are arguments for and against this. This is a good little wikipedia page about the differences.

One big problem with natural primary keys is that they often turn out to not be as unique as we think. Plus, then we’re¬†put in the position of “faking” the SS number when we want to manually add customers who don’t have one, e.g. “999-….”. (I remember a college I attended which assigned 999- SS numbers to international students.) And this is the hack that the task description¬†refers to.

In contrast to natural keys, the¬†id¬†field is a so-called surrogate key. It intentionally¬†has no meaning in the real world, and so it has no reason to ever change. It doesn’t matter at all what an object’s id is, just so long as it’s unique. And since it gets set up as an auto-incrementing integer, that will be the case.

So, Rails is “opinionated software” and has made the decision for us. Every table will have;

  1. a surrogate key,
  2. named id,
  3. which is an auto-incrementing integer.

And in one swoop, a whole category of potential problems is eliminated. Secondly, this makes it very easy to get up to speed on a new Rails app.

Self-validating Ruby objects with ActiveModel Validations

I’m importing lots of CSV restaurant inspection data¬†with Ruby, and I need to make sure the cleaned up data matches the spec. For example, a violation must have a business_id and date. It can optionally have a code and description. My goal was to be able to write a class like this:

class Violation < ValidatedObject
  attr_accessor :business_id, :date, :code, :description

  validates :business_id, presence: true
  validates :date, presence: true, type: Date

…and it would just work, Rails-style:

Violation.new do |v|
  v.business_id = '1234'
  v.date = '2015-01-15'
# => ArgumentError: date must be of the class Date

Violation.new do |v|
 v.date = Date.new(2015, 1, 25)
# => ArgumentError: business_id is required

Violation.new do |v|
 v.business_id = '1234'
 v.date = Date.new(2015, 1, 25)
# => new instance Violation<...>

ActiveModel::Validations was refactored out of ActiveRecord to enable just this sort of use case. This is because the awesome list of built-in validations (here and here) and methods like #valid? are useful in a variety of contexts, not just in Rails.

It turned out that it was easy to write a small base class with the ActiveModel::Validations mixin to make the checking automatic upon initialization:

require 'active_model'

class ValidatedObject
  include ActiveModel::Validations

  def initialize(&block)

  def check_validations!
    fail ArgumentError, errors.messages.inspect if invalid?

For my importing and parsing purposes, I created a small custom TypeValidator:

 # Ensure an object is a certain class. This is an example of a custom
 # validator. It's here as a nested class for easy access by subclasses.
 # @example
 #   class Dog < ValidatedObject
 #     attr_accessor :weight
 #     validates :weight, type: Float
 #   end
 class TypeValidator < ActiveModel::EachValidator
   def validate_each(record, attribute, value)
     return if value.class == options[:with]

     message = options[:message] || "is not of class #{options[:with]}"
     record.errors.add attribute, message

Here’s the finished ValidatedObject, and an example subclass: information about a CSV feed. This set up is working great; the only change I can see making soon is changing ValidatedObject to be mixed in via include rather than subclassing.

Thanks to:

The problem with packaging in Python

Excellent article. We got to this situation because of the changing nature of writing software, and how we deploy. Our standards have risen, and packaging (and tooling in general) takes on ever greater importance.

But we don’t have to theorize and invent paradigms from scratch. A few other languages have solved this. Ruby is the best example. Let’s learn from its user experience and the use cases it serves.