需要一个文件,它也是一个带有自己的选项解析器的程序

Requiring a file that is also a program with it's own option parser

我的问题是:所需文件拦截了选项解析器。

我正在用 3 个文件编写一个 ruby 程序,一个 (connect.rb) 处理与某个站点的连接,另外 2 个(populate.rb 和 update.rb) 需要第一个从该站点收集数据。

connect.rb可以运行配置和测试连接,如:

$ruby connect.rb --adduser myuser -p 1234 --test
Created user myuser
Connecting as myuser...
Connection test OK

另一方面,populate.rb 有一条 'require connect.rb' 行,但它也可以是 运行 并且有自己的选项。

以前connect.rb没有选项,一切正常,但是自从我用optparse向connect.rb添加选项后,populate.rb中的选项解析器和update.rb 不再工作了。如果我 运行 'ruby populate.rb -h',它会显示 connect.rb 可用的选项,而不是 populate.rb 中的可用选项。如果我使用 connect.rb 接受的选项,例如“-t”,则该选项的执行就像在 connect.rb 中一样。如果我使用 connect.rb 不接受但 populate.rb 应该接受的选项,它会显示 "invalid option" 错误并退出。

基本上,我希望 connect.rb 当我 运行 它单独运行时与我在另一个文件中需要它时表现不同。当我 运行 它独奏时,我希望它接受选项并做事;但是当它在另一个文件中需要时,我只希望方法可用,并且我想要一组不同的选项。

这可能吗?有没有办法告诉它是如何被调用的,或者有其他方法来防止选项拦截?我在所有文件中都使用 optparse。

我解决类似问题的方法是检查文件是否像这样 运行 独奏:

# connect.rb    

# wrap logic in a module
module Connect
  def self.run(args: ARGV)
    args # access to command line options
  end
end

# run if solo
Connect.run if [=10=] == __FILE__

最后一个条件 [=12=] 是一个 Ruby 全局设置为已执行文件的名称,__FILE__ 是当前文件的名称。如果两者相同,那么您知道该文件是 运行ning solo,即 ruby connect.rb

使用该设置,您可以 运行 connect.rb 单人游戏,而且效果很好。然后,当您在其他文件中需要它时 populate.rb 您需要明确 运行 它:

# popoulate.rb
require 'connect'
Connect.run ARGV.dup # dup the commandline options in case other files mutate them

希望对您有所帮助。

好吧,当我写下我的问题时,我意识到我知道一个答案!

基本上将 'require connect.rb' 行移动到 选项被解析之后。所以我的 populate.rb 现在是这样的:

require "optparse"
Version = 1.4

# Parses command line arguments
options = {}
optparse = OptionParser.new do |opts|
    # populate the options array according to the options
    ...
end

optparse.parse!

require "./connect_fb"

# start actual program
...

之所以可行,是因为我通过将选项存储在数组中将选项解析与大量代码分开,并且因为 connect.rb 如果在没有任何选项的情况下调用它,则不需要执行任何操作。我真的不明白为什么第一个调用的选项解析器是唯一有效的解析器。

我对离文件头部这么远的 'require' 行感到不舒服,所以我希望有更好的解决方案。

在测试了之前答案中的解决方案后,我得出了一个简单的解决方案:

您可以测试文件正在 运行 独奏

if [=10=] == __FILE__

所以我将所有解析放入一个 if 块中,如下所示:

# connect.rb
# code to be ran when required
...
class connect
    ....
end

# the following will only be executed if this script is ran solo
if [=11=] == __FILE__
    # code to be ran solo here
    ...
    # also parse options here
    options = {}
    optparse = OptionParser.new do |opts|
        ...
    end
    optparse.parse!
    # more code
    ...
 end

这个解决方案基本上是 diego 答案的准系统版本。