Namespacing Core Extensions In Ruby Gems
If you’ve spent any time developing your own Ruby gems or libraries, you’ve probably added some custom methods to Ruby’s core classes. This post is about the best place to keep these methods.
A Contrived Example With Parrots
Here’s an example of how I might extend a core class, and then use the extended class in my code. Imagine I’m building a gem called “parrot” which takes a string and repeats the string back to the user (it’s groundbreaking stuff):
This looks good: everything are well-organised, my core extensions are kept in their own files (named after the classes they’re extending), in their own “core_ext” folder. If I want to load my extensions to Array, I know exactly where to go: core_ext/array.rb. Also I have a talking ruby parrot, which is cool.
This setup is great 90% of the time, but that doesn’t mean we shouldn’t care about the other 10%: we could run into problems when the parrot gem is used alongside another gem which also extends Array. Put simply, the issue is:
- Both gems extend
Array - Both gems keep their extensions in gem_name/lib/core_ext/array.rb
- Both gems use
require "core_ext/array"to load their extensions - When both gems are used together, that require statement becomes ambiguous
In short, when both gems work together it may not be possible to say for sure which file require "core_ext/array" will load (I’m assuming that the load path is setup to allow each gem access to the other gem’s lib folder: this is normally the case).
I think it’s worth going the extra mile (or extra few lines of code) to preempt this problem. Here’s how I handle it:
I’ve moved core_ext/array.rb to parrot/core_ext/array.rb. By namespacing the file under “parrot”, I can avoid clashes with core extensions in other gems: require "parrot/core_ext/array" will always load my core extensions (and another gem, if they’re taking the same approach, can require "other_gem/core_ext/array" to load their own extensions).
It’s a small change but one that — I think — makes for better-structured code.