caruby-tissue 1.3.1 → 1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|