newline

Table of Contents

  1. Patching an Array
  2. Patching a Hash

Monkey patching: why Ruby is the best for prototyping and one-off scripts

Programming

September 09, 2022

In Ruby, ‘monkey patching’ lets you extend a class definition (with e.g. new methods) at runtime, for any class, even built-ins like Integer and Object. This gives you an incredible amount of flexibility, especially when you’re writing a one-off script, just working in a REPL, or prototyping something. Here’s two such ‘monkey patches’ I used today that prompted me to write this post.

Patching an Array

Let’s say you’re working with long arrays in a REPL, such as:

arr = (1..10_000).to_a

Every time an array like that prints, it’ll take a bit of time and scroll the whole screen. I’d like to get a preview of what’s in the array, like the first six elements. But I don’t want to type arr[..5] every time, something like arr.head would be nicer. Ruby doesn’t have a head method on arrays, but we can define it on the built-in Array class:

class Array
    def head
        self[..5]
    end
end

That class definition doesn’t re-define Array, it just extends the existing definition. And now we can use it:

[1,2,3,4,5,6,7,8].head
# => [1, 2, 3, 4, 5, 6]
arr.head
# => [1, 2, 3, 4, 5, 6]

Patching a Hash

Another example - I have a hash that uses symbols as its keys, like this:

h = {a: 1, b: 2, c: 3}

Typing h[:a] every time is a bit cumbersome, it would be nicer to do something like h.a. Calling h.a raises a NoMethodError, so we can use Ruby’s method_missing, which is called every time a method is called that doesn’t exist:

class Hash
    def method_missing meth, *args, **kwargs
        return self[meth] if self.has_key? meth
        raise NoMethodError.new("no method #{meth} on hash")
    end
end

And now we can use it:

h.a
# => 1
h.b
# => 2

So there you have it: in my opinion, this amount of flexibility makes Ruby one of the best languages for single-use scripts and prototypes. Should you use something like this in production code? I’d say no, unless it’s a very specific use case and you document it thoroughly. But for things like interactive work in a REPL, I don’t think there’s a better language.