Ruby Footguns

Alexander Avery

Sat | Jul 2, 2022

computer-science A ruby ring, representing the Ruby programming language.

Exploring Ruby Metaprogramming Footguns

The last few weeks, I’ve been learning different languages to see what’s popular outside my regular sphere. My journey took me to lots of articles written by Ruby enthusiasts, and the common usage of metaprogramming. Plenty of languages support metaprogramming, but I’ve seen very few communities use and encourage it actively. It’s even used in considerably “Enterprise Projects” such as RSpec and Active Record.

In an effort to have fun with metaprogramming, I’ve created a project of intentional Ruby Footguns. This project is not a point against metaprogramming or meant to showcase potential problems, it is simply meant to make me laugh… or facepalm.

My first entry in this repo is quite basic, a class that implements method_missing in a rather horrible way. If you invoke a non-existent method, it will invoke a method with a Levenshtein distance of two or less, and subsequently make it private. By design, it punishes small typos by causing NoMethodError to appear from seemingly innocuous lines of code.

class TypoBomb

  def print_stuff
  	puts "My method is working as expected"
  end

  def method_missing(method_name, *args, &block)
    name = methods.select do |name|
      levenshtein(name.to_s, method_name.to_s) <= 2
    end.first

    if !name.nil?
      val = send(name, *args, &block)
      self.class.undef_method(name)
      return val
    else
      raise NoMethodError
    end
  end
end

b = TypoBomb.new
b.pint_stuff # > "My method is working as expected"

# more stuff happening until...
b.print_stuff # BOOM! raises NoMethodError and confusion ensues

So now this seemingly perfect line is raising an error, when the real culprit is the typo that occurred elsewhere. As another consequence, the typo doesn’t even have to occur on the same instance. If an instance b2 calls print_stoff, the next time b or any instance anywhere of TypoBomb calls print_stuff, it will break.

Go check out the repo to see this and other footguns complete with unit tests.

Next: Open Source Without GitHub
Previous: Go, One Year Later
>> Home