Load Two Ruby Modules/Gems with the Same Name

Load two Ruby Modules/Gems with the same name

In Ruby, modules with the same name from different gems don't replace each other. If one gem implements

module AWS
class Foo
end
end

and another implements

module AWS
class Bar
end
end

and you require them both, you will end up with an AWS module that contains both a class Foo and a class Bar (unless the second does something really tricky like explicitly undefining anything already present in the module, before defining its own stuff, which is very unlikely). As long as the second gem doesn't redefine any methods in the first gem (or attempts to use a module as a class or vice versa), they should both work fine. I think you may be looking for the wrong solution.

Edit:
And in fact, what happens for me (in an environment with only these gems present (aws-sdk 1.2.3 and amazon-ec2 0.9.17) and the exact code you listed above) is exactly that:

.rvm/gems/ree-1.8.7-2011.03@ec2/gems/amazon-ec2-0.9.17/lib/AWS/EC2.rb:2: EC2 is not a module (TypeError)

Could it be that an error gets swallowed somewhere and that the module AWS::Cloudwatch hasn't been defined, simply because the initialization of the gem goes awry?

Two Ruby gems using the same namespace

This seems like a perfectly acceptable way to structure your gems. In your code sample, Foo::Bar and Foo::Baz will be two completely different classes within the same namespace, and they will not clash with each other. This is true even if you used the same method names within the two classes:

module Foo
class Bar
def do_thing
puts "Bar!"
end
end
end

module Foo
class Baz
def do_thing
puts "Baz!"
end
end
end

In this modified example, Foo::Bar#do_thing will output "Bar!" and Foo::Baz#do_thing will output "Baz!", since they are separate methods in separate classes. This approach allows you to swap out Foo::Baz objects for Foo::Bar objects to change behavior, since they have the same interface.

If you wanted your third-party API gem to extend the functionality of your vanilla API gem, you may want to consider adjusting your approach to use inheritance.

Ruby Rails: How Rails handle same method name in in two different gems

To answer your question directly: This is ultimately the responsibility of the developer who uses the gems. The authors of gems should take some care to name their methods appropriately, but nothing they can (or should) do will obviate the possibility of a collision.

This feature of Ruby is very powerful, but as always, with great power comes great potential for disaster.

how to require different gems with the same name?

As others answers and comments have said, you cannot simply require both gems as they are.

However, given that both are hosted on GitHub, you could fork one of them and rename the offending classes. So long as your renaming is consistent within the gem you could use your fork within your Gemfile

Of course, you wouldn't be easily able to rebase changes onto your fork easily but if you really must use both gems this might be a compromise that you are happy with.

How to have multiple gems that share the same common Ruby module?

Summarizing comments above for posterity...

There are a couple things to consider here.
1. Is commonCode significant? Is it a good chunk of code, or just a few files?
2. Are gemA and gemB significant? Should each of them really be gems?

Seems like you're in either one of two situations, depending on the significance of the code you've written:

  1. commonCode is significant enough (amount of code, complexity, logical separation from gemA and gemB) to merit its own gem? If so, definitely pull it out into its own gem. You can require gem-common in the other two. It doesn't make sense to require a plain ruby file in A and B that lives outside of those two code bases.

  2. commonCode is too insignificant to be pulled into its own gem. If this is the case, you should consider whether or not gemA and gemB really deserve their own gems, each. If they aren't big enough or logically separate enough, maybe all three can be combined into a larger gem.

Use two gems in same namespace in Rails

I wouldn't recommend doing this, since it could have some weird side effects such as if linkedin-oauth2 references itself with ::LinkedIn, but a method to redefine a ruby constant is shown in this answer.

I would change it a little bit to prevent renaming a constant warning... Object.send(:remove_const, :Stripe) instead of the Stripe = Module.new as shown in the answer. So, an example (not tested) would be:

require 'linkedin-oauth2'
LinkedInOauth2 = LinkedIn

Object.send(:remove_const, :LinkedIn)

require 'linkedin'


Related Topics



Leave a reply



Submit