caruby-tissue 1.3.1 → 1.3.2
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +4 -0
- data/README.md +6 -0
- data/lib/catissue/annotation/annotation_class.rb +1 -1
- data/lib/catissue/cli/migrate.rb +1 -0
- data/lib/catissue/domain/container.rb +13 -8
- data/lib/catissue/domain/specimen.rb +9 -3
- data/lib/catissue/domain/specimen_event_parameters.rb +1 -8
- data/lib/catissue/domain/specimen_requirement.rb +1 -1
- data/lib/catissue/domain/storage_container.rb +4 -3
- data/lib/catissue/domain/uniquify.rb +82 -0
- data/lib/catissue/migration/migrator.rb +15 -7
- data/lib/catissue/migration/uniquify.rb +2 -111
- data/lib/catissue/util/position.rb +14 -2
- data/lib/catissue/version.rb +1 -1
- data/test/fixtures/catissue/domain/conf/catissue_override.yaml +9 -0
- data/test/fixtures/catissue/extract/conf/scg_extract.yaml +3 -0
- data/test/fixtures/catissue/extract/conf/scg_fields.yaml +3 -0
- data/test/fixtures/catissue/extract/conf/spc_extract.yaml +3 -0
- data/test/fixtures/catissue/extract/conf/spc_fields.yaml +4 -0
- data/test/fixtures/lib/catissue/defaults_test_fixture.rb +202 -0
- data/test/lib/catissue/database/controlled_values_test.rb +47 -0
- data/test/lib/catissue/database/database_test.rb +28 -0
- data/test/lib/catissue/domain/address_test.rb +53 -0
- data/test/lib/catissue/domain/base_haemotology_pathology_test.rb +25 -0
- data/test/lib/catissue/domain/ca_tissue_test_defaults_test.rb +27 -0
- data/test/lib/catissue/domain/capacity_test.rb +12 -0
- data/test/lib/catissue/domain/collection_event_parameters_test.rb +24 -0
- data/test/lib/catissue/domain/collection_protocol_event_test.rb +25 -0
- data/test/lib/catissue/domain/collection_protocol_registration_test.rb +71 -0
- data/test/lib/catissue/domain/collection_protocol_test.rb +69 -0
- data/test/lib/catissue/domain/container_position_test.rb +29 -0
- data/test/lib/catissue/domain/department_test.rb +21 -0
- data/test/lib/catissue/domain/disposal_event_parameters_test.rb +16 -0
- data/test/lib/catissue/domain/location_test.rb +38 -0
- data/test/lib/catissue/domain/metadata_test.rb +62 -0
- data/test/lib/catissue/domain/participant_medical_identifier_test.rb +26 -0
- data/test/lib/catissue/domain/participant_test.rb +96 -0
- data/test/lib/catissue/domain/site_test.rb +30 -0
- data/test/lib/catissue/domain/specimen_array_test.rb +38 -0
- data/test/lib/catissue/domain/specimen_array_type_test.rb +27 -0
- data/test/lib/catissue/domain/specimen_characteristics_test.rb +15 -0
- data/test/lib/catissue/domain/specimen_collection_group_test.rb +216 -0
- data/test/lib/catissue/domain/specimen_event_parameters_test.rb +61 -0
- data/test/lib/catissue/domain/specimen_position_test.rb +62 -0
- data/test/lib/catissue/domain/specimen_requirement_test.rb +61 -0
- data/test/lib/catissue/domain/specimen_test.rb +272 -0
- data/test/lib/catissue/domain/storage_container_test.rb +150 -0
- data/test/lib/catissue/domain/storage_type_test.rb +70 -0
- data/test/lib/catissue/domain/transfer_event_parameters_test.rb +38 -0
- data/test/lib/catissue/domain/user_test.rb +50 -0
- data/test/lib/catissue/extract/delta_test.rb +25 -0
- data/test/lib/catissue/extract/extractor_test.rb +43 -0
- data/test/lib/catissue/import/importable_module_test.rb +14 -0
- data/test/lib/catissue/migration/test_case.rb +103 -0
- data/test/lib/catissue/test_case.rb +225 -0
- data/test/lib/examples/galena/domain/examples_test.rb +70 -0
- data/test/lib/examples/galena/migration/catissue.log +0 -0
- data/test/lib/examples/galena/migration/filter_test.rb +26 -0
- data/test/lib/examples/galena/migration/frozen_test.rb +28 -0
- data/test/lib/examples/galena/migration/general_test.rb +44 -0
- data/test/lib/examples/galena/migration/simple_test.rb +29 -0
- data/test/lib/examples/galena/migration/test_case.rb +52 -0
- data/test/lib/examples/galena/migration/uniquify.rb +93 -0
- metadata +223 -184
data/History.txt
CHANGED
data/README.md
CHANGED
@@ -91,3 +91,9 @@ Common fields are as follows:
|
|
91
91
|
* Box - Tissue storage container
|
92
92
|
* X - the tissue box column
|
93
93
|
* Y - the tissue box row
|
94
|
+
|
95
|
+
Copyright
|
96
|
+
---------
|
97
|
+
|
98
|
+
caRuby © 2010, 2011 by [Oregon Health & Science University](http://www.ohsu.edu/xd/health/services/cancer/index.cfm).
|
99
|
+
caRuby is licensed under the MIT license. Please see the LICENSE and LEGAL files for more information.
|
@@ -118,7 +118,7 @@ module CaTissue
|
|
118
118
|
# Recurses the dependency hierarchy to this annotation class's dependents in a
|
119
119
|
# breadth-first manner.
|
120
120
|
#
|
121
|
-
# @param [<CaRuby::AttributeMetadata>] the visited attributes
|
121
|
+
# @param [<CaRuby::AttributeMetadata>] path the visited attributes
|
122
122
|
def add_dependent_attribute_closure(path=[])
|
123
123
|
return if path.include?(self)
|
124
124
|
attrs = dependent_attributes(false)
|
data/lib/catissue/cli/migrate.rb
CHANGED
@@ -16,6 +16,7 @@ module CaTissue
|
|
16
16
|
[:input, "-i", "input", "Source file to migrate"],
|
17
17
|
[:target, "-t", "--target CLASS", "Migration target class"],
|
18
18
|
[:mapping, "-m", "--mapping FILE", "The input field => caTissue attribute mapping file"],
|
19
|
+
[:defaults, "-d", "--defaults FILE", "The caTissue attribute => default value mapping file"],
|
19
20
|
[:shims, "-s", "--shims FILE[,FILE...]", Array, "Migration customization shim files to load"],
|
20
21
|
[:bad, "-b", "--bad FILE", "Write each invalid record to the given file and continue migration"],
|
21
22
|
[:unique, "-u", "--unique", "Make the migrated objects unique for testing"],
|
@@ -137,6 +137,7 @@ module CaTissue
|
|
137
137
|
|
138
138
|
# @return the occupant at the given zero-based row and column, or nil if none
|
139
139
|
def [](column, row)
|
140
|
+
return if column.nil? or row.nil?
|
140
141
|
all_occupied_positions.detect_value do |pos|
|
141
142
|
return if row < pos.row
|
142
143
|
next unless row == pos.row
|
@@ -149,10 +150,10 @@ module CaTissue
|
|
149
150
|
# The storable Storable position is updated to reflect the new location. Returns self.
|
150
151
|
#
|
151
152
|
# @param [Storable] storable the item to add
|
152
|
-
# @param [CaRuby::Coordinate,
|
153
|
+
# @param [CaRuby::Coordinate, <Integer>] coordinate the x-y coordinate to place the item
|
153
154
|
# @raise [IndexError] if this Container is full
|
154
155
|
# @raise [IndexError] if the row and column are given but exceed the Container bounds
|
155
|
-
def add(storable, coordinate
|
156
|
+
def add(storable, *coordinate)
|
156
157
|
validate_type(storable)
|
157
158
|
loc = create_location(coordinate)
|
158
159
|
pos = storable.position || storable.position_class.new
|
@@ -185,18 +186,22 @@ module CaTissue
|
|
185
186
|
# @param [Storable] the item to store
|
186
187
|
# @raise [TypeError] if this container cannot hold the storable
|
187
188
|
def validate_type(storable)
|
189
|
+
unless container_type then
|
190
|
+
raise TypeError.new("Container #{self} is missing a type")
|
191
|
+
end
|
188
192
|
unless container_type.can_hold_child?(storable) then
|
189
|
-
raise TypeError.new("Container #{self} cannot hold an item of the #{storable} type")
|
193
|
+
raise TypeError.new("Container #{self} cannot hold an item of the #{storable} type #{storable.container_type}")
|
190
194
|
end
|
191
195
|
end
|
192
196
|
|
193
|
-
# @param
|
197
|
+
# @param coordinate (see #add)
|
194
198
|
# @return [Location] the created location
|
195
|
-
def create_location(coordinate
|
196
|
-
if coordinate then
|
197
|
-
Location.new(:in => self, :at => coordinate)
|
198
|
-
else
|
199
|
+
def create_location(coordinate)
|
200
|
+
if coordinate.empty? then
|
199
201
|
first_available_location or raise IndexError.new("Container #{qp} does not have an available location")
|
202
|
+
else
|
203
|
+
if coordinate.size == 1 then coordinate = coordinate.first end
|
204
|
+
Location.new(:in => self, :at => coordinate)
|
200
205
|
end
|
201
206
|
end
|
202
207
|
|
@@ -217,9 +217,7 @@ module CaTissue
|
|
217
217
|
# one external identifier.
|
218
218
|
def match_in_owner_scope(others)
|
219
219
|
super or others.detect do |other|
|
220
|
-
|
221
|
-
other.external_identifiers.detect { |oeid| eid.name == oeid.name and eid.value == oeid.value }
|
222
|
-
end
|
220
|
+
other.class == self.class and external_identifier_match?(other)
|
223
221
|
end
|
224
222
|
end
|
225
223
|
|
@@ -368,6 +366,14 @@ module CaTissue
|
|
368
366
|
MERGEABLE_RQMT_ATTRS = nondomain_java_attributes - primary_key_attributes
|
369
367
|
|
370
368
|
MERGEABLE_SPC_CHR_ATTRS = SpecimenCharacteristics.nondomain_java_attributes - SpecimenCharacteristics.primary_key_attributes
|
369
|
+
|
370
|
+
# @param [Resource] other the object to match
|
371
|
+
# @return [Boolean] whether this specimen matches the other specimen on at least one external identifier
|
372
|
+
def external_identifier_match?(other)
|
373
|
+
external_identifiers.any? do |eid|
|
374
|
+
other.external_identifiers.detect { |oeid| eid.name == oeid.name and eid.value == oeid.value }
|
375
|
+
end
|
376
|
+
end
|
371
377
|
|
372
378
|
# @see #fetch_saved
|
373
379
|
def available_quantity_changed?
|
@@ -93,15 +93,8 @@ module CaTissue
|
|
93
93
|
self.user ||= default_user
|
94
94
|
end
|
95
95
|
|
96
|
-
# Returns whether the given value is either nil, empty or equals other.
|
97
|
-
def missing_or_match?(attribute, other)
|
98
|
-
value = send(attr)
|
99
|
-
value.nil_or_empty? or value == other.send(attr)
|
100
|
-
end
|
101
|
-
|
102
96
|
def default_user
|
103
|
-
scg = specimen_collection_group
|
104
|
-
scg ||= specimen.specimen_collection_group if specimen
|
97
|
+
scg = specimen_collection_group || (specimen.specimen_collection_group if specimen)
|
105
98
|
scg.receiver if scg
|
106
99
|
end
|
107
100
|
end
|
@@ -46,7 +46,7 @@ module CaTissue
|
|
46
46
|
# in others with the same class, specimen type, pathological_status and characteristics.
|
47
47
|
def match_in_owner_scope(others)
|
48
48
|
others.detect do |other|
|
49
|
-
self.class
|
49
|
+
self.class == other.class and specimen_type == other.specimen_type and pathological_status == other.pathological_status and
|
50
50
|
characteristics and characteristics.match?(other.characteristics)
|
51
51
|
end
|
52
52
|
end
|
@@ -61,6 +61,7 @@ module CaTissue
|
|
61
61
|
end
|
62
62
|
|
63
63
|
alias :add_local :add
|
64
|
+
private :add_local
|
64
65
|
|
65
66
|
# Adds the given storable to this container. If the storable has a current position, then
|
66
67
|
# the storable is moved from that position to this container. The new position is given
|
@@ -76,12 +77,12 @@ module CaTissue
|
|
76
77
|
# freezer << specimen #=> places the specimen in the first available box in the freezer
|
77
78
|
#
|
78
79
|
# @param [Storable] the item to add
|
79
|
-
# @param [Coordinate] the storage location (default is first available location)
|
80
|
+
# @param [Coordinate, <Integer>] the storage location (default is first available location)
|
80
81
|
# @return [StorageContainer] self
|
81
82
|
# @raise [IndexError] if this Container is full
|
82
83
|
# @raise [IndexError] if the row and column are given but exceed the Container bounds
|
83
|
-
def add(storable, coordinate
|
84
|
-
return add_local(storable, coordinate) if coordinate
|
84
|
+
def add(storable, *coordinate)
|
85
|
+
return add_local(storable, *coordinate) if coordinate
|
85
86
|
add_to_existing_container(storable) or add_to_new_subcontainer(storable) or out_of_bounds(storable)
|
86
87
|
self
|
87
88
|
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'caruby/domain/uniquify'
|
2
|
+
|
3
|
+
module CaTissue
|
4
|
+
class CollectionProtocol
|
5
|
+
include CaRuby::Resource::Unique
|
6
|
+
|
7
|
+
# Makes this CP's short and long title unique.
|
8
|
+
def uniquify
|
9
|
+
super
|
10
|
+
self.title = short_title
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Container
|
15
|
+
include CaRuby::Resource::Unique
|
16
|
+
|
17
|
+
# Makes this Container and all of its subcontainers unique.
|
18
|
+
def uniquify
|
19
|
+
super
|
20
|
+
subcontainers.each { |ctr| ctr.uniquify }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class ParticipantMedicalIdentifier
|
25
|
+
include CaRuby::Resource::Unique
|
26
|
+
end
|
27
|
+
|
28
|
+
class CollectionProtocolRegistration
|
29
|
+
include CaRuby::Resource::Unique
|
30
|
+
|
31
|
+
# Makes this CPR's PPI unique.
|
32
|
+
def uniquify
|
33
|
+
oldval = protocol_participant_identifier || return
|
34
|
+
newval = uniquify_value(oldval)
|
35
|
+
self.protocol_participant_identifier = newval
|
36
|
+
logger.debug { "Reset #{qp} PPI from #{oldval} to unique value #{newval}." }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class SpecimenCollectionGroup
|
41
|
+
include CaRuby::Resource::Unique
|
42
|
+
|
43
|
+
# Makes this SCG's SPN unique.
|
44
|
+
def uniquify
|
45
|
+
super
|
46
|
+
oldval = surgical_pathology_number || return
|
47
|
+
newval = uniquify_value(oldval)
|
48
|
+
self.surgical_pathology_number = newval
|
49
|
+
logger.debug { "Reset #{qp} SPN from #{oldval} to unique value #{newval}." }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class Specimen
|
54
|
+
include CaRuby::Resource::Unique
|
55
|
+
end
|
56
|
+
|
57
|
+
class ExternalIdentifier
|
58
|
+
include CaRuby::Resource::Unique
|
59
|
+
|
60
|
+
# Makes this ExternalIdentifier's value unique.
|
61
|
+
def uniquify
|
62
|
+
oldval = value || return
|
63
|
+
newval = uniquify_value(oldval)
|
64
|
+
self.value = newval
|
65
|
+
logger.debug { "Reset #{qp} value from #{oldval} to unique value #{newval}." }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class User
|
70
|
+
include CaRuby::Resource::Unique
|
71
|
+
|
72
|
+
# Makes this User's login id and email address unique.
|
73
|
+
# The result is in the form _name___suffix_+@test.com+
|
74
|
+
# where:
|
75
|
+
# * _name_ is the name prefix portion of the original email address
|
76
|
+
# * _suffix_ is a unique number
|
77
|
+
def uniquify
|
78
|
+
email = email_address ||= self.login_name || return
|
79
|
+
self.login_name = self.email_address = uniquify_value(email[/[^@]+/]) + '@test.com'
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -30,6 +30,8 @@ module CaTissue
|
|
30
30
|
# @option opts [String] :target required target domain class
|
31
31
|
# @option opts [String] :input required source file to migrate
|
32
32
|
# @option opts [String] :shims optional array of shim files to load
|
33
|
+
# @option opts [String] :unique makes migrated objects unique object for testing
|
34
|
+
# mix-in do not conflict with existing or future objects
|
33
35
|
# @option opts [String] :bad write each invalid record to the given file and continue migration
|
34
36
|
# @option opts [String] :offset zero-based starting source record number to process (default 0)
|
35
37
|
def initialize(opts={})
|
@@ -40,12 +42,6 @@ module CaTissue
|
|
40
42
|
# add config options but don't override the parameter options
|
41
43
|
opts.merge!(conf, :deep) { |key, oldval, newval| oldval }
|
42
44
|
end
|
43
|
-
|
44
|
-
|
45
|
-
# TODO - move opt parsing to CaTissue::CLI::Migrate and call that from test cases
|
46
|
-
# Migrate then calls this Migrator with parsed options
|
47
|
-
|
48
|
-
|
49
45
|
# open the log file before building structure
|
50
46
|
log_file = opts[:log]
|
51
47
|
CaRuby::Log.instance.open(log_file, :debug => opts[:debug]) if log_file
|
@@ -60,12 +56,22 @@ module CaTissue
|
|
60
56
|
# call the CaRuby::Migrator initializer with the augmented options
|
61
57
|
super
|
62
58
|
|
63
|
-
#
|
59
|
+
# The remaining options are specific to this CaTissue::Migrator subclass.
|
60
|
+
|
61
|
+
# If the unique option is set, then append the CaTissue-specific uniquifier shim.
|
62
|
+
if opts[:unique] then
|
63
|
+
# add the uniquify shim
|
64
|
+
@shims << UNIQUIFY_SHIM
|
65
|
+
end
|
66
|
+
|
67
|
+
# The tissue site CV look-up option.
|
64
68
|
tissue_sites = opts[:tissue_sites]
|
65
69
|
if tissue_sites then
|
66
70
|
CaTissue::SpecimenCharacteristics.tissue_site_cv_finder = ControlledValueFinder.new(:tissue_site, tissue_sites)
|
67
71
|
logger.info("Migrator enabled controlled value lookup.")
|
68
72
|
end
|
73
|
+
|
74
|
+
# The clinical diagnosis CV look-up option.
|
69
75
|
diagnoses = opts[:diagnoses]
|
70
76
|
if diagnoses then
|
71
77
|
CaTissue::SpecimenCollectionGroup.diagnosis_cv_finder = ControlledValueFinder.new(:clinical_diagnosis, diagnoses)
|
@@ -75,6 +81,8 @@ module CaTissue
|
|
75
81
|
|
76
82
|
private
|
77
83
|
|
84
|
+
UNIQUIFY_SHIM = File.join(File.dirname(__FILE__), 'uniquify')
|
85
|
+
|
78
86
|
# Clears the migration protocol CPR and SCG references.
|
79
87
|
# This action frees up memory for the next iteration, thereby ensuring that migration is an
|
80
88
|
# O(1) rather than O(n) operation.
|
@@ -1,111 +1,2 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
module CaTissue
|
4
|
-
shims CollectionProtocol, Site, User, Container, ExternalIdentifier, ParticipantMedicalIdentifier,
|
5
|
-
CollectionProtocolRegistration, SpecimenCollectionGroup, Specimen
|
6
|
-
|
7
|
-
class CollectionProtocol
|
8
|
-
include CaRuby::Migratable::Unique
|
9
|
-
|
10
|
-
# Makes this CP's title unique.
|
11
|
-
def uniquify
|
12
|
-
self.title = self.short_title = uniquify_value(short_title)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
class Site
|
17
|
-
include CaRuby::Migratable::Unique
|
18
|
-
|
19
|
-
# Makes this Site's name unique.
|
20
|
-
def uniquify
|
21
|
-
self.name = uniquify_value(name)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
class CollectionProtocolRegistration
|
26
|
-
include CaRuby::Migratable::Unique
|
27
|
-
|
28
|
-
# Makes this CPR's PPI unique.
|
29
|
-
def uniquify
|
30
|
-
self.protocol_participant_identifier = uniquify_value(protocol_participant_identifier)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
class Container
|
35
|
-
include CaRuby::Migratable::Unique
|
36
|
-
|
37
|
-
# Makes this Container's name unique.
|
38
|
-
def uniquify
|
39
|
-
self.name = uniquify_value(name)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
class ContainerType
|
44
|
-
include CaRuby::Migratable::Unique
|
45
|
-
|
46
|
-
# Makes this ContainerType's name unique.
|
47
|
-
def uniquify
|
48
|
-
self.name = uniquify_value(name)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
class StorageType
|
53
|
-
include CaRuby::Migratable::Unique
|
54
|
-
|
55
|
-
# Makes this StorageType and the ContainerTypes which it holds unique.
|
56
|
-
def uniquify
|
57
|
-
super
|
58
|
-
child_types.each { |ct| ct.uniquify if ContainerType === ct }
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
class SpecimenCollectionGroup
|
63
|
-
include CaRuby::Migratable::Unique
|
64
|
-
|
65
|
-
# Makes this SCG's SPN unique.
|
66
|
-
def uniquify
|
67
|
-
self.surgical_pathology_number = uniquify_value(surgical_pathology_number)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
class Specimen
|
72
|
-
include CaRuby::Migratable::Unique
|
73
|
-
|
74
|
-
# Makes this Specimen's label unique.
|
75
|
-
def uniquify
|
76
|
-
self.label = uniquify_value(label.uniquify) if label
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
class ExternalIdentifier
|
81
|
-
include CaRuby::Migratable::Unique
|
82
|
-
|
83
|
-
# Makes this ExternalIdentifier's value unique.
|
84
|
-
def uniquify
|
85
|
-
self.value = uniquify_value(value)
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
class ParticipantMedicalIdentifier
|
90
|
-
include CaRuby::Migratable::Unique
|
91
|
-
|
92
|
-
# Makes this PMI's MRN unique.
|
93
|
-
def uniquify
|
94
|
-
self.medical_record_number = uniquify_value(medical_record_number)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
class User
|
99
|
-
include CaRuby::Migratable::Unique
|
100
|
-
|
101
|
-
# Makes this User's login id and email address unique.
|
102
|
-
# The result is in the form _name___suffix_+@test.com+
|
103
|
-
# where:
|
104
|
-
# * _name_ is the name prefix portion of the original email address
|
105
|
-
# * _suffix_ is a unique number
|
106
|
-
def uniquify
|
107
|
-
email = email_address ||= self.login_name || return
|
108
|
-
self.login_name = self.email_address = uniquify_value(email[/[^@]+/]) + '@test.com'
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
1
|
+
# This include file is a convenience CaTissue migrator shim which enables CaTissue class uniquification.
|
2
|
+
require 'catissue/domain/uniquify'
|
@@ -47,6 +47,11 @@ module CaTissue
|
|
47
47
|
self.row = @location.row
|
48
48
|
self.column = @location.column
|
49
49
|
end
|
50
|
+
|
51
|
+
# @return whether either the column or the row is nil
|
52
|
+
def unspecified?
|
53
|
+
column.nil? or row.nil?
|
54
|
+
end
|
50
55
|
|
51
56
|
# @return [(Integer, Integer)] this Position's zero-based ({#column}, {#row}) tuple.
|
52
57
|
def to_a
|
@@ -56,8 +61,15 @@ module CaTissue
|
|
56
61
|
# @raise [ValidationError] if the holder cannot hold the occupant type
|
57
62
|
def validate
|
58
63
|
super
|
59
|
-
|
60
|
-
|
64
|
+
logger.debug { "Validating that #{holder} can hold #{occupant}..." }
|
65
|
+
curr_occ = holder[column, row]
|
66
|
+
if curr_occ.nil? then
|
67
|
+
unless holder.can_hold_child?(occupant) then
|
68
|
+
reason = holder.full? ? "it is full" : "the occupant type is not among the supported types #{holder.container_type.child_types.qp}"
|
69
|
+
raise ValidationError.new("#{holder} cannot hold #{occupant} since #{reason}")
|
70
|
+
end
|
71
|
+
elsif curr_occ != occupant
|
72
|
+
raise ValidationError.new("#{holder} cannot hold #{occupant} since the location #{[colum, row]} is already occupied by #{curr_occ}")
|
61
73
|
end
|
62
74
|
end
|
63
75
|
end
|