如何使用 rubygems 构建模块化命令行界面?
我编写了一个命令行工具,用于操作名为“Scaffolder”的基因组支架。目前我想要使用的所有工具都被硬编码到库中。例如,这些工具“验证”或“构建”脚手架。我想将这些工具拆分成自己的 gem,使其更加模块化,并允许第三方编写自己的命令。
理想的情况是我运行“gem installscaffolder-validate”,然后这个 gem 捆绑的命令将作为脚手架的一部分可用。我知道有几个库可以轻松构建命令行界面:thor、commander、gli……但是我不认为它们中的任何一个都适合这种类型的功能。
我的问题是如何使用 gem 结构来创建用于安装这些命令的模块结构?具体来说,如何自动检测并加载已安装的命令?在gem名称scaffolder-*中添加一些前缀然后搜索rubygems?我如何用黄瓜测试这个?
I've written a command-line tool for manipulating with genome scaffolds called "Scaffolder". At the moment all the tools I want to use are hard-coded into the library. For instance these tools "validate" or "build" the scaffold. I'd like to split these tools out into their own gems, make it more modular, and to allow third parties to write their own commands.
The ideal case would be that I run "gem install scaffolder-validate" and this gem-bundled command would then be available as part of scaffolder. I know a couple of libraries make it easy to build a command-line interface: thor, commander, gli, .... However I don't think any of them cater for this type of functionality.
My question is how can I use a gem structure to create a module structure for installing these commands? Specifically how can the installed commands be auto-detected and loaded? With some prefix in the gem name scaffolder-* then searching rubygems? How could I test this with cucumber?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
因此,您可以做的一件事就是为您的插件确定一个规范名称,然后使用该约定来动态加载内容。
看起来您的代码都在模块
Scaffolder
下,因此您可以按照以下规则创建插件:Scaffolder
gems 必须命名为scaffold-tools-plugin-
pluginnameScaffolder::Plugin::
Pluginname 的此,您可以接受要加载的插件的命令行参数(假设
OptionParser
):然后:
现在
plugin_classes
是一个<配置插件的类对象的 code>Array。假设它们都符合一些通用的构造函数和一些通用的方法:显然,在进行大量这样的动态类加载时,您需要小心并信任您正在运行的代码。我假设对于这么小的域,这不会是一个问题,但只是要警惕
需要
随机代码。So, one thing you can do is to decide on a canonical name for your plugins, and then use that convention to load things dynamically.
It looks like your code is all under a module
Scaffolder
, so you can create plugins following the following rules:Scaffolder
gems must be namedscaffold-tools-plugin-
pluginnameScaffolder::Plugin::
PluginnameGiven that, you can then accept a command-line argument of the plugins to load (assuming
OptionParser
):Then:
Now
plugin_classes
is anArray
of the class objects for the plugins configured. Supposing they all conform to some common constructor and some common methods:Obviously, when doing a lot of dynamic class loading like this, you need to be careful and trust the code that you are running. I'm assuming for such a small domain, it won't be a concern, but just be wary of
require
ing random code.嗯,棘手的一个。我的一个简单想法是,主 gem 只是尝试
需要
所有其他宝石,并在它们不存在时捕获加载错误并禁用相应的功能。我在我的一颗宝石中这样做。如果 HighLine 存在,系统会提示用户输入密码,如果不存在,则必须输入密码一个配置文件。如果你有很多宝石,这可能会变得丑陋......
Hm, tricky one. One simple idea I have is that the main gem just tries to
require
all the others and catches the load error when they are not there and disables the respective features. I do this in one of my gems. If HighLine is present, the user gets prompted for a password, if it isn't there has to be a config file.If you have a lot of gems this could become ugly though...