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.
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]
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.