Class: Parsers::BioanalysisCsvParser

Inherits:
Object
  • Object
show all
Defined in:
app/models/parsers/bioanalysis_csv_parser.rb

Overview

rubocop:todo Metrics/ClassLength

Defined Under Namespace

Classes: InvalidFile

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(content) ⇒ BioanalysisCsvParser

Returns a new instance of BioanalysisCsvParser.



14
15
16
# File 'app/models/parsers/bioanalysis_csv_parser.rb', line 14

def initialize(content)
  @content = content
end

Instance Attribute Details

#contentObject (readonly)

Returns the value of attribute content.



12
13
14
# File 'app/models/parsers/bioanalysis_csv_parser.rb', line 12

def content
  @content
end

Class Method Details

.parses?(content) ⇒ Boolean

Returns:

  • (Boolean)


148
149
150
151
# File 'app/models/parsers/bioanalysis_csv_parser.rb', line 148

def self.parses?(content)
  # We don't go through the whole file
  content[0..10].detect { |line| line[0]&.include?('Version Created') && /^B.*/ === line[1] }.present?
end

Instance Method Details

#build_range(range) ⇒ Object



44
45
46
47
48
# File 'app/models/parsers/bioanalysis_csv_parser.rb', line 44

def build_range(range)
  range = range.nil? ? [0, content.length - 1] : range.dup
  range.push(content.length - 1) if (range.length == 1)
  range
end

#concentration(plate_position) ⇒ Object



22
23
24
# File 'app/models/parsers/bioanalysis_csv_parser.rb', line 22

def concentration(plate_position)
  get_parsed_attribute(plate_position, field_name_for(:concentration))
end

#each_well_and_parametersObject



136
137
138
139
140
141
142
143
144
145
146
# File 'app/models/parsers/bioanalysis_csv_parser.rb', line 136

def each_well_and_parameters
  parsed_content.each do |well, values|
    yield(
      well,
      {
        'concentration' => Unit.new(values[:peak_table][field_name_for(:concentration)], 'ng/ul'),
        'molarity' => Unit.new(values[:peak_table][field_name_for(:molarity)], 'nmol/l')
      }
    )
  end
end

#field_name_for(sym_name) ⇒ Object



18
19
20
# File 'app/models/parsers/bioanalysis_csv_parser.rb', line 18

def field_name_for(sym_name)
  { concentration: 'Conc. [ng/µl]', molarity: 'Molarity [nmol/l]' }[sym_name]
end

#get_group_content(group) ⇒ Object

rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity



81
82
83
# File 'app/models/parsers/bioanalysis_csv_parser.rb', line 81

def get_group_content(group)
  content.slice(group[0], group[1] - group[0] + 1)
end

#get_groups(regexp, range = nil) ⇒ Object

Finds groups of lines by range in which the beginning of the range contains the matching regexp as text in the first column and the end of the range is an empty line - regexp -> Regular expression to be matched in the first column as beginning of range - range -> In case it is specified, restricts the searching process to this range of lines instead of using all the content of the CSV file rubocop:todo Metrics/PerceivedComplexity, Metrics/MethodLength, Metrics/AbcSize



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'app/models/parsers/bioanalysis_csv_parser.rb', line 56

def get_groups(regexp, range = nil) # rubocop:todo Metrics/CyclomaticComplexity
  groups = []
  group = []
  range = build_range(range)

  group_contents = get_group_content(range)

  group_contents.each_with_index do |line, pos|
    if line[0].present? && line[0].match(regexp) && group.empty?
      group.push(pos)
    elsif line.empty? && group.one?
      group.push(pos - 1)
    end

    if group.length == 2
      groups.push [group[0] + range[0], group[1] + range[0]]
      group = []
    end
    groups.push [group[0] + range[0], pos + range[0]] if (group.length == 1) && (pos == (group_contents.length - 1))
  end
  groups
end

#get_parsed_attribute(plate_position, field) ⇒ Object



130
131
132
133
134
# File 'app/models/parsers/bioanalysis_csv_parser.rb', line 130

def get_parsed_attribute(plate_position, field)
  return nil if parsed_content.nil? || parsed_content[plate_position].nil?

  parsed_content[plate_position][:peak_table][field]
end

#molarity(plate_position) ⇒ Object



26
27
28
# File 'app/models/parsers/bioanalysis_csv_parser.rb', line 26

def molarity(plate_position)
  get_parsed_attribute(plate_position, field_name_for(:molarity))
end

#parse_cell(group) ⇒ Object



98
99
100
# File 'app/models/parsers/bioanalysis_csv_parser.rb', line 98

def parse_cell(group)
  get_group_content(group)[0][1]
end

#parse_overall(group) ⇒ Object



93
94
95
96
# File 'app/models/parsers/bioanalysis_csv_parser.rb', line 93

def parse_overall(group)
  # Number of peaks
  get_group_content(get_groups(/Overall.*/m, group)[0])[1][1]
end

#parse_peak_table(group) ⇒ Object



85
86
87
# File 'app/models/parsers/bioanalysis_csv_parser.rb', line 85

def parse_peak_table(group)
  table_content_hash(get_groups(/Peak Table/m, group)[0])
end

#parse_region_table(group) ⇒ Object



89
90
91
# File 'app/models/parsers/bioanalysis_csv_parser.rb', line 89

def parse_region_table(group)
  table_content_hash(get_groups(/Region Table/m, group)[0])
end

#parse_sample(group) ⇒ Object



102
103
104
105
106
107
108
109
110
# File 'app/models/parsers/bioanalysis_csv_parser.rb', line 102

def parse_sample(group)
  {
    parse_cell(group) => {
      peak_table: parse_peak_table(group),
      region_table: parse_region_table(group),
      overall: parse_overall(group)
    }
  }
end

#parse_samplesObject



112
113
114
115
116
117
118
119
120
121
122
# File 'app/models/parsers/bioanalysis_csv_parser.rb', line 112

def parse_samples
  groups = get_groups(/Sample Name/)

  groups
    .each_with_index
    .map do |group, pos|
      next_index = pos == (groups.length - 1) ? @content.length - 1 : groups[pos + 1][0] - 1
      [group[0], next_index]
    end
    .reduce({}) { |memo, group| memo.merge(parse_sample group) }
end

#parsed_contentObject



124
125
126
127
128
# File 'app/models/parsers/bioanalysis_csv_parser.rb', line 124

def parsed_content
  @parsed_content ||= parse_samples
rescue NoMethodError => e # Ugh! I want to catch these where they happen
  raise InvalidFile
end

#table_content_hash(group) ⇒ Object

rubocop:todo Metrics/AbcSize



30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'app/models/parsers/bioanalysis_csv_parser.rb', line 30

def table_content_hash(group) # rubocop:todo Metrics/AbcSize
  content_hash = {}
  starting_line = group[0]
  ending_line = group[1]
  type = content[starting_line][0]
  fields = content[starting_line + 1]

  ((starting_line + 2)..(ending_line)).each do |pos|
    values = content[pos]
    content_hash.merge!(fields.zip(values).to_h) unless values.nil? && (values.length != fields.length)
  end
  content_hash
end