Reputation: 8894
a gem intends to support gems a
or b
as alternatives for a functionality.
In code I check with defined?(A)
if I fall back to b
that's fine.
But as a gem developer how to specify these dependencies?
1) what do I put in the Gemfile.
group :development, :test do
gem 'a', :require => false
gem 'b', :require => false
end
This allows Bundle.require(:test)
not to auto-require a,b?
2) How can explicitly require a
and b
separately to mimic (or mock) the scenario when we fall back to b
in my tests?
3) Also how do I specify that either a
or b
is prerequisite for the gem.
thanks
Upvotes: 5
Views: 2934
Reputation: 1025
I got this same question a while ago. My solution was to think that the developer should specify this behavior. I would not specify it on the gem, but on the wiki. I would recommend you to document it clearly that the developer need to define one of the dependencies.
To make it better, you can make a check on initialization of the gem, looking for the dependencies, if none can be found, just raise a runtime exception or if you prefer, your own exception. =)
Upvotes: 0
Reputation: 17030
Don't include the a
gem in your dependencies, but require
it anyway. If that fails, it will raise LoadError
, from which you can rescue.
begin
require 'a'
rescue LoadError
# The 'a' gem is not installed
require 'b'
end
I believe this is the best way to use and test this setup:
Define an interface for your backend and allow a custom implementation to be easily plugged in.
module YourGem
class << self
attr_accessor :backend
def do_something_awesome
backend.do_something_awesome
end
end
end
Implement the a
and b
backends.
# your_gem/backends/a.rb
require 'a'
module YourGem::Backends::A
def self.do_something_awesome
# Do it
end
end
# your_gem/backends/b.rb
require 'b'
module YourGem::Backends::B
def self.do_something_awesome
# Do it
end
end
Set the one you want to use.
begin
require 'your_gem/backends/a'
Gem.backend = YourGem::Backends::A
rescue LoadError
require 'your_gem/backends/b'
Gem.backend = YourGem::Backends::B
end
This will use YourGem::Backend::A
even if b
is installed.
Before testing, make sure both a
and b
gems are installed, require
both backends in the test code, run the tests with one backend, then run the tests again with the other backend.
Upvotes: 4