【问题标题】:How to deal with not knowing what exceptions can be raised by a library method in Ruby?如何处理不知道 Ruby 中的库方法会引发哪些异常?
【发布时间】:2010-11-26 10:04:22
【问题描述】:

这是一个有点宽泛的问题,但它是我在使用 Ruby 编程时不断遇到的问题。我主要来自 C 和 Java 背景,当我使用库函数或方法时,我会查看文档并查看它在错误时返回什么(通常在 C 中)或它可以抛出哪些异常(在 Java 中)。

在 Ruby 中,情况似乎完全不同。刚才我需要解析一些从服务器接收到的 JSON:

data = JSON.parse(response)

当然,写完这段代码我首先想到的是,万一输入不好怎么办? parse 是否会在出错时返回 nil,或者引发一些异常,如果是,是哪些?

我查看了文档 (http://flori.github.com/json/doc/JSON.html#M000022) 并查看:

“将 JSON 字符串源解析为 Ruby 数据结构并返回。”

这只是我在 Ruby 中反复遇到的一个模式示例。最初,我认为这是我使用的任何库的文档的一些缺陷,但现在我开始觉得这是标准做法,而且我的心态与 Ruby 程序员有些不同。有什么我不知道的约定吗?

开发人员如何处理这个问题?

(是的,我确实查看了库方法的代码,并且可以了解引发了哪些异常,但我不能 100% 确定,如果没有记录,我依赖它会感到不舒服。)

编辑:看了前两个答案后,让我继续上面的 JSON 解析示例。

我怀疑我不应该这样做:

begin
  data = JSON.parse(response)
  raise "parse error" if data.nil?
rescue Exception => e
  # blahblah
end

因为我可以查看代码/测试并看到它似乎会在错误时引发 ParserError(返回 nil 似乎不是 Ruby 中的标准做法)。我是否正确地说推荐的做法是:

begin
  data = JSON.parse(response)
rescue JSON::ParserError => e
  # blahblah
end

...基于我通过查看代码和测试了解ParserError

(我还编辑了示例以澄清它是来自我正在解析的服务器的响应。)

【问题讨论】:

    标签: ruby exception exception-handling rescue


    【解决方案1】:

    (是的,我确实查看了库方法的代码,并且可以了解引发了哪些异常,但我不能 100% 确定,如果没有记录,我依赖它会感到不舒服。)

    我建议看一下测试,因为它们会显示一些“可能”的场景以及可能引发的问题。不要忘记,好的测试也是文档。

    【讨论】:

    • 同意,将您的输入数据的所有可能规范/测试写入您的方法,并开发您的应用程序来管理这些异常。
    • 这是一个好点,我从现在开始看测试。
    【解决方案2】:

    是否要丢弃无效的 JSON 数据:

    begin
      res = JSON.parse(string)
    rescue JSON::ParserError => e
      # string was not valid
    end
    

    【讨论】:

      【解决方案3】:

      我猜如果没有提供文档,你必须依赖这样的东西:

      begin
         # code goes here
      rescue
         # fail reason is in $!
      end
      

      【讨论】:

      • 这与 Preet Sangha 的回答 stackoverflow.com/a/1392459/2658159 基本相同。另外,您说“如果没有提供文档”,就好像没有文档是边缘情况一样。但实际上,即使在核心和标准库中,“没有文档”——或者至少是关于方法引发的特定异常的糟糕文档——也是常态。
      【解决方案4】:

      除非库代码捕获所有异常然后包装它们,否则您永远无法确定会引发哪些异常。最好的办法是通过清理输入的内容来假设代码中的良好输入,然后使用您自己的更高级别的异常处理来捕获输入中的错误输入。

      【讨论】:

      • 我不认为这是现实的。在这种特殊情况下,我正在解析来自服务器的响应。在服务器向我发送错误数据的罕见情况下,我希望至少能够优雅地失败并说出“服务器的错误响应”。
      • 在这种情况下,您需要从该方法中捕获一般异常,并使用适当的消息重新引发。
      【解决方案5】:

      您的问题基本上归结为两个问题:是否有用于查找可能的例外的约定或标准,以及与此类约定相关的文档在哪里?

      对于第一个问题,最接近约定或标准的是 exceptions.rb 文件的位置和存在。对于源代码公开可用的库或 gem,您通常可以在此文件中找到异常的类型。 (参考here)。

      如果源代码不可用或无法轻松访问,则文档是您的下一个最佳信息来源。这就引出了你的第二个问题。不幸的是,即使在标准库中,文档也没有关于潜在异常的一致格式。例如,Net::Http documentation 并没有明确指出哪些异常可用,但如果仔细研究,您会发现所有异常 inherit from Net::HTTPExceptions

      作为另一个示例(同样来自标准库文档),JSON documentation 显示了一个 Exception class(确实在 exceptions.rb 文件中,尽管在源代码中 json /lib/json/add/exceptions.rb)。这里的关键是它是不一致的。 Exception 类的文档没有以类似于 Net::HTTPException 的方式列出。

      此外,在大多数方法的文档中,并没有说明可能引发的异常。参考例如 parse,已经提到的 JSON 模块最常用的方法之一:根本没有提到异常。

      在核心模块中也发现缺乏标准和一致性。 Documentation for Math 不包含对 exceptions.rb 文件的任何引用。与File 及其父级IO 相同。

      等等,等等。

      网络搜索会找到很多关于如何 挽救异常的信息,甚至是多种类型的异常(参考 herehereherehere 等)。但是,这些都不能回答您的问题:what 是查找可以引发的异常的标准,where 是这方面的文档。

      作为最后一点,这里建议如果一切都失败了,你可以拯救StandardError。在许多情况下,这是一种不太理想的做法(参考 this SO answer),尽管我假设您已经根据您对 Java 的熟悉程度和您提出这个问题的方式理解了这一点。当然,来自 Java 世界的您需要记住 rescue StandardError and not Exception

      【讨论】:

      • fwiw 我正在添加这个答案,因为我也一直想知道同样的问题,来自 .NET 背景(类似于 Java),我在编写 Ruby 代码时遇到了同样的挫败感在旁边
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-23
      • 1970-01-01
      • 2012-02-24
      • 2021-05-22
      相关资源
      最近更新 更多