Skip to content
This repository was archived by the owner on Jun 18, 2025. It is now read-only.

Commit edb54e2

Browse files
authored
Merge pull request #71 from emrojo/add_runner_move_barcodes_from_tube_rack_into_plate
Add runner move barcodes from tube rack into plate
2 parents aae8f7c + caaf2fc commit edb54e2

File tree

2 files changed

+160
-0
lines changed

2 files changed

+160
-0
lines changed
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# # This rule applies the barcodes from a rack into a plate
2+
# {
3+
# ?plate se:a """Plate""" .
4+
# ?rack se:a """TubeRack""" .
5+
# ?rack se:mergeInto ?plate .
6+
# ?rack se:contains ?tube .
7+
# ?plate se:contains ?well .
8+
# ?tube se:location ?location .
9+
# ?tube se:barcode ?barcode .
10+
# ?well se:location ?location .
11+
# } => {
12+
# :step :addFacts { ?well se:barcode ?barcode . } .
13+
# :step :removeFacts { ?tube se:barcode ?barcode . } .
14+
# :step :addFacts { ?tube se:barcode """""" . } .
15+
# :step :addFacts { ?tube se:previousBarcode ?barcode . } .
16+
# :step :addFacts { ?tube se:appliedBarcodeTo ?well . } .
17+
# :step :addFacts { ?rack se:mergedInto ?plate .}.
18+
# :step :addFacts { ?plate se:mergedFrom ?rack .}.
19+
# }.
20+
21+
class MoveBarcodesFromTubeRackToPlate
22+
attr_reader :asset_group
23+
24+
25+
def initialize(params)
26+
@asset_group = params[:asset_group]
27+
end
28+
29+
def assets_compatible_with_step_type
30+
[plate, tube_rack].flatten.compact.count > 0
31+
end
32+
33+
34+
def plate
35+
asset_group.assets.select{|a| a.facts.where(predicate: 'a', object: 'Plate').count > 0 }.first
36+
end
37+
38+
def tube_rack
39+
asset_group.assets.select{|a| a.facts.where(predicate: 'a', object: 'TubeRack').count > 0}.first
40+
end
41+
42+
def wells_for(asset)
43+
asset.facts.where(predicate: 'contains').map(&:object_asset)
44+
end
45+
46+
def well_at_location(asset, location)
47+
wells_for(asset).select{|w| w.facts.where(predicate: 'location', object: location).count > 0}.first
48+
end
49+
50+
def traverse_wells(asset, &block)
51+
wells_for(asset).each do |w|
52+
location = w.facts.where(predicate: 'location').first.object
53+
yield w, location
54+
end
55+
end
56+
57+
def process
58+
FactChanges.new.tap do |updates|
59+
if assets_compatible_with_step_type
60+
traverse_wells(tube_rack) do |well_from_tube_rack, location|
61+
well_from_plate = well_at_location(plate, location)
62+
updates.remove_where(well_from_tube_rack, 'barcode', well_from_tube_rack.barcode)
63+
updates.add(well_from_tube_rack, 'previousBarcode', well_from_tube_rack.barcode)
64+
updates.add(well_from_tube_rack, 'appliedBarcodeTo', well_from_plate)
65+
updates.add(well_from_plate, 'barcode', well_from_tube_rack.barcode)
66+
end
67+
68+
updates.add(tube_rack, 'mergedInto', plate)
69+
updates.add(plate, 'mergedFrom', tube_rack)
70+
end
71+
end
72+
end
73+
end
74+
75+
return unless ARGV.any?{|s| s.match(".json")}
76+
77+
args = ARGV[0]
78+
asset_group_id = args.match(/(\d*)\.json/)[1]
79+
asset_group = AssetGroup.find(asset_group_id)
80+
81+
begin
82+
updates = MoveBarcodesFromTubeRackToPlate.new(asset_group: asset_group).process
83+
json = updates.to_json
84+
JSON.parse(json)
85+
puts json
86+
rescue InvalidDataParams => e
87+
puts ({ set_errors: e.errors }.to_json)
88+
rescue StandardError => e
89+
puts ({ set_errors: ['Unknown error while parsing file'+e.backtrace.to_s]}.to_json)
90+
end
91+
92+
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
require 'rails_helper'
2+
3+
require Rails.root.to_s+'/script/runners/move_barcodes_from_tube_rack_to_plate'
4+
5+
RSpec.describe 'MoveBarcodesFromTubeRackToPlate' do
6+
NUM_WELLS = 3
7+
8+
let(:barcodes) {
9+
NUM_WELLS.times.map{|i| "FR00#{i}"}
10+
}
11+
let(:locations) {
12+
NUM_WELLS.times.map{|i| "A#{i}"}
13+
}
14+
let(:wells_for_rack) {
15+
NUM_WELLS.times.map do |i|
16+
asset = create(:asset, barcode: barcodes[i])
17+
asset.facts << create(:fact, predicate: 'a', object: 'Tube')
18+
asset.facts << create(:fact, predicate: 'location', object: locations[i])
19+
asset
20+
end
21+
}
22+
let(:wells_for_plate) {
23+
NUM_WELLS.times.map do |i|
24+
asset = create(:asset)
25+
asset.facts << create(:fact, predicate: 'a', object: 'Well')
26+
asset.facts << create(:fact, predicate: 'location', object: locations[i])
27+
asset
28+
end
29+
}
30+
let(:tube_rack) {
31+
asset = create :asset
32+
asset.facts << create(:fact, predicate: 'a', object: 'TubeRack')
33+
asset.facts << wells_for_rack.map{|a| create(:fact, predicate: 'contains', object_asset: a)}
34+
asset
35+
}
36+
let(:plate) {
37+
asset = create :asset
38+
asset.facts << create(:fact, predicate: 'a', object: 'Plate')
39+
asset.facts << wells_for_plate.map{|a| create(:fact, predicate: 'contains', object_asset: a)}
40+
asset
41+
}
42+
43+
context 'when run with a tube rack and a plate' do
44+
it 'adds the barcodes of the tube rack into the wells of the plate' do
45+
group = create(:asset_group, assets: [plate, tube_rack])
46+
changes = MoveBarcodesFromTubeRackToPlate.new(asset_group: group).process.to_h
47+
48+
expect(changes[:add_facts].select{|t| t[1] == 'barcode'}.count).to eq(NUM_WELLS)
49+
50+
wells_for_plate.each_with_index do |w, pos|
51+
expect(changes[:add_facts]).to include(
52+
[w.uuid, 'barcode', barcodes[pos]])
53+
end
54+
end
55+
it 'removes the barcodes from the tubes of the tube rack' do
56+
group = create(:asset_group, assets: [plate, tube_rack])
57+
changes = MoveBarcodesFromTubeRackToPlate.new(asset_group: group).process.to_h
58+
59+
expect(changes[:remove_facts].select{|t| t[1] == 'barcode'}.count).to eq(NUM_WELLS)
60+
61+
wells_for_rack.each_with_index do |w, pos|
62+
expect(changes[:remove_facts]).to include(
63+
[w.uuid, 'barcode', barcodes[pos]])
64+
end
65+
end
66+
67+
end
68+
end

0 commit comments

Comments
 (0)