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.
Files changed (64) hide show
  1. data/History.txt +4 -0
  2. data/README.md +6 -0
  3. data/lib/catissue/annotation/annotation_class.rb +1 -1
  4. data/lib/catissue/cli/migrate.rb +1 -0
  5. data/lib/catissue/domain/container.rb +13 -8
  6. data/lib/catissue/domain/specimen.rb +9 -3
  7. data/lib/catissue/domain/specimen_event_parameters.rb +1 -8
  8. data/lib/catissue/domain/specimen_requirement.rb +1 -1
  9. data/lib/catissue/domain/storage_container.rb +4 -3
  10. data/lib/catissue/domain/uniquify.rb +82 -0
  11. data/lib/catissue/migration/migrator.rb +15 -7
  12. data/lib/catissue/migration/uniquify.rb +2 -111
  13. data/lib/catissue/util/position.rb +14 -2
  14. data/lib/catissue/version.rb +1 -1
  15. data/test/fixtures/catissue/domain/conf/catissue_override.yaml +9 -0
  16. data/test/fixtures/catissue/extract/conf/scg_extract.yaml +3 -0
  17. data/test/fixtures/catissue/extract/conf/scg_fields.yaml +3 -0
  18. data/test/fixtures/catissue/extract/conf/spc_extract.yaml +3 -0
  19. data/test/fixtures/catissue/extract/conf/spc_fields.yaml +4 -0
  20. data/test/fixtures/lib/catissue/defaults_test_fixture.rb +202 -0
  21. data/test/lib/catissue/database/controlled_values_test.rb +47 -0
  22. data/test/lib/catissue/database/database_test.rb +28 -0
  23. data/test/lib/catissue/domain/address_test.rb +53 -0
  24. data/test/lib/catissue/domain/base_haemotology_pathology_test.rb +25 -0
  25. data/test/lib/catissue/domain/ca_tissue_test_defaults_test.rb +27 -0
  26. data/test/lib/catissue/domain/capacity_test.rb +12 -0
  27. data/test/lib/catissue/domain/collection_event_parameters_test.rb +24 -0
  28. data/test/lib/catissue/domain/collection_protocol_event_test.rb +25 -0
  29. data/test/lib/catissue/domain/collection_protocol_registration_test.rb +71 -0
  30. data/test/lib/catissue/domain/collection_protocol_test.rb +69 -0
  31. data/test/lib/catissue/domain/container_position_test.rb +29 -0
  32. data/test/lib/catissue/domain/department_test.rb +21 -0
  33. data/test/lib/catissue/domain/disposal_event_parameters_test.rb +16 -0
  34. data/test/lib/catissue/domain/location_test.rb +38 -0
  35. data/test/lib/catissue/domain/metadata_test.rb +62 -0
  36. data/test/lib/catissue/domain/participant_medical_identifier_test.rb +26 -0
  37. data/test/lib/catissue/domain/participant_test.rb +96 -0
  38. data/test/lib/catissue/domain/site_test.rb +30 -0
  39. data/test/lib/catissue/domain/specimen_array_test.rb +38 -0
  40. data/test/lib/catissue/domain/specimen_array_type_test.rb +27 -0
  41. data/test/lib/catissue/domain/specimen_characteristics_test.rb +15 -0
  42. data/test/lib/catissue/domain/specimen_collection_group_test.rb +216 -0
  43. data/test/lib/catissue/domain/specimen_event_parameters_test.rb +61 -0
  44. data/test/lib/catissue/domain/specimen_position_test.rb +62 -0
  45. data/test/lib/catissue/domain/specimen_requirement_test.rb +61 -0
  46. data/test/lib/catissue/domain/specimen_test.rb +272 -0
  47. data/test/lib/catissue/domain/storage_container_test.rb +150 -0
  48. data/test/lib/catissue/domain/storage_type_test.rb +70 -0
  49. data/test/lib/catissue/domain/transfer_event_parameters_test.rb +38 -0
  50. data/test/lib/catissue/domain/user_test.rb +50 -0
  51. data/test/lib/catissue/extract/delta_test.rb +25 -0
  52. data/test/lib/catissue/extract/extractor_test.rb +43 -0
  53. data/test/lib/catissue/import/importable_module_test.rb +14 -0
  54. data/test/lib/catissue/migration/test_case.rb +103 -0
  55. data/test/lib/catissue/test_case.rb +225 -0
  56. data/test/lib/examples/galena/domain/examples_test.rb +70 -0
  57. data/test/lib/examples/galena/migration/catissue.log +0 -0
  58. data/test/lib/examples/galena/migration/filter_test.rb +26 -0
  59. data/test/lib/examples/galena/migration/frozen_test.rb +28 -0
  60. data/test/lib/examples/galena/migration/general_test.rb +44 -0
  61. data/test/lib/examples/galena/migration/simple_test.rb +29 -0
  62. data/test/lib/examples/galena/migration/test_case.rb +52 -0
  63. data/test/lib/examples/galena/migration/uniquify.rb +93 -0
  64. metadata +223 -184
@@ -14,3 +14,7 @@
14
14
 
15
15
  * Full PCBIN DE support
16
16
 
17
+ === 1.3.2 / 2011-02-25
18
+
19
+ * Minor migration bug fixes
20
+
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)
@@ -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, nil] coordinate the x-y coordinate to place the item
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=nil)
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 [Coordinate] coordinate the optional location to create
197
+ # @param coordinate (see #add)
194
198
  # @return [Location] the created location
195
- def create_location(coordinate=nil)
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
- external_identifiers.any? do |eid|
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 === other and specimen_type == other.specimen_type and pathological_status == other.pathological_status and
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=nil)
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
- # the options specific to this CaTissue::Migrator subclass
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
- require 'caruby/migration/uniquify'
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
- unless holder.can_hold_child?(occupant) then
60
- raise ValidationError.new("#{self} cannot be occupied by #{occupant}")
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
@@ -1,6 +1,6 @@
1
1
  module CaTissue
2
2
  # The version of this caRuby Tissue release.
3
- VERSION = "1.3.1"
3
+ VERSION = "1.3.2"
4
4
 
5
5
  # The supported caTissue release versions.
6
6
  CATISSUE_VERSIONS = "1.1.2"