Module: WellSorterService

Defined in:
app/services/well_sorter_service.rb

Overview

Derived from github.com/sanger/code_snippets/blob/main/ruby/well_helpers.rb Provides tools for dealing with well ranges

Constant Summary collapse

COLUMNS_RANGE =
{ 96 => (1..12), 384 => (1..24) }.freeze
ROWS_RANGE =
{ 96 => ('A'..'H'), 384 => ('A'..'P') }.freeze

Class Method Summary collapse

Class Method Details

.column_order(size = 96) ⇒ Array

Returns an array of all well names in column order

Returns:

  • (Array)

    well names in column order ie. A1, B1, C1 …



21
22
23
24
25
# File 'app/services/well_sorter_service.rb', line 21

def self.column_order(size = 96)
  columns_range(size).each_with_object([]) do |c, wells|
    rows_range(size).each { |r| wells << "#{r}#{c}" }
  end.freeze
end

.columns_range(size) ⇒ Object



10
11
12
# File 'app/services/well_sorter_service.rb', line 10

def self.columns_range(size)
  COLUMNS_RANGE.fetch(size)
end

.first_and_last_in_columns(wells) ⇒ Array<string>

Extracts the first and last well (as sorted in column order) from the array

Parameters:

  • wells (Array<String>)

    Array of well names to sort

Returns:

  • (Array<string>)

    [‘first_well_name’,‘last_well_name’]



110
111
112
113
# File 'app/services/well_sorter_service.rb', line 110

def self.first_and_last_in_columns(wells)
  sorted = sort_in_column_order(wells)
  [sorted.first, sorted.last]
end

.formatted_range(wells, size = 96) ⇒ String

Compacts the provided well range into an easy to read summary. e.g.. formatted_range([‘A1’, ‘B1’, ‘C1’,‘A2’,‘A5’,‘B5’]) => ‘A1-C1,A2,A5-B5’ Mostly this will just be start_well-end_well

Parameters:

  • wells (Array<String>)

    Array of well names to format

Returns:

  • (String)

    A name describing the range



96
97
98
99
100
101
# File 'app/services/well_sorter_service.rb', line 96

def self.formatted_range(wells, size = 96)
  sort_in_column_order(wells)
    .slice_when { |prev, nxt| index_of(nxt, size) - index_of(prev, size) > 1 }
    .map { |range| [range.first, range.last].uniq.join('-') }
    .join(', ')
end

.index_of(well, size = 96) ⇒ Int

Returns the index of the well by column

Parameters:

  • well (String)

    The well name eg. A1

Returns:

  • (Int)

    the index, eg. 0



50
51
52
53
# File 'app/services/well_sorter_service.rb', line 50

def self.index_of(well, size = 96)
  column_order(size).index(well) ||
    raise("Unknown well #{well} on plate of size 96")
end

.row_order(size = 96) ⇒ Array

Returns an array of all well names in row order

Returns:

  • (Array)

    well names in column order ie. A1, A2, A3 …



30
31
32
33
34
# File 'app/services/well_sorter_service.rb', line 30

def self.row_order(size = 96)
  rows_range(size).each_with_object([]) do |r, wells|
    columns_range(size).each { |c| wells << "#{r}#{c}" }
  end.freeze
end

.rows_range(size) ⇒ Object



14
15
16
# File 'app/services/well_sorter_service.rb', line 14

def self.rows_range(size)
  ROWS_RANGE.fetch(size)
end

.sort_in_column_order(wells) ⇒ Array<String>

Returns a new array sorted into column order e.g.. sort_in_column_order([‘A1’, ‘A2’, ‘B1’]) => [‘A1’, ‘B1’, ‘A2’]

Parameters:

  • wells (Array<String>)

    Array of well names to sort

Returns:

  • (Array<String>)

    Array of well names sorted in column order



83
84
85
# File 'app/services/well_sorter_service.rb', line 83

def self.sort_in_column_order(wells)
  wells.sort_by { |well| well_coordinate(well) }
end

.stamp_hash(size) ⇒ Hash

Returns a hash suitable for stamping an entire plate

Parameters:

  • size (Integer)

    The size of the plate

Returns:

  • (Hash)

    eg. { ‘A1’ => ‘A1’, ‘B1’ => ‘B1’, …}



43
44
45
# File 'app/services/well_sorter_service.rb', line 43

def self.stamp_hash(size)
  column_order(size).each_with_object({}) { |well, hash| hash[well] = well }
end

.well_at_column_index(index, size = 96) ⇒ String

Returns the name of the well at the provided index. e.g.. WellHelpers.column_index(2) #=> 'C1'

Parameters:

  • index (Int)

    Well index by column

Returns:

  • (String)

    string name of the well



71
72
73
# File 'app/services/well_sorter_service.rb', line 71

def self.well_at_column_index(index, size = 96)
  column_order(size)[index]
end

.well_coordinate(well) ⇒ Array<Integer>

Converts a well name to its co-ordinates

Parameters:

  • well (<String>)

    Name of the well. Eg. A3

Returns:

  • (Array<Integer>)

    An array of two integers indicating column and row. eg. [0, 2]



122
123
124
# File 'app/services/well_sorter_service.rb', line 122

def self.well_coordinate(well)
  [well[1..].to_i - 1, well.upcase.getbyte(0) - 'A'.getbyte(0)]
end

.well_name(row, column) ⇒ String

Returns the name of the well at the given co-ordinates e.g.. WellHelpers.well_name(2,3) #=> 'D3'

Parameters:

  • row (Int)

    The row co-ordinate, zero indexed

  • column (Int)

    The column co-ordinate, zero indexed

Returns:

  • (String)

    the well name, eg. A1



61
62
63
64
# File 'app/services/well_sorter_service.rb', line 61

def self.well_name(row, column)
  row_name = ('A'.getbyte(0) + row).chr
  "#{row_name}#{column + 1}"
end