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

dee*_*pak 5 ruby rubygems require


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

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
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,我可以要求 Ruby 在点击 rescue LoadError.

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

需要它,因为我有一个需要aws-sdkruby​​gem 的 rake 任务,但我仅在本地计算机上使用它。如果aws-sdk找不到,那么我之后在同一个文件中加载代码就没有意义。我想我可以将代码分割成更小的文件并在 require 调用中扭曲它

if Rails.env.development?
  require 'import_to_heroku'
end
Run Code Online (Sandbox Code Playgroud)

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

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

也许是一个 api,比如

require_or_skip_further_loading 'aws-ruby`
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

或者通过 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
Run Code Online (Sandbox Code Playgroud)

LoadError希望程序在引发后继续执行。IE。优雅地处理LoadError并且不加载LoadError在同一文件中写入的代码。不能 raiseexit或abortonLoadError特别是后面的代码LoadError不应由 ruby​​ 解释器执行(或加载)

最初问过如何在 ruby​​ 中跳过 require? 但我没有正确地提出问题。希望措辞更好

Ber*_*rdK 3

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

我有一个关于捕捉/抛出的想法。

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

catch :aws_sdk do
    require_relative 'original'
end

puts '... continued'
Run Code Online (Sandbox Code Playgroud)

您不想修改的原始文件,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
Run Code Online (Sandbox Code Playgroud)

执行 :

$ 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>'
Run Code Online (Sandbox Code Playgroud)

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

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

puts '... continued'
Run Code Online (Sandbox Code Playgroud)

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

$ ruby -w treq2.rb 
in original, not to be modified
aws-sdk gem not found
rescued LocalJumpError
... continued
Run Code Online (Sandbox Code Playgroud)

这样就可以了。
华泰