gpt4 book ai didi

ruby - OptionParser 可以跳过未知选项,以便稍后在 Ruby 程序中处理吗?

转载 作者:数据小太阳 更新时间:2023-10-29 06:41:20 26 4
gpt4 key购买 nike

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

例如:

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

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

用例是:

  1. 在一个松散耦合的前端程序中,各种组件都有不同的参数,我不希望“main”知道所有事情,只是将参数/选项集委托(delegate)给每个部分。

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

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

在 Unix 世界(startx/X、git plumbing 和 porcelain)中有很多类似事物的现实世界示例,其中一层处理一些选项,但将其余选项传播到较低层。

开箱即用,这似乎行不通。每个 OptionParse.parse! 调用都会进行详尽的处理,在它不知道的任何事情上失败。我想我很乐意跳过未知选项。

欢迎任何提示,也许还有其他方法。

最佳答案

我需要一个永远不会抛出 OptionParser::InvalidOption 的解决方案,并且在当前的答案中找不到一个优雅的解决方案。这个猴子补丁基于 other answers 之一但清理它并使其更像当前的 order! 语义。但请参阅下文,了解多 channel 选项解析固有的未解决问题。

class OptionParser
# Like order!, but leave any unrecognized --switches alone
def order_recognized!(args)
extra_opts = []
begin
order!(args) { |a| extra_opts << a }
rescue OptionParser::InvalidOption => e
extra_opts << e.args[0]
retry
end
args[0, 0] = extra_opts
end
end

就像 order! 一样工作,除了它不是抛出 InvalidOption,而是在 ARGV 中留下无法识别的开关。

RSpec 测试:

describe OptionParser do
before(:each) do
@parser = OptionParser.new do |opts|
opts.on('--foo=BAR', OptionParser::DecimalInteger) { |f| @found << f }
end
@found = []
end

describe 'order_recognized!' do
it 'finds good switches using equals (--foo=3)' do
argv = %w(one two --foo=3 three)
@parser.order_recognized!(argv)
expect(@found).to eq([3])
expect(argv).to eq(%w(one two three))
end

it 'leaves unknown switches alone' do
argv = %w(one --bar=2 two three)
@parser.order_recognized!(argv)
expect(@found).to eq([])
expect(argv).to eq(%w(one --bar=2 two three))
end

it 'leaves unknown single-dash switches alone' do
argv = %w(one -bar=2 two three)
@parser.order_recognized!(argv)
expect(@found).to eq([])
expect(argv).to eq(%w(one -bar=2 two three))
end

it 'finds good switches using space (--foo 3)' do
argv = %w(one --bar=2 two --foo 3 three)
@parser.order_recognized!(argv)
expect(@found).to eq([3])
expect(argv).to eq(%w(one --bar=2 two three))
end

it 'finds repeated args' do
argv = %w(one --foo=1 two --foo=3 three)
@parser.order_recognized!(argv)
expect(@found).to eq([1, 3])
expect(argv).to eq(%w(one two three))
end

it 'maintains repeated non-switches' do
argv = %w(one --foo=1 one --foo=3 three)
@parser.order_recognized!(argv)
expect(@found).to eq([1, 3])
expect(argv).to eq(%w(one one three))
end

it 'maintains repeated unrecognized switches' do
argv = %w(one --bar=1 one --bar=3 three)
@parser.order_recognized!(argv)
expect(@found).to eq([])
expect(argv).to eq(%w(one --bar=1 one --bar=3 three))
end

it 'still raises InvalidArgument' do
argv = %w(one --foo=bar)
expect { @parser.order_recognized!(argv) }.to raise_error(OptionParser::InvalidArgument)
end

it 'still raises MissingArgument' do
argv = %w(one --foo)
expect { @parser.order_recognized!(argv) }.to raise_error(OptionParser::MissingArgument)
end
end
end

问题:通常 OptionParser 允许缩写选项,前提是有足够的字符来唯一标识预期的选项。在多个阶段解析选项打破了这一点,因为 OptionParser 在第一遍中看不到所有可能的参数。例如:

describe OptionParser do
context 'one parser with similar prefixed options' do
before(:each) do
@parser1 = OptionParser.new do |opts|
opts.on('--foobar=BAR', OptionParser::DecimalInteger) { |f| @found_foobar << f }
opts.on('--foo=BAR', OptionParser::DecimalInteger) { |f| @found_foo << f }
end
@found_foobar = []
@found_foo = []
end

it 'distinguishes similar prefixed switches' do
argv = %w(--foo=3 --foobar=4)
@parser1.order_recognized!(argv)
expect(@found_foobar).to eq([4])
expect(@found_foo).to eq([3])
end
end

context 'two parsers in separate passes' do
before(:each) do
@parser1 = OptionParser.new do |opts|
opts.on('--foobar=BAR', OptionParser::DecimalInteger) { |f| @found_foobar << f }
end
@parser2 = OptionParser.new do |opts|
opts.on('--foo=BAR', OptionParser::DecimalInteger) { |f| @found_foo << f }
end
@found_foobar = []
@found_foo = []
end

it 'confuses similar prefixed switches' do
# This is not generally desirable behavior
argv = %w(--foo=3 --foobar=4)
@parser1.order_recognized!(argv)
@parser2.order_recognized!(argv)
expect(@found_foobar).to eq([3, 4])
expect(@found_foo).to eq([])
end
end
end

关于ruby - OptionParser 可以跳过未知选项,以便稍后在 Ruby 程序中处理吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3642331/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com