Álvaro Fernández-Alonso Araluce

Álvaro Fernández-Alonso Araluce

Published in ruby, gems, open-source, tutorial, building-a-gem-serie, rubygems, maintenance · · 6 min read

Publishing, Versioning, and the Real Life of a Gem

Final article in the series about building Ruby gems. We’ve demystified gems, seen their anatomy, built an API wrapper, and tested everything. Now it’s time for the final step: putting it out in the world.


From your folder to RubyGems

You have a functional, tested gem. Publishing it is ridiculously simple.

First, make sure your gemspec has all the information filled out: name, version, description, homepage, license. This is what shows up on rubygems.org.

Then, two commands:

gem build my_gem.gemspec
gem push my_gem-0.1.0.gem

The first time it’ll ask for your RubyGems account. If you don’t have one, create it in two minutes at rubygems.org/sign_up. And that’s it. Your gem is published. Anyone in the world can do gem install my_gem.

If you’re using the Rakefile we covered in the anatomy article, you can simplify even further:

rake build    # Builds the .gem
rake release  # Git tag + push to RubyGems

rake release creates the git tag with the version, pushes the tag to your repository, and publishes the gem. All in one command.

Semantic Versioning: the contract with your users

When you change your gem’s version, you’re communicating something. Semantic Versioning (SemVer) is the convention that tells you exactly what to communicate:

MAJOR.MINOR.PATCH1.2.3

  • PATCH (1.2.3 → 1.2.4): bug fixes. Nothing breaks.
  • MINOR (1.2.0 → 1.3.0): new functionality. Existing features still work.
  • MAJOR (1.0.0 → 2.0.0): breaking changes. User code may need updates.

It’s essentially a contract. If you publish a PATCH, people trust they can update without fear. If you publish a MAJOR, they know they need to review.

In Calendlyr I went from 0.7.0 (the first real, usable release) to 1.0.0 over 5 years. The jump to 1.0 meant: “this gem covers the entire Calendly API v2 and is stable.” The versions in between were MINORs with new features and PATCHes with fixes.

My advice: don’t be afraid of 0.x. Your gem doesn’t need to be 1.0 to be useful. Use 0.x while you’re iterating fast and haven’t settled on a stability contract.

CHANGELOG: don’t underestimate it

A CHANGELOG is a chronological list of changes per version. It sounds like bureaucracy, but when someone is considering updating your gem, it’s the first thing they look at.

The format is simple:

## [0.8.0]
### Added
* All error classes now inherit from `Calendlyr::Error`

### Fixed
* Empty body responses no longer crash

### Changed — Breaking
* `rescue StandardError` no longer catches API errors

Each version lists what was added, what was fixed, and what broke. No prose. No fluff. Pure information.

Keep the CHANGELOG from day one. Update it with each change, not after. It’s much easier to write “added X” when you just did it than to reconstruct it three months later from the git log.

The reality of maintenance

And now the part nobody talks about.

Calendlyr has been around since 2021. That’s 5 years. In that time, the Calendly API has changed responses, added endpoints, deprecated others. And for most of those 5 years, maintenance was practically nonexistent.

You know what? The gem kept working.

That’s not luck. It’s a direct consequence of the design decisions I made at the beginning:

Zero production dependencies. There was never a moment of “Faraday released a new version and broke everything.” If Ruby works, Calendlyr works.

Objects without fixed attributes. The Calendly API added new fields to its responses many times. The gem returns them automatically without needing any updates. That decision to use method_missing instead of defining static attributes was, in hindsight, the best decision of the entire project.

Tests with fixtures. When I finally did update the gem, the tests told me exactly what worked and what didn’t. Being able to run rake test after months of not touching the code and seeing green is an enormous relief.

Minimal maintenance isn’t neglect. It’s intentional design. If you make good decisions at the start, your gem needs less attention later.

What actually changed

It wasn’t all autopilot. These are the real changes I had to make over the years:

  • Ruby deprecated OpenStruct. I had to replace it with my own Object class. The logic didn’t change, just the mechanism. One change, and the gem kept working the same.
  • New API endpoints. Calendly kept adding functionality. Some endpoints I implemented when I needed them, others when I decided it was time to complete the coverage.
  • Minor bugs. Typos in error class names, empty body causing a crash. Small things the tests would have caught if I’d had them from the start (lesson learned).

The point is that none of these changes were emergencies. The gem worked. The changes were improvements, not urgent patches.

The reception

I’ll be honest with you. I published Calendlyr, shared it on blogs and Rails community chats, and the reception was almost nonexistent. A handful of GitHub stars, a follow here and there, no memorable conversations.

Did it discourage me? A little, at first. Did it matter? Not at all.

The gem exists. It works. I use it in production. I learned how the gem ecosystem works from the inside, how to design an API wrapper, how to maintain open source software. All of that is worth infinitely more than a star counter.

If you wait for your gem to be “good enough” or “original enough” to publish it, you’re never going to publish it. Put it out there. If it helps someone else, great. If it only helps you, that’s great too.

What I wish I had known

If I could go back to the day I created Calendlyr, I’d tell myself:

  1. Start simple. You don’t need to cover the entire API on day one. The first version of Calendlyr was a handful of endpoints. And it was enough.

  2. Design decisions matter more than code. Zero dependencies and dynamic objects were 5-minute decisions that saved me years of maintenance.

  3. Test from the start. The tests I didn’t write at the beginning I had to write later. It’s easier to do it when the code is fresh.

  4. Find someone to bounce ideas off. My CTO was key. You don’t need a formal mentor, just someone who listens and challenges you.

  5. Don’t wait for external validation. Your gem’s value isn’t defined by GitHub stars.

Closing

We’ve walked the entire path. From “why on earth would I build a gem?” to having one published, tested, and running in production.

Was it hard? No. Does it take time? Yes. Is it worth it? Absolutely.

A gem is packaged Ruby code. If you know how to write Ruby, you know how to create a gem. The barrier was never technical. It was psychological. And if you’ve made it this far, you’ve already broken it.

Now it’s your turn. Open your terminal. Type bundle gem. And start.