我可以有条件地跳过在同一个文件中加载“更多”红宝石代码吗?

Posted

技术标签:

【中文标题】我可以有条件地跳过在同一个文件中加载“更多”红宝石代码吗?【英文标题】:Can I conditionally skip loading "further" ruby code in the same file? 【发布时间】:2013-01-09 16:19:35 【问题描述】:

我可以有条件地跳过在同一个文件中加载“更多”ruby 代码吗? 如果找不到库(通过 require 加载)?

begin
  require 'aws-sdk'
rescue LoadError
  puts "aws-sdk gem not found"
  return #does not work. nor does next
end

# code after here should not be executed as `aws-sdk` gem was not found
puts "=== should not get executed"

namespace :db do
  desc "import local postgres database to heroku. user and database name is hardcoded"
  task :import_to_heroku => [:environment, "db:dump_for_heroku"] do
    # code using aws-sdk gem
  end
end

在上面的代码中,我可以要求 Ruby 之后不要再加载文件了吗? 击中rescue LoadError

类似于提前返回,但用于加载文件而非函数。

需要它,因为我有一个需要 aws-sdk ruby​​gem 的 rake 任务,但我只使用它 在我的本地机器上。如果没有找到aws-sdk,我以后在同一个文件中加载代码是没有意义的。我想我可以将代码拆分为较小的文件并将其变形 需要调用

if Rails.env.development?
  require 'import_to_heroku'
end

但不想扭曲或修改我现有的代码

另外,我可以将整个代码包装在一个条件中,但这并不优雅。 begin-rescue 块也是一种显式控制流。 我不想以任何方式包装或触摸原始代码

也许是一个 api,例如

require_or_skip_further_loading 'aws-ruby`

所以我希望我的代码在功能上等同于

begin
  require 'aws-sdk'

  namespace :db do
    desc "import local postgres database to heroku. user and database name is hardcoded"
    task :import_to_heroku => [:environment, "db:dump_for_heroku"] do
      # code using aws-sdk gem
    end
  end
rescue LoadError
  puts "aws-sdk gem not found"
end

或者通过 if 条件

library_found = false
begin
  require 'aws-sdk'
  library_found = true
rescue LoadError
  puts "aws-sdk gem not found"
  return #does not work
end

if library_found      
  namespace :db do
    desc "import local postgres database to heroku. user and database name is hardcoded"
    task :import_to_heroku => [:environment, "db:dump_for_heroku"] do
    # code using aws-sdk gem
    end
  end
end

希望在引发LoadError 后继续执行程序。 IE。优雅地处理LoadError 并且不要在同一文件中加载LoadError 之后编写的代码。不能在 LoadError 上引发 exitabort 尤其是 LoadError 之后的代码不应由 ruby​​ 解释器执行(或加载)

本来问How to skip require in ruby? 但我没有正确地问这个问题。希望这个措辞更好

【问题讨论】:

没有必要“跳过”文件的其余部分,反正已经“加载”了。在rescue LoadError 的情况下,您的代码将终止(使用return 或最好使用exit),Ruby 不会处理文件的其余部分。 @BernardK 谢谢。编辑了问题。希望它等同于将其包装在问题中所问的 begin-rescue 或 if-block 中。相关部分是。希望在引发LoadError 后继续执行程序。 IE。优雅地处理LoadError 并且不要在同一文件中加载LoadError 之后编写的代码。无法在 LoadError 上引发 exitabort 尤其是 LoadError 之后的代码不应由 ruby​​ 解释器执行(或加载) 这个文件是怎么加载的?我不认识瑞克。是require你的文件吗? 我认为这正在考虑用于 Ruby 2:bugs.ruby-lang.org/issues/4840。不过,我不知道是否有任何实现进入 Ruby 2 预览版。 How to cancel evaluating a required Ruby file?的可能重复 【参考方案1】:

“***回归”功能has been added。

现在可以在顶层使用return 关键字,如您的“通过 if 条件”示例。 Further discussion here.

【讨论】:

【参考方案2】:

我没有检查源代码,但我想,当您在控制台运行 ruby my_file.rb 或从 Ruby 代码运行 require/load 时,文件会在评估之前完全读入内存。恐怕没有跳过文件的一部分这样的事情。

我有一个关于接球/投球的想法。

需要文件(例​​如 Rake 任务?)treq1.rb :

catch :aws_sdk do
    require_relative 'original'
end

puts '... continued'

你不想修改的原始文件,original.rb:

puts 'in original, not to be modified'
begin
  require 'aws-sdk'
rescue LoadError
  puts "aws-sdk gem not found"
  throw :aws_sdk
end

puts ">>> to execute only if 'aws-sdk' is found"

# namespace :db do ... etc
#end

执行:

$ ruby -w treq1.rb 
in original, not to be modified
aws-sdk gem not found
treq1.rb:2:in `require_relative': method `backtrace' called on unexpected T_NODE object (0x007fd32b88e900 flags=0x381c klass=0x0) (NotImplementedError)
    from treq1.rb:2:in `block in <main>'
    from treq1.rb:1:in `catch'
    from treq1.rb:1:in `<main>'

谷歌搜索错误:http://www.ruby-forum.com/topic/4406870 最近的帖子,没有答案。如果您想包装代码,它可以在单个文件中工作。 让我们尝试另一种解决方案。假设您可以更改 Rake 任务,treq2.rb :

begin
    require_relative 'original'
rescue LocalJumpError
    puts 'rescued LocalJumpError'
end

puts '... continued'

在 original.rb 中,将 throw :aws_sdk 替换为 return

$ ruby -w treq2.rb 
in original, not to be modified
aws-sdk gem not found
rescued LocalJumpError
... continued

这样就可以了。 高温

【讨论】:

不理解第二个例子,即。使用LocalJumpError。我在第一个示例中没有收到任何错误。我正在使用 ruby​​ 1.9.3p327 您使用的是两个单独的文件吗?只有两个文件会出现错误。 实际上是的。实际代码(从您的示例中复制),输出位于gist.github.com/4644058。我正在使用 MRI ruby​​ 1.9.3p327(2012-11-10 修订版 37606)[x86_64-darwin10.8.0] Ruby 安装没有任何自定义补丁 我已经安装了 ruby​​-1.9.3-p362。现在带有 catch/throw 的版本分发到两个文件中,以及带有 return/rescue 的版本。那你现在快乐吗?是你要找的吗? @deepak 回答您的第一条评论:如果您使用return 运行ruby original.rb,而不是throw,错误in 'rescue in &lt;main&gt;': unexpected return (LocalJumpError),但如果另一个文件需要original.rb,我们可以捕获错误,挽救它并继续。

以上是关于我可以有条件地跳过在同一个文件中加载“更多”红宝石代码吗?的主要内容,如果未能解决你的问题,请参考以下文章

VBA - 如何有条件地跳过for循环迭代

如何有条件地跳过 Grails Spring Security 插件过滤器链中的 SecurityContextPersistenceFilter 过滤器

如何有条件地跳过python中for循环中的迭代步骤数?

在 clickhouse 中加载数据时跳过 csv 标头

在 Amazon Redshift Spectrum 中加载外部表时如何跳过最后几条记录?

在 QLabel 中加载图像