OptionParser可以跳过未知选项,以便稍后在Ruby程序中进行处理吗? [英] Can OptionParser skip unknown options, to be processed later in a Ruby program?

查看:119
本文介绍了OptionParser可以跳过未知选项,以便稍后在Ruby程序中进行处理吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有什么方法可以启动 OptionParser 在一个Ruby程序中几次,每个都有不同的选项集?

Is there any way to kick off OptionParser several times in one Ruby program, each with different sets of options?

例如:

$ myscript.rb --subsys1opt a --subsys2opt b

在这里,myscript.rb将使用subsys1和subsys2,将它们的选项处理逻辑委派给他们,可能的顺序是先处理'a',然后在单独的OptionParser对象中处理'b';每次选择仅与该上下文相关的选项. 最后一个阶段可以检查每个零件处理完零件后是否还有未知的东西.

Here, myscript.rb would use subsys1 and subsys2, delegating their options handling logic to them, possibly in a sequence where 'a' is processed first, followed by 'b' in separate OptionParser object; each time picking options only relevant for that context. A final phase could check that there is nothing unknown left after each part processed theirs.

用例是:

  1. 在一个松耦合的前端程序中,其中的各个组件具有不同的参数,我不希望"main"了解所有信息,而只是将参数/选项集委派给每个部分.

  1. In a loosely coupled front-end program, where various components have different arguments, I don't want 'main' to know about everything, just to delegate sets of arguments/options to each part.

将一些较大的系统(如RSpec)嵌入到我的应用程序中,而我只是简单地通过命令行通过它们的选项,而我的包装程序不知道这些选项.

Embedding some larger system like RSpec into my application, and I'd to simply pass a command-line through their options without my wrapper knowing those.

我也可以使用一些定界符选项,例如某些Java应用程序中的----vmargs.

I'd be OK with some delimiter option as well, like -- or --vmargs in some Java apps.

在Unix世界(startx/X,git管道和瓷器)中,有很多类似的现实世界示例,其中一层处理一些选项,但将其余选项传播到下层.

There are lots of real world examples for similar things in the Unix world (startx/X, git plumbing and porcelain), where one layer handles some options but propagates the rest to the lower layer.

开箱即用,这似乎不起作用.每个OptionParse.parse!调用都将进行详尽的处理,使所有未知的操作失败. 我想我很乐意跳过未知的选项.

Out of the box, this doesn't seem to work. Each OptionParse.parse! call will do exhaustive processing, failing on anything it doesn't know about. I guess I'd happy to skip unknown options.

任何提示,也许欢迎使用其他方法.

Any hints, perhaps alternative approaches are welcome.

推荐答案

假设解析器的运行顺序已明确定义,则只需将额外的选项存储在临时全局变量中,然后在每个集合上运行OptionParser#parse!选项.

Assuming the order in which the parsers will run is well defined, you can just store the extra options in a temporary global variable and run OptionParser#parse! on each set of options.

最简单的方法是使用像您提到的分隔符.假设第二个参数集与第一个参数集由定界符--隔开.然后,这将满足您的要求:

The easiest way to do this is to use a delimiter like you alluded to. Suppose the second set of arguments is separated from the first by the delimiter --. Then this will do what you want:

opts = OptionParser.new do |opts|
  # set up one OptionParser here
end

both_args = $*.join(" ").split(" -- ")
$extra_args = both_args[1].split(/\s+/)
opts.parse!(both_args[0].split(/\s+/))

然后,在第二个代码/上下文中,您可以执行以下操作:

Then, in the second code/context, you could do:

other_opts = OptionParser.new do |opts|
  # set up the other OptionParser here
end

other_opts.parse!($extra_args)

或者,这可能是做到这一点的更合适的"方法,您可以简单地使用OptionParser#parse,而没有感叹号,这不会从$*数组中删除命令行开关,并且确保在两个集合中没有定义相同的选项.我建议不要手工修改$*数组,因为如果只看第二部分,它会使您的代码更难理解,但是您可以可以做到这一点.在这种情况下,您将不得不忽略无效的选项:

Alternatively, and this is probably the "more proper" way to do this, you could simply use OptionParser#parse, without the exclamation point, which won't remove the command-line switches from the $* array, and make sure that there aren't options defined the same in both sets. I would advise against modifying the $* array by hand, since it makes your code harder to understand if you are only looking at the second part, but you could do that. You would have to ignore invalid options in this case:

begin
    opts.parse
rescue OptionParser::InvalidOption
    puts "Warning: Invalid option"
end


正如评论中指出的那样,第二种方法实际上不起作用.但是,如果您仍然必须修改$*数组,则可以执行以下操作:


The second method doesn't actually work, as was pointed out in a comment. However, if you have to modify the $* array anyway, you can do this instead:

tmp = Array.new

while($*.size > 0)
    begin
        opts.parse!
    rescue OptionParser::InvalidOption => e
        tmp.push(e.to_s.sub(/invalid option:\s+/,''))
    end
end

tmp.each { |a| $*.push(a) }

它有点不客气,但它应该做您想做的事.

It's more than a little bit hack-y, but it should do what you want.

这篇关于OptionParser可以跳过未知选项,以便稍后在Ruby程序中进行处理吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆