我正在构建一个加载用户提供的ruby代码的框架。它基本上是一个插件机制。我希望用户提供ruby代码,以便能够获得自己的宝石。我打算让“插件”包中包含一个包含宝石的供应商目录。
如何加载插件所需的宝石,而不会让它们与我的框架的宝石发生冲突?例如,如果我的框架使用treetop版本1.3.0,并且插件使用treetop 1.4.2我希望每个都使用他们指定的版本。
同样,有没有办法防止插件相互冲突?
我看过gem_plugin,_why的沙箱和其他一些工具。但是我没有看到任何专门处理这种情况的库 - 我认为它之前已经完成了。
我还看了Bundler的内部,看看它如何管理宝石版本。如果需要,我准备做一些非常复杂的事情。但我仍然不确定如何去做。
我对如何实现这一点也有很大的自由。所以,如果你认为我正在咆哮错误的树,请说出来。
感谢您的任何建议。
SIDE注意:在我写这篇文章时,我发现需要类似于Java servlet容器中的类加载器。 WAR文件可以包含jar文件,Web应用程序的类加载器将优先于全局类路径上的jar。有没有办法在ruby中分割ruby“classpath”(即load_path,require等)?
答案 0 :(得分:5)
说实话,你不能同时加载同一个宝石的两个版本。
Bundler做了很好的(ish)工作,查看所有必需的gem并找到各种重叠依赖项的解决方案,但即便如此,它也只限于一次只加载一个gem版本。
这导致插件开发人员不断更新以支持在依赖宝石中所做的任何更改,以避免您描述的情况。
(不要让我从各种竞争的JSON实现开始搞砸了,当你有几个gem依赖项都需要不同的时候,你必须经历的痛苦。)
答案 1 :(得分:0)
恭敬地不同意上述答案。我是这样做的:
ruby -S gem list my_gem
`*** LOCAL GEMS ***
my_gem (1.0.1, 1.0.0, 0.0.2)
`
ruby -S gem lock my_gem-1.0.0 > locklist.rb
生成特定版本的依赖关系列表到locklist
require 'rubygems'
gem 'my_gem', '= 1.0.0'
gem 'gem_base', '= 1.0.0'
gem 'rest-client', '= 1.7.2'
gem 'savon', '= 1.1.0'
gem 'addressable', '= 2.3.6'
gem 'mime-types', '= 1.25.1'
gem 'netrc', '= 0.11.0'
现在您可以执行load('locklist.rb')
,它将加载特定版本的gem及其依赖项。看马,没有Bundler。