【问题标题】:How to cancel evaluating a required Ruby file? (a.k.a. top-level return)如何取消评估所需的 Ruby 文件? (又名顶级回报)
【发布时间】:2016-03-24 15:53:11
【问题描述】:

file1 需要file2,我希望能够在某些条件下取消评估file2 而无需退出整个过程。

# file1.rb
  puts "In file 1"
  require 'file2'
  puts "Back in file 1"

# file2.rb
  puts "In file 2"
  # return if some_conditional
  puts "Still in file 2"

运行file1时,我想看到的输出是:

In file 1
In file 2
Back in file 1

目标是Still in file 2 永远不会打印,而Back in file 1 会打印。 我可以在file2 做些什么来实现这一点?

我不能在这里使用exit/exit!/abort,因为Back in file 1 永远不会打印。我可以使用raise/fail,但要做到这一点,我必须更改file1rescue 失败的require。我希望找到一种不涉及更改file1的方法。

更新

一个“顶级回归”功能has been added

【问题讨论】:

  • 您可能已经提供了一个简化的示例来说明您的观点。可能如果您能告诉我们您想要达到的目标,那么,可能有人可以提供更好的帮助。至少,让我们避免任何XY problem
  • 这里没有 X 或 Y。我习惯于让 Ruby 做任何事情,但它不能做到这一点让我感到很奇怪。如果可能的话,我想知道如何。
  • 我认为这个问题没有很好地说明。正如 steenslag 的回答一样,您可以做任何事情来使 A 中的 A 之后的剩余部分不成为代码的一部分。那是微不足道的。将代码写入您不想执行的文件中似乎没有意义。 A之后的部分在任何情况下都可以执行吗?
  • 有一个 Ruby 问题讨论添加这样的功能:bugs.ruby-lang.org/issues/4840。目前我认为你只需要用条件将代码包装在所需的文件中。
  • @matt 感谢您的链接。这正是我正在寻找的讨论。

标签: ruby return exit abort raise


【解决方案1】:

__END__will not be executed 下面的行。

# file2.rb
puts "In file 2" 
__END__
puts "Still in file 2" # Never gets called

【讨论】:

  • 是的,它也不会被解析。
【解决方案2】:

更新

一个“顶级回归”功能has been added

原创

评论者matt 指出了功能 4840,它可以完全满足我的要求,has been in discussion since June 2011。此外,该功能是在核心团队会议上关于新 Ruby 功能的still being discussed as late as November 2015

设计这样的功能有很多困难;对于利弊列表,我强烈建议您查看讨论。

提议的功能将允许在使用以下任何顶级语句时退出所需的文件:

if condition
  return
end

while condition
  # ...
  return
end

begin
  # ...
  return
rescue
  # ...
  return
ensure
  # ...
  return
end

并且它不会在以下语句中退出所需的文件:

class Foo
  return # LocalJumpError
end

def foo
  return # returns from method, not from required file
end

proc do
  return # LocalJumpError
end

x = -> { return } # returns as from lambda, not from required file

由于该功能仍未实现,因此我已将赏金授予steenslag,以表彰其成功解决问题(如最初所写),如果不是精神的话。

【讨论】:

    【解决方案3】:

    我不知道破解所需文件的任何官方方法,特别是因为有几种 require 方法(例如,捆绑程序猴子补丁需要)

    我能想到的最佳解决方案是使用 ruby​​s throw-catch 控制流。我不确定您使用的条件来确定执行是否应该提前返回,但这应该能够应对大多数情况

    # file1.rb
    puts "In file 1" 
    catch(:done) do
        require 'file2' end
    puts "Back in file 1"
    
    # file2.rb
    puts "In file 2" 
    throw :done
    puts "Still in file 2" # Never gets called
    

    【讨论】:

    • 这会起作用,就像raise/rescue 会起作用一样。但是,理想情况下,不需要对 file1.rb 进行修改。
    【解决方案4】:

    是否可以使用方法?它仍然会解析该方法,但不会被执行。类似的东西:

    #file1.rb
      puts "In file 1"
      require 'file2'
      puts "Back in file 1"
      a_method
    
    #file2.rb
      puts "In file 2"
      # <= A
    
      def a_method
        puts "Still in file 2"
      end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-11
      • 2013-05-24
      • 2010-11-10
      • 1970-01-01
      • 2017-09-12
      相关资源
      最近更新 更多