Given a gem that defines top-level classes that clash with some code I have written, is it possible to require the gem in such a way that all its classes are grouped inside a module I can define? For example, if an unsafe_gem defines a class:
class Word
# ... some code
end
I would need something like:
class Word
# My word class.
end
module SafeContainer
# This obviously doesn't work
# (i.e. the gem still defines ::Word).
require 'unsafe_gem'
end
So that I can distinguish between:
Word.new # => The class I defined.
SafeContainer::Word.new # => The class defined by the gem.
Some further details: My code (e.g. the 'Word' class) is already wrapped in its own namespace. However, I want to be able to provide the user with the option of enabling a form of "syntactic sugar", which makes some classes directly accessible under the top-level namespace. This, however, creates a name clash with one of the gems I am using, which defines a top-level class. None of the currently proposed solutions work because the gem actually relies on its globally-defined class being there; so undefining the class breaks the gem. Of course, the gem has more than one file, and individually requiring its files into a module seems to be a very brittle solution. Currently, the only workaround I have found is this:
begin
# Require the faulty gem.
require 'rbtagger'
rescue
# If syntactic sugar is enabled...
if NAT.edulcorated?
# Temporarily remove the sugar for the clashing class.
Object.const_unset(:Word); retry
else; raise; end
ensure
# Restore syntactic sugar for the clashing class.
if NAT.edulcorated?
Object.const_set(:Word, NAT::Entities::Word)
end
end
I don't know why, but this makes my toenails curl. Anybody have a better solution?
I think your best bet is to wrap your own code in a module. Depending on how much code you have written, this may or may not be a huge pain. However, it is the best way to be sure that your code won't clash with someone else's.
So your Word
class becomes
module LoismsProject
class Word
#some awesome code
end
end
That way you can safely require 'unsafe_gem'
.
The simple answer is "no"
If we have a file 'word.rb';
class Word
def say
puts "I'm a word"
end
end
and we try and require
it, it will always load in the global scope.
If you knew the gem was just a single file, you could, however do the following.
module SafeContainer
module_eval(File.read("word.rb"))
end
but this is unlikely to work in your case.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With