A Guide to Extracting Your First Ruby Gem

Is your GitHub contribution chart solid gray? You could use an open source project to work on. But you don’t have to start it from scratch. The easiest way to create a useful side project is to pull it out of the app you’re already building. That’s how Rails was born!

But how do you know what to extract? And how do you turn it into a gem, without destroying your workflow?

Find the code you want to extract.

Somewhere, deep inside your app, is some code that doesn’t belong there. Code that doesn’t need your app to do its job. Where is it?

Sometimes, you’ll just have to guess. But I often find extractable code in the same few places:

  • Validations

    Have you written any custom validations for your attributes? Those can make great gems.

  • Changes you’ve made to Rails

    Every once in a while, you’ll have to mess with Rails to get commit hooks working in tests or blank attributes to turn into NULL in the database. Whenever I’ve moved this kind of logic into a gem, it’s become more stable and easier to understand.

  • Non-activerecord models

    Do you do so much email address or phone number parsing that you moved it into its own class? These classes are often useful in other apps, and they’re pretty easy to turn into gems.

  • Mock objects and custom assertions

    You can write more readable tests by using custom assertions. And once you have some good custom assertions written for a library or pattern, they’re helpful to anyone else who uses that library or pattern.

You don’t have to think big. Some of my favorite gems are just one file!

And if you still can’t decide what to extract, browse the category list on RubyToolbox for some inspiration.

Put your code in a gem-like directory

Once you know which code you’ll turn into a gem, move that code around so it fits a gem-like structure inside your app.

In Rails apps, I use lib/ as a gem staging area. lib/ is where I put code that has the potential to turn into its own gem. So, if you’re creating a gem called “json_api_client”, your Rails app’s lib/ directory might look like:

...
my_rails_app/lib/json_api_client.rb
my_rails_app/lib/json_api_client/associations.rb
my_rails_app/lib/json_api_client/connection.rb
...

Most gems will have a file under lib/ named after the gem (lib/json_api_client.rb), and a bunch of files in a directory named after that gem (everything under lib/json_api_client/). So, take that same structure and match it inside your Rails app. That will make it much easier to move code into the gem later on.

If you’re confused about what a gem layout looks like, take a look at some of your favorite gems’ source on GitHub. You’ll pick up the pattern pretty quickly.

What about tests?

I used to follow lib/’s structure inside test/unit/:

...
my_rails_app/test/unit/json_api_client_test.rb
my_rails_app/test/unit/json_api_client/associations_test.rb
my_rails_app/test/unit/json_api_client/connection_test.rb
...

It worked OK, even if putting models and libraries in the same folder got a little messy.

Now, though, Rails uses test/models/ instead of test/unit/. And storing your lib/ tests inside test/models/ doesn’t make a whole lot of sense. I haven’t really decided on a convention for this yet. Do you have any suggestions?

Break the dependencies

Once your code is inside a gem, it won’t be able to depend on your app. This means you’ll have to go through the code you put in lib/, and look for places where it depends on classes, objects, or behavior specific to your app.

If you do find any of these dependencies, you’ll have to break them. There’s a lot of great writing about how to break (or inject) dependencies, so I’m not really going to go into that now.

Create a gem

I use bundle gem to create my gems. Specifically, to create a gem called bulk_cache_fetcher:

bundle gem bulk_cache_fetcher -t minitest

The -t adds some test helper files and the test tasks to the gem’s Rakefile.

You’ll have to do some housekeeping next, like filling out the .gemspec, writing the README, picking a LICENSE, all that stuff.

And then, since you already have your gem’s code in your Rails app’s lib/ folder, you can just move that code and its tests into the lib/ and test/ folders in your new gem.

A lot of the time, there’ll be things you missed or forgot about, or code that assumes things about your app that aren’t true inside a gem. So, before you move on, run the tests you moved into your gem, and make sure they all pass.

Use your new gem in your app

Now that you have a gem, you want to use it, right? But testing changes to your gem inside your Rails app can get annoying, quickly. You have to:

  1. Make the change in your gem
  2. Build the gem
  3. Remove all traces of the gem from your system, or update the version
  4. Install the gem
  5. Restart your server

This is pretty awful. Luckily, bundler gives you an easier way. Say you’ve created your gem in ~/Source/bulk_cache_fetcher. While you’re testing gem changes, you can write this inside your Rails app’s Gemfile:

Gemfile
gem "bulk_cache_fetcher", path: "~/Source/bulk_cache_fetcher"

Next, run bundle install, and you’ll be able to make changes to your gem as if that code still lived in your app’s lib/ folder.

One last thing: make sure you remove the path: before you check in your code! That path may not point to the right place on other systems, so chances are it won’t work anywhere except your machine.

Build, ship, and enjoy!

Once your gem is ready, you can send it out to the world.

So, sign up for an account on RubyGems if you haven’t already, check in your changes, and run rake release. Congratulations, you’re now a gem author! And once you push that gem to github, you’ll get your nice green square for the day.

Do you have any parts of your own apps that seem extractable? Anything that you think might make a good gem? I’d love to hear about it – just leave a comment below.

And if you want to learn a ton more about creating, managing, and maintaining Ruby gems, I highly recommend Brandon Hilkert’s Build a Ruby Gem. The process his book follows is very close to this one, and it covers a whole lot more.

Pushing through tutorials, and still not learning anything?

Have you slogged through the same guide three times and still don't know how to build a real app?

In this free 7-day Rails course, you'll learn specific steps to start your own Rails apps — without giving up, and without being overwhelmed.

You'll also discover the fastest way to learn new Rails features with your 32-page sample of Practicing Rails: Learn Rails Without Being Overwhelmed.

Sign up below to get started:

Powered by ConvertKit

Did you like this article? You should read these:

Comments