Class: SampleManifestExcel::Upload::Data

Inherits:
Object
  • Object
show all
Includes:
ActiveModel::Model, Enumerable, Converters
Defined in:
app/sample_manifest_excel/sample_manifest_excel/upload/data.rb

Overview

An object to store the data for a particular manifest upload. The data is split into a header row (column names) and the actual data.

Constant Summary collapse

SANGER_SAMPLE_ID_COLUMN_LABEL =
'SANGER SAMPLE ID'

Constants included from Converters

Converters::BLANK_CHARS, Converters::BLANK_CHARS_REGEXP

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Converters

#strip_all_blanks

Constructor Details

#initialize(file) ⇒ Data

The file is opened as a Roo spreadsheet. If it is valid it is split by the start row. Start row of column headers and data put into separate rows.



29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'app/sample_manifest_excel/sample_manifest_excel/upload/data.rb', line 29

def initialize(file) # rubocop:todo Metrics/MethodLength
  @file = file
  @file_errors = nil
  @sheet = read_sheet
  @start_row = find_start_row
  return if @start_row.nil?

  @header_row = sheet&.row(@start_row)
  @data = sheet&.drop(@start_row)
  @description_info = extract_description_info(sheet, @start_row)
ensure
  @header_row ||= []
  @data ||= []
end

Instance Attribute Details

#dataObject (readonly)

Returns the value of attribute data.



13
14
15
# File 'app/sample_manifest_excel/sample_manifest_excel/upload/data.rb', line 13

def data
  @data
end

#description_infoObject (readonly)

Returns the value of attribute description_info.



13
14
15
# File 'app/sample_manifest_excel/sample_manifest_excel/upload/data.rb', line 13

def description_info
  @description_info
end

#fileObject (readonly)

Returns the value of attribute file.



13
14
15
# File 'app/sample_manifest_excel/sample_manifest_excel/upload/data.rb', line 13

def file
  @file
end

#header_rowObject (readonly)

Returns the value of attribute header_row.



13
14
15
# File 'app/sample_manifest_excel/sample_manifest_excel/upload/data.rb', line 13

def header_row
  @header_row
end

#sheetObject (readonly)

Returns the value of attribute sheet.



13
14
15
# File 'app/sample_manifest_excel/sample_manifest_excel/upload/data.rb', line 13

def sheet
  @sheet
end

#start_rowObject (readonly)

Returns the value of attribute start_row.



13
14
15
# File 'app/sample_manifest_excel/sample_manifest_excel/upload/data.rb', line 13

def start_row
  @start_row
end

Instance Method Details

#cell(row, column) ⇒ Object

Find a cell of data based on the column and row



56
57
58
59
# File 'app/sample_manifest_excel/sample_manifest_excel/upload/data.rb', line 56

def cell(row, column)
  val = data.try(:fetch, row - 1).try(:fetch, column - 1)
  strip_all_blanks(val)
end

#column(col_num) ⇒ Object

Return a column of data for a particular column number



63
64
65
66
67
68
# File 'app/sample_manifest_excel/sample_manifest_excel/upload/data.rb', line 63

def column(col_num)
  data.map do |row|
    val = row[col_num - 1]
    strip_all_blanks(val)
  end
end

#eachObject



44
45
46
# File 'app/sample_manifest_excel/sample_manifest_excel/upload/data.rb', line 44

def each(&)
  data.each(&)
end

#extract_description_info(sheet, start_row) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'app/sample_manifest_excel/sample_manifest_excel/upload/data.rb', line 100

def extract_description_info(sheet, start_row)
  # look through each row starting from from under the heading (row 2), to above the start row
  # build a hash of the value in the first column => value in second column
  # this was built to extract the tube rack barcodes, and assumes the label is in the first column and the value
  # in the second
  return nil if sheet.nil? || start_row.nil?

  output = {}
  (2..start_row - 1).each do |row_num|
    row = sheet.row(row_num)
    info_label = row[0]
    info_value = row[1]
    output[info_label] = info_value unless info_label.nil?
  end
  output
end

#file_errors_emptyObject



82
83
84
# File 'app/sample_manifest_excel/sample_manifest_excel/upload/data.rb', line 82

def file_errors_empty
  errors.add(:file, @file_errors) if @file_errors.present?
end

#file_extensionObject



48
49
50
51
52
# File 'app/sample_manifest_excel/sample_manifest_excel/upload/data.rb', line 48

def file_extension
  return nil if file.nil?

  File.extname(file.path)
end

#find_start_rowObject



90
91
92
93
94
95
96
97
98
# File 'app/sample_manifest_excel/sample_manifest_excel/upload/data.rb', line 90

def find_start_row
  return nil if sheet.nil?

  (0..sheet.last_row).each do |row_num|
    sheet.row(row_num).each { |cell_value| return row_num if cell_value == SANGER_SAMPLE_ID_COLUMN_LABEL }
  end

  nil
end

#inspectObject



86
87
88
# File 'app/sample_manifest_excel/sample_manifest_excel/upload/data.rb', line 86

def inspect
  "<#{self.class}: @header_row=#{header_row}, @data=#{data}, @start_row=#{@start_row}, @file=#{file}>"
end

#read_sheetObject



70
71
72
73
74
75
76
77
78
79
80
# File 'app/sample_manifest_excel/sample_manifest_excel/upload/data.rb', line 70

def read_sheet
  return nil if file.nil?

  Roo::Spreadsheet.open(file).sheet(0)
  # In production we see a variety of errors here, all of which indicate problems with the manifest
rescue StandardError => e
  # We store the errors in an instance variable, as otherwise they get lost on any subsequent
  # calls to #valid?
  @file_errors = "could not be read: #{e.message}"
  nil
end