caruby-tissue 1.4.2 → 1.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (115) hide show
  1. data/History.md +53 -0
  2. data/bin/crtdump +1 -6
  3. data/bin/crtexample +1 -6
  4. data/bin/crtmigrate +1 -6
  5. data/bin/crtsmoke +1 -6
  6. data/conf/migration/filter_fields.yaml +1 -1
  7. data/conf/migration/general_fields.yaml +1 -1
  8. data/conf/migration/simple_fields.yaml +1 -1
  9. data/conf/migration/small_fields.yaml +1 -1
  10. data/examples/galena/README.md +34 -25
  11. data/examples/galena/bin/seed +2 -7
  12. data/examples/galena/conf/migration/annotation_fields.yaml +1 -1
  13. data/examples/galena/conf/migration/filter_fields.yaml +1 -1
  14. data/examples/galena/conf/migration/frozen_fields.yaml +2 -2
  15. data/examples/galena/conf/migration/general_fields.yaml +1 -1
  16. data/examples/galena/conf/migration/registration_fields.yaml +1 -0
  17. data/examples/galena/conf/migration/simple_fields.yaml +1 -1
  18. data/examples/galena/data/frozen.csv +1 -1
  19. data/examples/galena/data/general.csv +1 -1
  20. data/examples/galena/data/registration.csv +1 -1
  21. data/examples/galena/lib/galena/tissue/migration/frozen_shims.rb +8 -4
  22. data/examples/galena/lib/galena/tissue/seed/defaults.rb +16 -9
  23. data/examples/pcbin/README.md +8 -8
  24. data/examples/pcbin/conf/biopsy_fields.yaml +1 -1
  25. data/examples/pcbin/conf/patient_fields.yaml +1 -1
  26. data/examples/pcbin/conf/surgery_fields.yaml +1 -1
  27. data/examples/pcbin/conf/t_stage_fields.yaml +1 -1
  28. data/examples/pcbin/conf/therapy_fields.yaml +1 -1
  29. data/lib/catissue.rb +1 -1
  30. data/lib/catissue/annotation/annotatable.rb +12 -22
  31. data/lib/catissue/annotation/annotatable_class.rb +87 -114
  32. data/lib/catissue/annotation/annotation.rb +9 -44
  33. data/lib/catissue/annotation/annotation_class.rb +238 -145
  34. data/lib/catissue/annotation/annotation_module.rb +47 -59
  35. data/lib/catissue/annotation/de_integration.rb +12 -2
  36. data/lib/catissue/annotation/proxy.rb +11 -17
  37. data/lib/catissue/annotation/proxy_1_1.rb +47 -0
  38. data/lib/catissue/annotation/proxy_class.rb +55 -37
  39. data/lib/catissue/annotation/record_entry_proxy.rb +20 -0
  40. data/lib/catissue/database.rb +164 -112
  41. data/lib/catissue/database/annotation/annotation_service.rb +5 -5
  42. data/lib/catissue/database/annotation/annotator.rb +2 -2
  43. data/lib/catissue/database/annotation/entity_facade.rb +24 -21
  44. data/lib/catissue/database/annotation/id_generator.rb +26 -26
  45. data/lib/catissue/database/annotation/integration_service.rb +8 -8
  46. data/lib/catissue/database/annotation/record_entry_integrator.rb +24 -6
  47. data/lib/catissue/database/annotation/reference_writer.rb +33 -6
  48. data/lib/catissue/domain.rb +26 -0
  49. data/lib/catissue/domain/abstract_position.rb +1 -1
  50. data/lib/catissue/domain/abstract_specimen.rb +16 -16
  51. data/lib/catissue/domain/check_in_check_out_event_parameter.rb +1 -1
  52. data/lib/catissue/domain/collection_event_parameters.rb +1 -1
  53. data/lib/catissue/domain/collection_protocol.rb +9 -13
  54. data/lib/catissue/domain/collection_protocol_event.rb +4 -4
  55. data/lib/catissue/domain/collection_protocol_registration.rb +4 -4
  56. data/lib/catissue/domain/container.rb +12 -21
  57. data/lib/catissue/domain/container_type.rb +65 -64
  58. data/lib/catissue/domain/disposal_event_parameters.rb +1 -1
  59. data/lib/catissue/domain/hash_code.rb +3 -6
  60. data/lib/catissue/domain/new_specimen_array_order_item.rb +4 -4
  61. data/lib/catissue/domain/order_details.rb +3 -3
  62. data/lib/catissue/domain/participant.rb +28 -20
  63. data/lib/catissue/domain/participant/clinical/chemotherapy.rb +21 -0
  64. data/lib/catissue/domain/participant/clinical/duration.rb +11 -0
  65. data/lib/catissue/domain/participant/clinical/radiation_therapy.rb +21 -0
  66. data/lib/catissue/domain/participant_medical_identifier.rb +2 -2
  67. data/lib/catissue/domain/site.rb +6 -6
  68. data/lib/catissue/domain/specimen.rb +41 -34
  69. data/lib/catissue/domain/specimen/pathology/prostate_specimen_gleason_score.rb +18 -0
  70. data/lib/catissue/domain/specimen/pathology/prostate_specimen_pathology_annotation.rb +13 -8
  71. data/lib/catissue/domain/specimen/pathology/specimen_additional_finding.rb +21 -0
  72. data/lib/catissue/domain/specimen/pathology/specimen_base_solid_tissue_pathology_annotation.rb +30 -7
  73. data/lib/catissue/domain/specimen/pathology/specimen_details.rb +18 -0
  74. data/lib/catissue/domain/specimen/pathology/specimen_histologic_grade.rb +18 -0
  75. data/lib/catissue/domain/specimen/pathology/specimen_histologic_type.rb +22 -6
  76. data/lib/catissue/domain/specimen/pathology/specimen_histologic_variant_type.rb +18 -0
  77. data/lib/catissue/domain/specimen/pathology/specimen_invasion.rb +18 -0
  78. data/lib/catissue/domain/specimen_array.rb +8 -8
  79. data/lib/catissue/domain/specimen_array_content.rb +4 -4
  80. data/lib/catissue/domain/specimen_collection_group.rb +43 -41
  81. data/lib/catissue/domain/specimen_collection_group/pathology/base_pathology_annotation.rb +16 -0
  82. data/lib/catissue/domain/specimen_collection_group/pathology/base_solid_tissue_pathology_annotation.rb +16 -0
  83. data/lib/catissue/domain/specimen_position.rb +3 -3
  84. data/lib/catissue/domain/specimen_protocol.rb +7 -7
  85. data/lib/catissue/domain/specimen_requirement.rb +9 -9
  86. data/lib/catissue/domain/storage_container.rb +13 -13
  87. data/lib/catissue/domain/storage_type.rb +12 -7
  88. data/lib/catissue/domain/transfer_event_parameters.rb +2 -2
  89. data/lib/catissue/domain/user.rb +15 -15
  90. data/lib/catissue/extract/extractor.rb +1 -1
  91. data/lib/catissue/resource.rb +8 -36
  92. data/lib/catissue/util/location.rb +0 -13
  93. data/lib/catissue/util/person.rb +2 -1
  94. data/lib/catissue/util/position.rb +1 -11
  95. data/lib/catissue/util/uniquify.rb +1 -1
  96. data/lib/catissue/version.rb +1 -1
  97. data/lib/catissue/wustl/logger.rb +17 -16
  98. data/test/fixtures/lib/catissue/defaults_test_fixture.rb +6 -4
  99. data/test/lib/catissue/domain/collection_protocol_test.rb +0 -1
  100. data/test/lib/catissue/domain/participant_test.rb +74 -19
  101. data/test/lib/catissue/domain/specimen_collection_group_test.rb +14 -10
  102. data/test/lib/catissue/domain/specimen_test.rb +36 -60
  103. data/test/lib/catissue/domain/storage_type_test.rb +5 -5
  104. data/test/lib/catissue/domain/transfer_event_parameters_test.rb +14 -12
  105. data/test/lib/catissue/migration/test_case.rb +0 -1
  106. data/test/lib/catissue/test_case.rb +12 -12
  107. data/test/lib/examples/galena/tissue/domain/examples_test.rb +1 -1
  108. data/test/lib/examples/galena/tissue/migration/annotation_test.rb +9 -7
  109. data/test/lib/examples/galena/tissue/migration/frozen_test.rb +1 -1
  110. data/test/lib/examples/galena/tissue/migration/general_test.rb +1 -1
  111. data/test/lib/examples/galena/tissue/migration/registration_test.rb +3 -9
  112. data/test/lib/examples/galena/tissue/migration/seedify.rb +3 -3
  113. data/test/lib/examples/pcbin/migration_test.rb +37 -16
  114. metadata +24 -10
  115. data/History.txt +0 -50
@@ -1,4 +1,4 @@
1
- Protocol: CollectionProtocol.short_title
1
+ Protocol: CollectionProtocol.title
2
2
  Patient: CollectionProtocolRegistration.protocol_participant_identifier
3
3
  Specimen Type: TissueSpecimen.specimen_type
4
4
  Year of Diagnosis: Participant::Clinical::NewDiagnosisHealthAnnotation.date_of_examination
@@ -1,4 +1,4 @@
1
- Protocol: CollectionProtocol.short_title
1
+ Protocol: CollectionProtocol.title
2
2
  Patient: CollectionProtocolRegistration.protocol_participant_identifier
3
3
  Race: Race.name
4
4
  Ethnicity: Participant.ethnicity
@@ -1,4 +1,4 @@
1
- Protocol: CollectionProtocol.short_title
1
+ Protocol: CollectionProtocol.title
2
2
  Patient: CollectionProtocolRegistration.protocol_participant_identifier
3
3
  Specimen Type: TissueSpecimen.specimen_type
4
4
  Year of Surgery: Participant::Clinical::Duration.start_date
@@ -1,4 +1,4 @@
1
- Protocol: CollectionProtocol.short_title
1
+ Protocol: CollectionProtocol.title
2
2
  Patient: CollectionProtocolRegistration.protocol_participant_identifier
3
3
  Clinical Staging System: Participant::Clinical::LabAnnotation.other_lab_test_name
4
4
  Clinical T Stage: Participant::Clinical::LabAnnotation.result
@@ -1,4 +1,4 @@
1
- Protocol: CollectionProtocol.short_title
1
+ Protocol: CollectionProtocol.title
2
2
  Patient: CollectionProtocolRegistration.protocol_participant_identifier
3
3
  Agent: Participant::Clinical::TreatmentAnnotation.agent
4
4
  Dose: Participant::Clinical::TreatmentAnnotation.dose
data/lib/catissue.rb CHANGED
@@ -10,7 +10,7 @@ rescue LoadError
10
10
  end
11
11
 
12
12
  require 'caruby/util/log'
13
- require 'catissue/resource'
13
+ require 'catissue/domain'
14
14
  require 'catissue/database'
15
15
 
16
16
  # CaTissue wraps the caTissue Java API.
@@ -13,32 +13,22 @@ module CaTissue
13
13
  self.class.annotation_attribute?(attr) ? send(mth, *args) : super
14
14
  rescue AnnotationError
15
15
  raise
16
- rescue Exception
17
- raise
16
+ rescue NoMethodError
18
17
  super
19
18
  end
20
19
  end
21
20
 
22
- # Creates a {Annotation::Proxy} whose hook reference is set to this annotatable object.
23
- #
24
- # @param [Class] the proxy class
25
- # @return [Resource] the new proxy
26
- def create_proxy(klass)
27
- # make the proxy instance
28
- pxy = klass.new
29
- # set the proxy hook reference to this hook instance
30
- pxy.hook = self
31
- logger.debug { "Created #{qp} #{klass.domain_module.qp} annotation proxy #{pxy}." }
32
- pxy
33
- end
34
-
35
- # @param [Symbol] attribute the hook -> annotation attribute
36
- # @return [Annotation] the hook -> proxy attribute
37
- # @raise (see AnnotatableClass#annotation_proxy_attribute)
38
- def annotation_proxy(attribute)
39
- pxy_attr = self.class.annotation_proxy_attribute(attribute)
40
- # the hook -> proxy attribute value
41
- send(pxy_attr)
21
+ # @param [Symbol] attribute the hook => proxy attribute
22
+ # @param [Annotation] the annotation
23
+ # @return [Proxy] the hook proxy for the given annotation
24
+ def proxy_for(attribute, annotation)
25
+ @ann_pxy_hash ||= LazyHash.new do |ann|
26
+ pxy = self.class.attribute_metadata(attribute).type.new
27
+ pxy.hook = self
28
+ send(attribute) << pxy
29
+ pxy
30
+ end
31
+ @ann_pxy_hash[annotation]
42
32
  end
43
33
  end
44
34
  end
@@ -1,6 +1,7 @@
1
- require 'forwardable'
2
1
  require 'caruby/util/inflector'
2
+ require 'caruby/domain/metadata'
3
3
  require 'catissue/annotation/annotation_module'
4
+ require 'catissue/annotation/de_integration'
4
5
 
5
6
  module CaTissue
6
7
  # Mix-in for extending a caTissue domain class with annotations.
@@ -9,32 +10,47 @@ module CaTissue
9
10
  # @return [Integer, nil] the the hook class designator that is used by caTissue to persist primary
10
11
  # annotation objects, or nil if this is not a primary annotation class
11
12
  attr_reader :entity_id
13
+
14
+ # @return [Class] the {DEIntegration} proxy class (nil for 1.1 caTissue)
15
+ def de_integration_proxy_class
16
+ @de_integration_proxy_class or (superclass.de_integration_proxy_class if superclass < Annotatable)
17
+ end
18
+
19
+ # Adds {CaRuby::Domain::Metadata} and {AnnotatableClass} functionality to the given class.
20
+ #
21
+ # @param [Class] the domain class to extend
22
+ def self.extend_class(klass)
23
+ # Enable the class meta-data.
24
+ klass.extend(CaRuby::Domain::Metadata)
25
+ klass.extend(self)
26
+ end
12
27
 
13
28
  def self.extended(klass)
14
29
  super
15
- # the annotation name => spec hash
30
+ # Initialize the class annotation hashes.
16
31
  klass.class_eval do
17
- extend Forwardable
32
+ # Enable the class meta-data.
33
+ # the annotation name => spec hash
18
34
  @ann_spec_hash = {}
19
- @local_ann_attrs = []
35
+ # the annotation module => proxy hash
36
+ @ann_mod_pxy_hash = {}
20
37
  end
21
38
  end
22
-
39
+
23
40
  # @return [Integer, nil] this class's entity id, if it exists, otherwise the superclass effective entity id
24
41
  # if the superclass is an annotation class
25
42
  def effective_entity_id
26
43
  @entity_id or parent_entity_id
27
44
  end
28
-
45
+
29
46
  # Loads the annotations defined for this class if necessary.
30
47
  def ensure_annotations_loaded
31
48
  # referencing the annotations loads them
32
49
  annotation_modules
33
50
  end
34
-
35
- # If there is an existing annotation whose proxy accessor is the
36
- # given symbol, then return true. Otherwise, attempt to import
37
- # an annotation and return whether the import was successful.
51
+
52
+ # If there is an existing annotation whose proxy accessor is the given symbol, then return true.
53
+ # Otherwise, attempt to import an annotation and return whether the import was successful.
38
54
  #
39
55
  # @param [Symbol] symbol the potential accessor attribute
40
56
  # @return [Boolean] whether there is a corresponding annotation
@@ -45,34 +61,19 @@ module CaTissue
45
61
  annotation_defined?(symbol)
46
62
  end
47
63
 
48
- # Refines the {CaRuby::ResourceAttributes#toxic_attributes} to exclude annotation attributes.
64
+ # Refines the {CaRuby::Domain::Attributes#toxic_attributes} to exclude annotation attributes.
49
65
  #
50
66
  # @return [<Symbol>] the non-annotation unfetched attributes
51
67
  def toxic_attributes
52
68
  @anntbl_toxic_attrs ||= unfetched_attributes.compose { |attr_md| not attr_md.type < Annotation }
53
69
  end
54
-
55
- def annotation_proxy_attribute(attribute)
56
- annotatable_class_hierarchy.detect_value { |klass| klass.local_annotation_proxy_attribute(attribute) }
57
- end
58
70
 
59
- # Makes a new attribute in this hook class for the given annotation proxy domain attribute.
60
- # The hook annotation reference attribute delegates to the proxy. This method is intended for
61
- # the exclusive use of {Annotation::ProxyClass}.
62
- #
63
71
  # @param [AnnotationModule] mod the annotation module
64
- # @param [Symbol] attribute the proxy => annotation reference
65
- def create_annotation_attribute(mod, attribute)
66
- pxy = mod.proxy
67
- pxy_attr = @ann_mod_pxy_hash[mod]
68
- ann_attr_md = pxy.attribute_metadata(attribute)
69
- # the type referenced by the annotation proxy
70
- klass = ann_attr_md.type
71
- # create annotation accessors which delegate to the proxy
72
- def_delegators(pxy_attr, *ann_attr_md.accessors)
73
- logger.debug { "Created #{qp}.#{attribute} which delegates to the annotation proxy #{pxy_attr}." }
74
- # add the attribute
75
- add_annotation_attribute(attribute, klass)
72
+ # @return [Symbol] the corresponding annotation proxy reference attribute
73
+ def annotation_proxy_attribute(mod)
74
+ @ann_mod_pxy_hash[mod] or
75
+ (superclass.annotation_proxy_attribute(mod) if superclass < Annotatable) or
76
+ raise AnnotationError.new("#{qp} #{mod} proxy attribute not found.")
76
77
  end
77
78
 
78
79
  # Loads the annotations, if necessary, and tries to get the constant again.
@@ -88,6 +89,14 @@ module CaTissue
88
89
  const_get(symbol)
89
90
  end
90
91
  end
92
+
93
+ # Filters {CaRuby::Domain::Attributes#loadable_attributes} to exclude the {#annotation_attributes}
94
+ # since annotation lazy-loading is not supported.
95
+ #
96
+ # @return (see CaRuby::Domain::Attributes#loadable_attributes)
97
+ def loadable_attributes
98
+ @antbl_ld_attrs ||= super.compose { |attr_md| not attr_md.type < Annotation }
99
+ end
91
100
 
92
101
  def printable_attributes
93
102
  @prbl_attrs ||= super.union(annotation_attributes)
@@ -106,7 +115,7 @@ module CaTissue
106
115
  end
107
116
 
108
117
  def annotation_attributes
109
- @ann_attrs ||= append_ancestor_enum(@local_ann_attrs) do |sc|
118
+ @ann_attrs ||= append_ancestor_enum(@ann_mod_pxy_hash.enum_values) do |sc|
110
119
  sc.annotation_attributes if sc < Annotatable
111
120
  end
112
121
  end
@@ -118,21 +127,23 @@ module CaTissue
118
127
  @ann_mods ||= load_annotations
119
128
  end
120
129
 
121
- # @param [Symbol] attribute the annotation attribute
122
- # @return [Symbol] the annotation proxy attribute
123
- # @raise [TypeError] if the given attribute is not an annotation attribute
124
- def local_annotation_proxy_attribute(attribute)
125
- unless annotation_attribute?(attribute) then
126
- raise TypeError.new("#{qp} #{attribute} is not an annotation attribute")
127
- end
128
- # the annotation class
129
- klass = attribute_metadata(attribute).type
130
- mod = klass.domain_module
131
- @ann_mod_pxy_hash[mod]
132
- end
133
-
134
130
  private
135
131
 
132
+ # @param [String] name the proxy record entry class name
133
+ def annotation_proxy_class_name=(name)
134
+ @de_integration_proxy_class = Annotation::DEIntegration.proxy(name)
135
+ if @de_integration_proxy_class then
136
+ # hide the internal caTissue proxy collection attribute
137
+ attr = detect_attribute_with_type(@de_integration_proxy_class)
138
+ if attr then
139
+ remove_attribute(attr)
140
+ logger.debug { "Hid the internal caTissue #{qp} annotation record-keeping attribute #{attr}." }
141
+ end
142
+ else
143
+ logger.debug { "Ignored the missing caTissue #{qp} proxy class name #{name}, presumably unsupported in this caTissue release." }
144
+ end
145
+ end
146
+
136
147
  # Loads the annotation modules in the class hierarchy.
137
148
  #
138
149
  # @return [<AnnotationModule>] an Enumerable on the loaded annotation modules
@@ -175,16 +186,17 @@ module CaTissue
175
186
  #
176
187
  # @return [<AnnotationModule>] the loaded annotation modules
177
188
  def load_local_annotations
178
- # the annotation module => proxy hash
179
- @ann_mod_pxy_hash = {}
180
189
  # an annotated class has a hook entity id
181
- unless @ann_spec_hash.empty? then
182
- @entity_id = Annotation::EntityFacade.instance.hook_entity_id(self)
183
- end
190
+ unless @ann_spec_hash.empty? then initialize_annotation_holder end
184
191
  # build the annotations
185
192
  @ann_spec_hash.map { |name, opts| import_annotation(name, opts) }
193
+ end
194
+
195
+ # Determines this annotated class's {#entity_id} and {#de_integration_proxy_class}.
196
+ def initialize_annotation_holder
197
+ @entity_id = Annotation::EntityFacade.instance.hook_entity_id(self)
186
198
  end
187
-
199
+
188
200
  # @param [Symbol] attribute the annotation accessor
189
201
  # @return [Module] the annotation module which implements the attribute
190
202
  def annotation_attribute_module(attribute)
@@ -199,20 +211,19 @@ module CaTissue
199
211
  # @raise [AnnotationError] if there is no annotation proxy class
200
212
  def import_annotation(name, opts)
201
213
  logger.debug { "Importing #{qp} annotation #{name}..." }
202
- # make the annotation module scoped by this Annotatable class
203
- class_eval("module #{name}; end")
204
- mod = const_get(name)
205
- # append the AnnotationModule methods
206
- AnnotationModule.extend_module(mod, self, opts)
207
- # make the proxy attribute
208
- create_proxy_attribute(mod)
209
- # make the annotation dependent attributes
210
- create_annotation_attributes(mod)
211
- # add proxy references
212
- mod.ensure_proxy_attributes_are_defined
213
- mod.add_annotation_dependents
214
- logger.debug { "Imported #{qp} annotation #{name}." }
215
- mod
214
+ # Make the annotation module scoped by this Annotatable class.
215
+ class_eval("class #{name}; end")
216
+ klass = const_get(name)
217
+ # Append the AnnotationModule methods.
218
+ AnnotationModule.extend_module(klass, self, opts)
219
+ # Make the proxy attribute.
220
+ attr = create_proxy_attribute(klass)
221
+ # The proxy is a logical dependent.
222
+ add_dependent_attribute(attr, :logical)
223
+ logger.debug { "Created #{qp} annotation proxy logical dependent reference attribute #{attr}." }
224
+ # Fill out the dependency hierarchy.
225
+ klass.proxy.build_annotation_dependency_hierarchy
226
+ klass
216
227
  end
217
228
 
218
229
  # Returns whether this class has an annotation whose proxy accessor is the
@@ -229,59 +240,21 @@ module CaTissue
229
240
  # The attribute reader creates an {Annotation::Proxy} instance of the method
230
241
  # receiver {Annotatable} instance on demand.
231
242
  #
232
- # @param [AnnotationModule] mod the subject annotation module
243
+ # @param [AnnotationModule] klass the subject annotation
233
244
  # @return [Symbol] the proxy attribute
234
- def create_proxy_attribute(mod)
245
+ def create_proxy_attribute(klass)
235
246
  # the proxy class
236
- pxy = mod.proxy
237
- # the proxy attribute
238
- attr = mod.name.demodulize.underscore.to_sym
239
- # define the proxy attribute
240
- attr_create_on_demand_accessor(attr) { |obj| obj.create_proxy(pxy) }
241
- # add it as a standard (but unpersisted) attribute
242
- add_attribute(attr, pxy, :unsaved)
243
- # create the proxy => hook inverse
244
- pxy.set_hook(self, attr)
245
- logger.debug { "Added #{qp} #{mod.qp} annotation proxy attribute #{attr}." }
247
+ pxy = klass.proxy
248
+ # the proxy attribute symbol
249
+ attr = klass.name.demodulize.underscore.to_sym
250
+ # Define the proxy attribute.
251
+ attr_create_on_demand_accessor(attr) { Set.new }
252
+ # Register the attribute.
253
+ add_attribute(attr, pxy, :collection, :saved)
254
+ logger.debug { "Added #{qp} #{klass.qp} annotation proxy attribute #{attr} of type #{pxy}." }
246
255
  # the annotation module => proxy attribute association
247
- @ann_mod_pxy_hash[mod] = attr
256
+ @ann_mod_pxy_hash[klass] = attr
248
257
  attr
249
258
  end
250
-
251
- # Makes a new attribute in this hook class for each of the given annotation module's
252
- # proxy domain attributes. The hook annotation reference attribute delegates to the
253
- # proxy.
254
- #
255
- # @param [AnnotationModule] mod the subject annotation module
256
- # @param [Symbol] proxy_attribute the hook => proxy reference
257
- def create_annotation_attributes(mod)
258
- # create annotation attributes which delegate to the proxy
259
- mod.proxy.annotation_attributes.each do |attr|
260
- create_annotation_attribute(mod, attr)
261
- end
262
- end
263
-
264
- # Adds the given annotation attribute as a dependent collection attribute with meta-data.
265
- #
266
- # @param [Symbol] attribute the annotation accessor
267
- # @param [Class] type the attribute domain type
268
- def add_annotation_attribute(attribute, type)
269
- logger.debug { "Adding #{qp} #{type.qp} annotation attribute #{attribute}..." }
270
- # Mark the attribute as a collection.
271
- add_attribute(attribute, type, :collection)
272
-
273
- # the camel-case attribute is a potential alias
274
- jattr = attribute.to_s.camelize(:lower).to_sym
275
- unless attribute == jattr then
276
- add_attribute_aliases(jattr => attribute)
277
- end
278
-
279
- # the annotation is a dependent
280
- add_dependent_attribute(attribute, :logical)
281
- # add the attribute to the local collection
282
- @local_ann_attrs << attribute
283
-
284
- attribute
285
- end
286
259
  end
287
260
  end
@@ -1,58 +1,23 @@
1
1
  require 'caruby/resource'
2
2
  require 'caruby/domain/id_alias'
3
+ require 'catissue/domain/hash_code'
3
4
 
4
5
  module CaTissue
5
6
  # Annotation acceess error class.
6
7
  class AnnotationError < StandardError; end
7
8
 
8
- # Annotation class mix-in.
9
+ # Annotation is the caTissue dynamic extension class mix-in.
10
+ #
11
+ # @quirk caTissue Annotation RecordEntry proxy classes implements hashCode with the identifier.
12
+ # Consequently, a set member is not found after identifier assignment.
13
+ # The work-around is to include the HashCode mixin, which reimplements the hash and equality
14
+ # test methods to be invariant with respect to identifier assignment.
9
15
  module Annotation
10
- include CaRuby::Resource, CaRuby::IdAlias
16
+ include CaRuby::Resource, CaRuby::IdAlias, HashCode
11
17
 
12
- # Returns the CaTissue::Database which stores this object.
18
+ # @return [Database] the database which stores this object
13
19
  def database
14
20
  CaTissue::Database.instance
15
21
  end
16
-
17
- # Updates the annotation proxy to reflect the hook, if necessary.
18
- #
19
- # @see Proxy#ensure_identifier_reflects_hook
20
- def ensure_proxy_reflects_hook
21
- pxy = proxy || return
22
- pxy.ensure_identifier_reflects_hook
23
- end
24
-
25
- # @return [Annotatable, nil] the hook object which owns this annotation, or nil if this annotation
26
- # is not directly owned by a hook entity
27
- def hook
28
- pxy_attr_md = self.class.proxy_attribute_metadata
29
- send(pxy_attr_md.reader) if pxy_attr_md
30
- end
31
-
32
- # If there is no conventional owner, then try the hook.
33
- #
34
- # caTissue alert - DE annotations have a physical dependency ownership model that is at odds
35
- # with the logical model. An annotation does not directly reference its static hook owner
36
- # instance. Rather, it references the hook proxy which stands in for the hook entity in the
37
- # annotation package.
38
- #
39
- # @return the {CaRuby::Resource#owner} or the {#hook}
40
- def owner
41
- super or hook
42
- end
43
-
44
- # @return [Proxy, nil] the proxy which references this annotation, or nil if this is not a
45
- # primary annotation
46
- def proxy
47
- # the annotation owner hook instance
48
- ownr = hook || return
49
- # the hook -> annotation reference attribute
50
- attr = self.class.hook_proxy_attribute
51
- if attr.nil? then
52
- raise AnnotationError.new("Primary annotation #{qp} references hook #{hook} but doesn't have a hook proxy attribute")
53
- end
54
- # the owner proxy for the attribute
55
- ownr.annotation_proxy(attr)
56
- end
57
22
  end
58
23
  end