我为manipulating with genome scaffolds called "Scaffolder"编写了一个命令行工具。目前,我想要使用的所有工具都被硬编码到库中。例如,这些工具“验证”或“构建”脚手架。我想将这些工具拆分成他们自己的宝石,使其更加模块化,并允许第三方编写自己的命令。
理想的情况是我运行“gem install scaffolder-validate”,然后这个gem-bundled命令将作为scaffolder的一部分提供。我知道有几个库可以很容易地构建一个命令行界面:thor,commander,gli,....但我不认为它们中的任何一个都能满足这种功能。
我的问题是我如何使用gem结构来创建用于安装这些命令的模块结构?具体如何自动检测和加载已安装的命令?在gem名称scaffolder- *中有一些前缀然后搜索rubygems?我怎么能用黄瓜测试呢?
答案 0 :(得分:1)
require
所有其他宝石,并在它们不存在时捕获加载错误并禁用相应的功能。我在我的一个宝石中这样做。如果存在HighLine,则会提示用户输入密码,如果不存在配置文件。
begin
require 'highline'
rescue LoadError
highline = false
end
如果你有很多宝石,这可能会变得很丑陋......
答案 1 :(得分:1)
因此,您可以做的一件事是确定插件的规范名称,然后使用该约定动态加载内容。
您的代码看起来都在模块Scaffolder
下,因此您可以按照以下规则创建插件:
Scaffolder
个宝石必须命名为scaffold-tools-plugin-
pluginname Scaffolder::Plugin::
插件名 鉴于此,您可以接受要加载的插件的命令行参数(假设OptionParser
):
plugin_names = []
opts.on('--plugins PLUGINS','List of plugins') do |plug|
plugin_names << plug
end
然后:
plugin_classes = []
plugin_names.each do |plugin_name|
require "scaffold-tools-plugin-#{plugin_name}"
plugin_classes << Kernel.const_get("Scaffold::Plugin::#{plugin_name}")
end
现在plugin_classes
是配置的插件的类对象的Array
。假设它们都符合一些常见的构造函数和一些常用方法:
plugin_classes.each do |plugin_class|
plugin = plugin_class.new(args)
plugin.do_its_thing(other,args)
end
显然,在进行这样的大量动态类加载时,您需要小心并信任您正在运行的代码。我假设这么小的域名,它不会引起关注,但只要警惕require
随机码。