Polish Your Gems

Share this article

As Ruby developers, we often forget how good we have it. We’ve got a awesome library distribution system in Rubygems, we use a powerful and flexible language that just begs to be used for DSLs and a culture of open development and community improvement. In this article, I’ll be talking about the ways you can add that bit of extra polish to your useful new gem. We’ll look at some common usage patterns and how they’re achieved in popular gems.

None of these tips provide any extra functionality for your gem – but they do provide a good user experience. If you have ambitions for your gem to become popular, UI matters and code is a programmers UI.

The Config Block

If you’ve been a rubyist for even a short while, you’ve seen this. The method I’m going to show use is useful for global set up of the gem. Let’s take a look:

[gist id=’3332088′]

So, there’s a few things to notice here. Firstly, I’ve chosen to have the Configuration object inherit from the fantastic hashie mash gem. This allows us to treat our Configuration object as a hash internally, but means we can expose nice dot syntax in the block itself. In the example a.magic_number = 3 results in the equivalent of a[:magic_number] = 3. Secondly, the config method acts just like the instance method that you’d write if you were making a singleton class, so we don’t have to worry about multiple instances of configuration turning up.

Chain Reaction

If you’re writing a gem which performs some kind of searching on an interface, then you’re presented with somewhat of a API challenge: How can I let my users create complex searches while avoiding a bad case of the hashes? To illustrate what I mean, let’s take a look at Active Record 2 vs 3:

[gist id=’3332092′]

In the Active Record 3 example, method chaining is used instead of a potentially massive hash to define our query. This also has the added benefit of allowing us to define our query easily over time and only execute it when we’re sure we need it by calling a method that sparks off the actual query execution – each for example.

Let’s build a really simple method chaining search object:

[gist id=’3332095′]

As you can see, we’ve made a pretty convincing search interface here that feels a fair deal like Active Records 3’s query syntax. All you’ll need to do is return self at the end of chainable methods to get the effect. Notice that each is a nice extra here, as it removes the need for an explicit call to results.

Include Everything, Where Appropriate.

As I’m sure you know, you can include a module to add the module’s instance methods to a class or you can extend a module to add class methods. Often, when writing gems, we need to do both. Adding a few lines to the documentation to explain to users that we need to include Library::InstanceMethods and extend Library::ClassMethods is one approach, but that is one extra thing for the user to worry about and there’s no reason the user experience can’t be improved.

HTTParty is perhaps the most used example of this pattern.

Default HTTParty usage looks something like this:

[gist id =’3332108′]

The class Thingy will now have the very handy instance method post for POST requests, but will also have the option to call post on the class should your application not actually need to create new Thingys but just to use one.

How does this work? Let’s look at the source – copied from github with some bits chopped out for clarity:

[gist id =’3332112′]

self.included is a method defined in the Ruby core Module class which get called on when a module is included in another class. base, in this example, is the class Thingy. By overriding it, we’re now able to extend Thingy with HTTPart::ClassMethods saving the user an additional extend.

Also, because we’ve got a handle on Thingy we’re able to perform some setup on the object – as in the example here we’re some default values are set.

The included method, and it’s counterpart extended, are really powerful – but easily abused. In places where you do not need to include and extend there’s really no need to muddy the water by overriding included just so you can use include to bring in class methods – there be dragons down that road.

Be Helpful

This isn’t a code tip – just something I bumped into this week and can’t recommend enough. As developers, perhaps especially as web developers, we should all be aware that it take x seconds for a user to leave a page if they’re having a bad time. I would suspect that the same holds for programmers when they’re having a bad time setting up a gem.

Friendly exceptions are one way to be helpful. Consider replacing the exception message “No configuration file found” with “Cannot find configuration file: config/awesome.yml” – maybe you could even pop in a url to the documentation there.

Ultimately, the experience of your gem is mostly a function of code quality and usefulness. Even libraries which aren’t very user friendly can find great success in the same way as software which isn’t very user friendly can inexplicably thrive.

I’d be intrested to hear your experiances with popular gems. Is there anything that recently caught your eye as a great bit of programmer centric UI? Is there anything that any of the big gems do that’s annoying? As ever, I’ll be lurking around the comment section or on the Tweet machine – do get in touch.

Daniel CooperDaniel Cooper
View Author

Daniel Cooper is a web developer from Brighton, UK

gems
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week