Open Source Adventures: Episode 37: Fixing beeminder gem to work with Ruby 3
Tags: ruby
Published: 2022-04-17 10:25:28

Here's an easy thing I needed to do. I was setting up a new laptop, with latest version of Ruby, and the script I used to snapshot beeminder data stopped working.

It turns out to be a trivial issue. `beeminder` gem depends on `json` 1.x, which doesn't work with Ruby 3. Simply changing that to `json` 2.x fixes it.

It also turns out this was already fixed, years ago, but the fix was never released. So all I did was [poke them on GitHub issues](https://github.com/beeminder/beeminder-gem/issues/31).

### Hotfixing gem dependencies

This is fine, but I have no patience for waiting for a new release.

So here's a hacky thing I did.

I installed latest version of json with `gem install json`.

Then I checked where `beeminder` gem is installed:

```
$ EDITOR=echo gem open beeminder
/Users/taw/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/beeminder-0.2.12
```

So my first idea was to hotfix `/Users/taw/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/beeminder-0.2.12/beeminder.gemspec` by replacing:

```ruby
  gem.add_dependency 'json', '~> 1'
```

with:

```ruby
  gem.add_dependency 'json', '~> 2'
```

That however did not work, as Rubygems is caching dependency information.

I needed to change `/Users/taw/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/specifications/beeminder-0.2.12.gemspec`. Here's the final file:

```ruby
# -*- encoding: utf-8 -*-
# stub: beeminder 0.2.12 ruby lib

Gem::Specification.new do |s|
  s.name = "beeminder".freeze
  s.version = "0.2.12"

  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
  s.require_paths = ["lib".freeze]
  s.authors = ["muflax".freeze, "bsoule".freeze]
  s.date = "2018-09-27"
  s.description = "Convenient access to Beeminder's API.".freeze
  s.email = ["support@beeminder.com".freeze]
  s.executables = ["beemind".freeze]
  s.files = ["bin/beemind".freeze]
  s.homepage = "https://github.com/beeminder/beeminder-gem".freeze
  s.rubygems_version = "3.3.7".freeze
  s.summary = "access Beeminder API".freeze

  s.installed_by_version = "3.3.7" if s.respond_to? :installed_by_version

  if s.respond_to? :specification_version then
    s.specification_version = 4
  end

  if s.respond_to? :add_runtime_dependency then
    s.add_runtime_dependency(%q<activesupport>.freeze, [">= 3.2", "< 6"])
    s.add_runtime_dependency(%q<chronic>.freeze, ["~> 0.7"])
    s.add_runtime_dependency(%q<json>.freeze, ["~> 2"])
    s.add_runtime_dependency(%q<highline>.freeze, ["~> 1.6"])
    s.add_runtime_dependency(%q<optimist>.freeze, ["~> 3"])
    s.add_runtime_dependency(%q<tzinfo>.freeze, ["~> 1.2"])
  else
    s.add_dependency(%q<activesupport>.freeze, [">= 3.2", "< 6"])
    s.add_dependency(%q<chronic>.freeze, ["~> 0.7"])
    s.add_dependency(%q<json>.freeze, ["~> 2"])
    s.add_dependency(%q<highline>.freeze, ["~> 1.6"])
    s.add_dependency(%q<optimist>.freeze, ["~> 3"])
    s.add_dependency(%q<tzinfo>.freeze, ["~> 1.2"])
  end
end
```

And that worked.

### Should you do this?

To be honest, I don't really recommend doing this. Hotfixing globally installed dependencies is generally a poor idea, and there are more proper ways to do this.

You can also use this kind of hotfixing to quickly check if you're on a right track. If the gem was crashing with updated `json`, I'd know it's something bigger.

If you do so, you should uninstall and reinstall that gem afterwards to make sure no edits remain.

### Coming next

For the next episode I'll go back to the Russian losses tracker, as there's a few more things I want to add.