Question

I'm working on writing a gem that has several gem dependencies, one of which depends on a gem that broke backwards compatibility in a newer version. This got me to thinking - I don't want the gem that I'm building to become "that gem" that is making it difficult for people to update their application. I also don't want to force people using my gem to have to use specific versions of the gems it depends on in the rest of their application.

On one hand, I could just rewrite all of the code from those dependencies to bundle them with my gem and remove the dependency all together, but that seems a little tedious. Is there any way for me to simply include the gem dependencies directly in my gem, then wrap them in a module so my packaged versions don't conflict with the versions used by the rest of the application?

Was it helpful?

Solution

I don't think what you want is possible via existing Ruby tools. However, if backwards-compatibility for you when relying on your dependency is purely a syntax/usage issue, and not a low-level difference between versions, then you don't have to import and maintain the old gem's code. You have another option: Create a "shim" layer in your gem that provides the functions you need from either new or old interface of the dependency.

In practice it might look like this, assuming by way of example that it was the constructor to the Thingy class that has changed:

module DependencyShim

  def new_Thingy( new_style_args )
    if thingy_is_new
      Thingy.new( new_style_args )
    else
      Thingy.new( convert_args_to_old_style( new_style_args ) )
    end
  end

  # convert_args_to_old_style() not shown

  private

  def thingy_is_old
    Thingy::VERSION < '1.3.4'
  end

  def thingy_is_new
    Thingy::VERSION >= '1.3.4'
  end
end

Better abstractions are very likely possible, but are difficult to predict as I don't know the nature of difference between old and new, and how tightly bound your code is to your dependency.

This is obviously painful if there are radical changes between versions, and your own gem uses the dependency heavily. But even then it may still be less painful than re-implementing and maintaining the dependency inside your own gem.

I would recommend looking at making your gem the most compatible with latest versions of your dependencies, and over the long term moving to deprecate support for the old dependencies, based on what you know of your user base. There may be good reasons for all involved to move away from the old dependency.

OTHER TIPS

Assuming you are using bundler, you can specify versions for dependencies in your Gemfile like this:

gem "my_dependency", "0.6.1"

There's a whole load of other options too such as 'version greater than X' etc. Read the bundler docs for more info.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top