Существуют различные и все идиоматические способы достижения этого:
На уровне источника (передавая массив заголовков)
Вы можете использовать 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
Лямбда позволит вызывающей стороне определить ихсобственные проверки, повышение при необходимости и т. д., что лучше для повторного использования.
На уровне преобразования
Если вы хотите дополнительно отделить компоненты (например, отделить обработку заголовков от факта, что строки приходятиз источника 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
.Это лучший дизайн, гарантирующий, что ввод-вывод будет происходить только при вызове Kiba.run
(так как он будет более ориентирован на будущее и будет поддерживать функции самоанализа в более поздних версиях Kiba).
Также с использованием pre_process
не рекомендуется (хотя это будет работать), потому что это приведет к небольшому дублированию и т. д.
Надеюсь, это поможет, и дайте мне знать, если это не ясно!