我需要检查一下:
标题行存在标头包含一组特定的标头
这是最好的地方。我有一些可能的解决方案,但不知道更惯用的解决方案
检查一下
有各种各样的&所有非常惯用的方法来实现这一目标:
您可以使用 CSV 无 headers: true ,提供精细检查标题的机会:
CSV
headers: true
class CSVSource def initialize(filename:, csv_options:, expected_headers:) # SNIP def each CSV.foreach(filename, csv_options).with_index do |row, file_row_index| if file_row_index == 0 check_headers!(actual: row.to_a, expected: expected_headers) next # do not propagate the headers row else yield(Hash[expected_headers.zip(row.to_a)]) end end end def check_headers!(actual:, expected:) # SNIP - verify uniqueness, presence, raise a clear message if needed end
class CSVSource def initialize(after_headers_read_callback:, ...) @after_headers_read_callback = ... def each CSV.foreach(filename, csv_options).with_index do |row, file_row_index| if file_row_index == 0 @after_headers_read_callback.call(row.to_a) next end # ... end end
lambda将让调用者定义自己的检查,如果需要则提升等,这样可以更好地重用。
如果您想进一步解耦组件(例如,将标题处理与行来自CSV源的事实分开),您可以使用转换。
我通常使用这种设计,它允许更好的重用(这里有一个CSV源,它会产生一些元数据):
def transform_array_rows_to_hash_rows(after_headers_read_callback:) transform do |row| if row.fetch(:file_row_index) == 0 @headers = row.fetch(:row) after_headers_read_callback.call(@headers) nil else Hash[@headers.zip(row.fetch(:row))].merge( filename: row.fetch(:filename), file_row_index: row.fetch(:file_row_index) ) end end end
在所有情况下,避免进行任何处理 Kiba.parse 本身。这是一个更好的设计,以确保IO只会在您打电话时发生 Kiba.run (因为它将更加面向未来,并将支持更高版本的Kiba中的内省功能)。
Kiba.parse
Kiba.run
另外,使用 pre_process 不推荐(虽然它会起作用),因为它会导致一些重复等。
pre_process
希望这会有所帮助,如果不清楚,请告诉我!