如何在未安装gem时从require"gem_name"进行救援

All*_*rgi 11 ruby rubygems

我正在写一个依赖于特定宝石的库.我需要宝石并在我的代码中使用它,只要宝石安装在用户的机器上,所有东西都是hunky-dory.但如果不是这样呢?!

我认为这很好,因为我可以从require命令中解救并向输出打印一条消息,告知用户缺少的宝石并优雅地完成它但我收到错误!

你能告诉我应该怎么做或这段代码有什么问题:

begin 
 require "some_gem"
rescue
 puts "please install some_gem first!" 
end
Run Code Online (Sandbox Code Playgroud)

Jör*_*tag 35

requireLoadError如果无法加载所需的库,则会引发异常.然而,你永远不会LoadError任何地方营救,你从救援StandardError.

如果你想拯救LoadError,你必须这样说:

begin 
  require 'some_gem'
rescue LoadError
  puts 'please install some_gem first!'
end
Run Code Online (Sandbox Code Playgroud)

更好的是,确保您实际上正在打印正确的缺失依赖项:

begin 
  require 'some_gem'
rescue LoadError => e
  raise unless e.message =~ /some_gem/
  puts 'please install some_gem first!'
end
Run Code Online (Sandbox Code Playgroud)

(这会重新引发从中获取的完全相同的异常,如果异常实际上是由其他地方的其他一些丢失的库引起的.你不想打印误导信息,对吗?)

根据库的预期目标受众是什么以及它们是否可能被转储到控制台的回溯吓跑,您可能想要在任何情况下重新引发异常,而不是仅仅吞下它:

begin 
  require 'some_gem'
rescue LoadError => e
  puts 'please install some_gem first!' if e.message =~ /some_gem/
  raise
end
Run Code Online (Sandbox Code Playgroud)

或者,您可以跳过puts,而是将消息设置为您要说的内容而引发异常:

begin 
  require 'some_gem'
rescue LoadError => e
  raise e.exception('please install some_gem first!') if e.message =~ /some_gem/
  raise
end
Run Code Online (Sandbox Code Playgroud)

除非现在异常在错误的位置引发,因此具有错误的行号和堆栈跟踪,因此具有误导性,但这很容易修复:

begin 
  require 'some_gem'
rescue LoadError => e
  raise unless e.message =~ /some_gem/
  friendly_ex = e.exception('please install some_gem first!')
  friendly_ex.set_backtrace(e.backtrace)
  raise friendly_ex
end
Run Code Online (Sandbox Code Playgroud)

现在你打印的内容几乎与你用它打印的相同puts,但是你有一个"正确的"例外,例如允许更好的调试或允许你的库的消费者拯救那个异常并按照他们的方式处理它们,这两者都是对你的解决方案只是吞下异常本来是不可能的,或者至少是困难的.