Class: Miscellany::BatchingCsvProcessor

Inherits:
Object
  • Object
show all
Defined in:
lib/miscellany/batching_csv_processor.rb

Defined Under Namespace

Classes: RowError

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(csv, file_name: nil) ⇒ BatchingCsvProcessor

Returns a new instance of BatchingCsvProcessor.



9
10
11
12
# File 'lib/miscellany/batching_csv_processor.rb', line 9

def initialize(csv, file_name: nil)
  @csv = csv
  @file_name = file_name
end

Instance Attribute Details

#csvObject

Returns the value of attribute csv.



5
6
7
# File 'lib/miscellany/batching_csv_processor.rb', line 5

def csv
  @csv
end

#file_nameObject

Returns the value of attribute file_name.



5
6
7
# File 'lib/miscellany/batching_csv_processor.rb', line 5

def file_name
  @file_name
end

Class Method Details

.file_matches?(file) ⇒ Boolean

Returns:

  • (Boolean)


78
79
80
81
82
# File 'lib/miscellany/batching_csv_processor.rb', line 78

def self.file_matches?(file)
  header = file.readline.strip.split(',')
  file.try(:rewind)
  headers_match?(header)
end

.headers_match?(headers) ⇒ Boolean

Returns:

  • (Boolean)


84
85
86
# File 'lib/miscellany/batching_csv_processor.rb', line 84

def self.headers_match?(headers)
  (self::HEADERS - headers).empty?
end

Instance Method Details

#apply_row_to_model(_row, _instance) ⇒ Object

Raises:

  • (NotImplementedError)


31
32
33
# File 'lib/miscellany/batching_csv_processor.rb', line 31

def apply_row_to_model(_row, _instance)
  raise NotImplementedError
end

#batch_rows_to_models(rows) ⇒ Object



49
50
51
# File 'lib/miscellany/batching_csv_processor.rb', line 49

def batch_rows_to_models(rows)
  rows.map { |row| build_model_from_row(row) }.reject { |inst| inst.nil? || !inst.changed? }
end

#build_model_from_row(row) ⇒ Object



53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/miscellany/batching_csv_processor.rb', line 53

def build_model_from_row(row)
  model = find_or_init(row)
  apply_row_to_model(row, model)
  return nil if model.respond_to?(:discarded_at) && model.discarded_at.present? && !model.persisted?

  model
rescue ActiveRecord::RecordNotFound, RowError => err
  log_line_error(err.message, row[:line_number], exception: err)
  nil
rescue StandardError => err
  log_line_error('An Internal Error Occurred', row[:line_number], exception: err)
  Raven.capture_exception(err) if defined?(Raven)
  nil
end

#find_or_init(_row) ⇒ Object

Raises:

  • (NotImplementedError)


27
28
29
# File 'lib/miscellany/batching_csv_processor.rb', line 27

def find_or_init(_row)
  raise NotImplementedError
end

#get_row_errors(row) ⇒ Object



25
# File 'lib/miscellany/batching_csv_processor.rb', line 25

def get_row_errors(row); end

#log_line_error(message, line_number, **kwargs) ⇒ Object

Raises:

  • (NotImplementedError)


35
36
37
# File 'lib/miscellany/batching_csv_processor.rb', line 35

def log_line_error(message, line_number, **kwargs)
  raise NotImplementedError
end

#map_defined_columns(row, map) ⇒ Object



68
69
70
71
72
73
74
75
76
# File 'lib/miscellany/batching_csv_processor.rb', line 68

def map_defined_columns(row, map)
  newh = {}
  map.each do |newk, oldk|
    next unless row.include?(oldk)

    newh[newk] = row[oldk]
  end
  newh
end

#process_in_batches(&blk) ⇒ Object



14
15
16
17
18
19
20
21
22
23
# File 'lib/miscellany/batching_csv_processor.rb', line 14

def process_in_batches(&blk)
  batch = BatchProcessor.new(&blk)
  CSV.new(csv, headers: true, header_converters: :symbol).each.with_index do |row, line|
    row[:line_number] = line + 1
    next unless validate_line(row)

    batch << row
  end
  batch.flush
end

#validate_line(row) ⇒ Object



39
40
41
42
43
44
45
46
47
# File 'lib/miscellany/batching_csv_processor.rb', line 39

def validate_line(row)
  errors = get_row_errors(row) || []
  if errors.present?
    log_line_error(errors[0], row[:line_number])
    false
  else
    true
  end
end