为什么CSV :: HeaderConverters在返回非String时停止处理?

时间:2016-06-23 19:01:21

标签: ruby csv

为什么header converters的处理会因为从标头转换器返回的第一个非String而停止?

详细

触发内置:symbol标头转换器后,不会处理其他转换器。似乎第一个转换器处理标头转换器停止,返回任何不是String的转换器(如果您编写一个返回Fixnum的自定义标头转换器,则行为相同,或其他任何事情)。

此代码按预期工作,在:throw_an_exception

中抛出异常
require 'csv'

CSV::HeaderConverters[:throw_an_exception] = lambda do |header|
  raise 'Exception triggered.'
end

csv_str = "Numbers\n" +
          "1\n" +
          "4\n" +
          "7"

puts CSV.parse(
  csv_str,
  {
    headers: true,
    header_converters: [
      :throw_an_exception,
      :symbol
    ]
  }
)

但是,如果您切换标头转换器的顺序以便:symbol转换器首先出现,则永远不会调用:throw_an_exception lambda。

...

header_converters: [
  :symbol,
  :throw_an_exception
]

...

2 个答案:

答案 0 :(得分:2)

所以我联系了JEG2

我当时认为转换器应该是链中的一系列步骤,其中所有元素都应该通过每个步骤。事实上,这不是最好地使用CSV库的方法,特别是如果你有非常大量的数据。

它应该被使用的方式(这是“为什么”问题的答案解释为什么这对性能更好)是让转换器像一系列匹配器一样工作,第一个匹配的转换器返回非String,向CSV库指示当前值已成功转换。当你这样做时,解析器可以在非String时立即停止,然后转到下一个标题/单元格值。

通过这种方式,您可以在解析CSV数据时删除TON的开销。您正在处理的文件越大,消除的开销就越大。

以下是我收到的电子邮件回复:

  

...

     

转换器基本上是一个尝试转换的管道。假设您使用的是两个转换器,一个用于日期,另一个用于数字。如果没有链接线,我们会为每个字段都尝试。但是,我们知道几件事:

     
      
  • 未转换的CSV字段为String,因为这是我们在
  • 中阅读的方式   
  • 现在为非String的字段已被转换,因此我们可以停止搜索匹配的转换器。
  •   
     

鉴于此,如果我们已经拥有Date对象,则优化有助于我们的示例跳过检查数字转换器。

     

...

答案 1 :(得分:1)

由于未知原因CSV#convert_fields功能有一个搞笑

break unless field.is_a? String # short-circuit pipeline for speed

converters.each行。我怀疑我能提出比monkeypatching这个功能更好的建议,但现在原因很清楚了。