caruby-tissue 1.5.6 → 2.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (255) hide show
  1. data/Gemfile +17 -0
  2. data/History.md +5 -1
  3. data/README.md +2 -2
  4. data/bin/crtdump +2 -8
  5. data/bin/crtexample +2 -5
  6. data/bin/crtmigrate +3 -6
  7. data/bin/crtsmoke +3 -8
  8. data/conf/wustl/{log4j.properties → linux/log4j.properties} +3 -3
  9. data/conf/wustl/windows/log4j.properties +40 -0
  10. data/examples/galena/Gemfile +16 -0
  11. data/examples/galena/Gemfile.lock +88 -0
  12. data/examples/galena/README.md +16 -16
  13. data/examples/galena/Rakefile +30 -0
  14. data/examples/galena/bin/seed +5 -11
  15. data/examples/galena/conf/annotation/defaults.yaml +2 -0
  16. data/examples/galena/conf/{migration/annotation_fields.yaml → annotation/fields.yaml} +2 -4
  17. data/examples/galena/conf/defaults.yaml +9 -0
  18. data/examples/galena/conf/{migration/filter_fields.yaml → filter/fields.yaml} +0 -1
  19. data/examples/galena/conf/filter/values.yaml +8 -0
  20. data/examples/galena/conf/{migration/frozen_defaults.yaml → frozen/defaults.yaml} +0 -0
  21. data/examples/galena/conf/{migration/frozen_fields.yaml → frozen/fields.yaml} +0 -2
  22. data/examples/galena/conf/{migration/general_fields.yaml → general/fields.yaml} +0 -24
  23. data/examples/galena/conf/registration/fields.yaml +6 -0
  24. data/examples/galena/conf/{migration/simple_fields.yaml → simple/fields.yaml} +1 -6
  25. data/examples/galena/data/annotation.csv +1 -1
  26. data/examples/galena/data/filter.csv +1 -1
  27. data/examples/galena/data/frozen.csv +1 -1
  28. data/examples/galena/data/general.csv +1 -1
  29. data/examples/galena/data/registration.csv +1 -1
  30. data/examples/galena/data/simple.csv +1 -1
  31. data/examples/galena/galena.gemspec +24 -0
  32. data/examples/galena/lib/galena/filter.rb +25 -0
  33. data/examples/galena/lib/galena/{tissue/migration/frozen_shims.rb → frozen.rb} +6 -10
  34. data/examples/galena/lib/galena/seed.rb +126 -0
  35. data/examples/galena/lib/galena/version.rb +3 -0
  36. data/examples/galena/lib/galena.rb +18 -7
  37. data/examples/galena/log/galena.log +37351 -0
  38. data/examples/galena/log/galena.log.0 +147830 -0
  39. data/examples/galena/spec/annotation_spec.rb +46 -0
  40. data/examples/galena/spec/filter_spec.rb +94 -0
  41. data/examples/galena/spec/frozen_spec.rb +39 -0
  42. data/examples/galena/spec/general_spec.rb +62 -0
  43. data/examples/galena/spec/registration_spec.rb +37 -0
  44. data/examples/galena/spec/seed.rb +107 -0
  45. data/examples/galena/spec/simple_spec.rb +58 -0
  46. data/examples/galena/spec/spec_helper.rb +11 -0
  47. data/examples/galena/spec/support/migration.rb +70 -0
  48. data/lib/catissue/annotation/annotatable.rb +10 -8
  49. data/lib/catissue/annotation/annotation.rb +7 -7
  50. data/lib/catissue/annotation/de_integration.rb +9 -20
  51. data/lib/catissue/annotation/importer.rb +148 -0
  52. data/lib/catissue/annotation/introspector.rb +32 -0
  53. data/lib/catissue/annotation/metadata.rb +422 -0
  54. data/lib/catissue/annotation/proxy.rb +2 -2
  55. data/lib/catissue/annotation/proxy_class.rb +45 -30
  56. data/lib/catissue/annotation/record_entry_proxy.rb +2 -2
  57. data/lib/catissue/cli/command.rb +14 -24
  58. data/lib/catissue/cli/example.rb +5 -3
  59. data/lib/catissue/cli/migrate.rb +45 -37
  60. data/lib/catissue/cli/smoke.rb +2 -3
  61. data/lib/catissue/database/annotation/annotation_service.rb +8 -17
  62. data/lib/catissue/database/annotation/entity_facade.rb +33 -30
  63. data/lib/catissue/database/annotation/id_generator.rb +1 -1
  64. data/lib/catissue/database/annotation/integration_service.rb +11 -4
  65. data/lib/catissue/database/annotation/reference_writer.rb +38 -38
  66. data/lib/catissue/database/controlled_value_finder.rb +13 -28
  67. data/lib/catissue/database/controlled_values.rb +73 -45
  68. data/lib/catissue/database.rb +637 -277
  69. data/lib/catissue/domain/abstract_domain_object.rb +5 -0
  70. data/lib/catissue/domain/abstract_position.rb +3 -5
  71. data/lib/catissue/domain/abstract_specimen.rb +79 -65
  72. data/lib/catissue/domain/abstract_specimen_collection_group.rb +3 -6
  73. data/lib/catissue/domain/address.rb +0 -2
  74. data/lib/catissue/domain/cancer_research_group.rb +0 -3
  75. data/lib/catissue/domain/capacity.rb +2 -4
  76. data/lib/catissue/domain/check_in_check_out_event_parameter.rb +0 -3
  77. data/lib/catissue/domain/collection_event_parameters.rb +2 -7
  78. data/lib/catissue/domain/collection_protocol.rb +11 -16
  79. data/lib/catissue/domain/collection_protocol_event.rb +19 -12
  80. data/lib/catissue/domain/collection_protocol_registration.rb +8 -12
  81. data/lib/catissue/domain/consent_tier_response.rb +0 -4
  82. data/lib/catissue/domain/consent_tier_status.rb +1 -4
  83. data/lib/catissue/domain/container.rb +10 -10
  84. data/lib/catissue/domain/container_position.rb +4 -7
  85. data/lib/catissue/domain/container_type.rb +4 -7
  86. data/lib/catissue/domain/department.rb +0 -3
  87. data/lib/catissue/domain/disposal_event_parameters.rb +5 -5
  88. data/lib/catissue/domain/embedded_event_parameters.rb +1 -4
  89. data/lib/catissue/domain/external_identifier.rb +0 -12
  90. data/lib/catissue/domain/frozen_event_parameters.rb +1 -4
  91. data/lib/catissue/domain/institution.rb +0 -3
  92. data/lib/catissue/domain/new_specimen_array_order_item.rb +0 -5
  93. data/lib/catissue/domain/order_details.rb +0 -2
  94. data/lib/catissue/domain/participant/clinical/chemotherapy.rb +1 -3
  95. data/lib/catissue/domain/participant/clinical/duration.rb +2 -4
  96. data/lib/catissue/domain/participant/clinical/radiation_therapy.rb +2 -4
  97. data/lib/catissue/domain/participant.rb +22 -24
  98. data/lib/catissue/domain/participant_medical_identifier.rb +0 -4
  99. data/lib/catissue/domain/password.rb +0 -4
  100. data/lib/catissue/domain/race.rb +0 -3
  101. data/lib/catissue/domain/received_event_parameters.rb +3 -6
  102. data/lib/catissue/domain/site.rb +1 -4
  103. data/lib/catissue/domain/specimen/pathology/additional_finding.rb +12 -0
  104. data/lib/catissue/domain/specimen/pathology/details.rb +12 -0
  105. data/lib/catissue/domain/specimen/pathology/gleason_score.rb +12 -0
  106. data/lib/catissue/domain/specimen/pathology/histologic_grade.rb +12 -0
  107. data/lib/catissue/domain/specimen/pathology/histologic_type.rb +19 -0
  108. data/lib/catissue/domain/specimen/pathology/histologic_variant_type.rb +12 -0
  109. data/lib/catissue/domain/specimen/pathology/invasion.rb +12 -0
  110. data/lib/catissue/domain/specimen/pathology/prostate_specimen_gleason_score.rb +5 -11
  111. data/lib/catissue/domain/specimen/pathology/prostate_specimen_pathology_annotation.rb +12 -12
  112. data/lib/catissue/domain/specimen/pathology/specimen_additional_finding.rb +5 -14
  113. data/lib/catissue/domain/specimen/pathology/specimen_base_solid_tissue_pathology_annotation.rb +6 -21
  114. data/lib/catissue/domain/specimen/pathology/specimen_details.rb +4 -10
  115. data/lib/catissue/domain/specimen/pathology/specimen_histologic_grade.rb +4 -10
  116. data/lib/catissue/domain/specimen/pathology/specimen_histologic_type.rb +6 -14
  117. data/lib/catissue/domain/specimen/pathology/specimen_histologic_variant_type.rb +5 -11
  118. data/lib/catissue/domain/specimen/pathology/specimen_invasion.rb +5 -11
  119. data/lib/catissue/domain/specimen.rb +113 -76
  120. data/lib/catissue/domain/specimen_array.rb +0 -3
  121. data/lib/catissue/domain/specimen_array_content.rb +1 -4
  122. data/lib/catissue/domain/specimen_array_type.rb +1 -4
  123. data/lib/catissue/domain/specimen_characteristics.rb +0 -3
  124. data/lib/catissue/domain/specimen_collection_group/pathology/base_pathology_annotation.rb +2 -4
  125. data/lib/catissue/domain/specimen_collection_group/pathology/base_solid_tissue_pathology_annotation.rb +2 -4
  126. data/lib/catissue/domain/specimen_collection_group.rb +43 -53
  127. data/lib/catissue/domain/specimen_event_parameters.rb +24 -32
  128. data/lib/catissue/domain/specimen_position.rb +8 -5
  129. data/lib/catissue/domain/specimen_protocol.rb +3 -6
  130. data/lib/catissue/domain/specimen_requirement.rb +22 -20
  131. data/lib/catissue/domain/storage_container.rb +9 -12
  132. data/lib/catissue/domain/storage_type.rb +6 -10
  133. data/lib/catissue/domain/transfer_event_parameters.rb +3 -6
  134. data/lib/catissue/domain/user.rb +22 -29
  135. data/lib/catissue/{util → helpers}/collectible.rb +23 -18
  136. data/lib/catissue/helpers/collectible_event_parameters.rb +68 -0
  137. data/lib/catissue/helpers/controlled_value.rb +35 -0
  138. data/lib/catissue/{domain → helpers}/hash_code.rb +0 -0
  139. data/lib/catissue/{util → helpers}/location.rb +6 -5
  140. data/lib/catissue/helpers/log.rb +4 -0
  141. data/lib/catissue/{util → helpers}/person.rb +1 -1
  142. data/lib/catissue/{util → helpers}/position.rb +10 -8
  143. data/lib/catissue/helpers/properties_loader.rb +143 -0
  144. data/lib/catissue/{util → helpers}/storable.rb +2 -1
  145. data/lib/catissue/{util → helpers}/storage_type_holder.rb +9 -3
  146. data/lib/catissue/{annotation/annotatable_class.rb → metadata.rb} +73 -95
  147. data/lib/catissue/migration/migratable.rb +93 -44
  148. data/lib/catissue/migration/migrator.rb +26 -42
  149. data/lib/catissue/migration/shims.rb +1 -1
  150. data/lib/catissue/migration/unique.rb +76 -0
  151. data/lib/catissue/resource.rb +16 -20
  152. data/lib/catissue/version.rb +1 -1
  153. data/lib/catissue/wustl/logger.rb +52 -32
  154. data/lib/catissue.rb +38 -20
  155. data/test/lib/catissue/database/controlled_values_test.rb +22 -27
  156. data/test/lib/catissue/database/database_test.rb +18 -0
  157. data/test/lib/catissue/domain/address_test.rb +9 -11
  158. data/test/lib/catissue/domain/ca_tissue_test_defaults_test.rb +5 -16
  159. data/test/lib/catissue/domain/capacity_test.rb +2 -2
  160. data/test/lib/catissue/domain/collection_event_parameters_test.rb +16 -8
  161. data/test/lib/catissue/domain/collection_protocol_event_test.rb +1 -1
  162. data/test/lib/catissue/domain/collection_protocol_registration_test.rb +26 -16
  163. data/test/lib/catissue/domain/collection_protocol_test.rb +2 -2
  164. data/test/lib/catissue/domain/container_position_test.rb +7 -4
  165. data/test/lib/catissue/domain/department_test.rb +3 -3
  166. data/test/lib/catissue/domain/disposal_event_parameters_test.rb +1 -1
  167. data/test/lib/catissue/domain/external_identifier_test.rb +5 -1
  168. data/test/lib/catissue/domain/location_test.rb +4 -4
  169. data/test/lib/catissue/domain/participant_medical_identifier_test.rb +3 -3
  170. data/test/lib/catissue/domain/participant_test.rb +33 -20
  171. data/test/lib/catissue/domain/received_event_parameters_test.rb +19 -0
  172. data/test/lib/catissue/domain/site_test.rb +2 -2
  173. data/test/lib/catissue/domain/specimen_array_test.rb +3 -3
  174. data/test/lib/catissue/domain/specimen_array_type_test.rb +6 -6
  175. data/test/lib/catissue/domain/specimen_characteristics_test.rb +1 -1
  176. data/test/lib/catissue/domain/specimen_collection_group_test.rb +49 -13
  177. data/test/lib/catissue/domain/specimen_event_parameters_test.rb +4 -4
  178. data/test/lib/catissue/domain/specimen_position_test.rb +1 -1
  179. data/test/lib/catissue/domain/specimen_requirement_test.rb +2 -2
  180. data/test/lib/catissue/domain/specimen_test.rb +58 -24
  181. data/test/lib/catissue/domain/storage_container_test.rb +3 -16
  182. data/test/lib/catissue/domain/storage_type_test.rb +3 -3
  183. data/test/lib/catissue/domain/transfer_event_parameters_test.rb +17 -17
  184. data/test/lib/catissue/domain/user_test.rb +32 -34
  185. data/test/lib/catissue/helpers/properties_loader_test.rb +19 -0
  186. data/test/lib/catissue/migration/{test_case.rb → helpers/test_case.rb} +30 -20
  187. data/test/lib/examples/galena/tissue/domain/examples_test.rb +28 -38
  188. data/test/lib/examples/galena/tissue/helpers/test_case.rb +24 -0
  189. metadata +175 -99
  190. data/bin/crtextract +0 -47
  191. data/examples/galena/conf/extract/simple_fields.yaml +0 -4
  192. data/examples/galena/conf/migration/annotation_defaults.yaml +0 -2
  193. data/examples/galena/conf/migration/filter_defaults.yaml +0 -1
  194. data/examples/galena/conf/migration/filter_values.yaml +0 -13
  195. data/examples/galena/conf/migration/participant_fields.yaml +0 -4
  196. data/examples/galena/conf/migration/registration_fields.yaml +0 -5
  197. data/examples/galena/data/participant.csv +0 -1
  198. data/examples/galena/lib/galena/tissue/migration/filter_shims.rb +0 -41
  199. data/examples/galena/lib/galena/tissue/seed/defaults.rb +0 -127
  200. data/examples/psbin/README.md +0 -45
  201. data/examples/psbin/conf/adjuvant_hormone_defaults.yaml +0 -2
  202. data/examples/psbin/conf/adjuvant_radiation_defaults.yaml +0 -3
  203. data/examples/psbin/conf/biopsy_defaults.yaml +0 -3
  204. data/examples/psbin/conf/biopsy_fields.yaml +0 -9
  205. data/examples/psbin/conf/neoadjuvant_hormone_defaults.yaml +0 -2
  206. data/examples/psbin/conf/neoadjuvant_radiation_defaults.yaml +0 -3
  207. data/examples/psbin/conf/patient_defaults.yaml +0 -3
  208. data/examples/psbin/conf/patient_fields.yaml +0 -5
  209. data/examples/psbin/conf/surgery_defaults.yaml +0 -4
  210. data/examples/psbin/conf/surgery_fields.yaml +0 -15
  211. data/examples/psbin/conf/t_stage_defaults.yaml +0 -1
  212. data/examples/psbin/conf/t_stage_fields.yaml +0 -4
  213. data/examples/psbin/conf/therapy_fields.yaml +0 -5
  214. data/examples/psbin/data/adjuvant_hormone.csv +0 -1
  215. data/examples/psbin/data/adjuvant_radiation.csv +0 -1
  216. data/examples/psbin/data/biopsy.csv +0 -1
  217. data/examples/psbin/data/neoadjuvant_hormone.csv +0 -1
  218. data/examples/psbin/data/neoadjuvant_radiation.csv +0 -1
  219. data/examples/psbin/data/patient.csv +0 -1
  220. data/examples/psbin/data/surgery.csv +0 -1
  221. data/examples/psbin/data/t_stage.csv +0 -1
  222. data/examples/psbin/lib/psbin/biopsy_shims.rb +0 -15
  223. data/examples/psbin/lib/psbin/surgery_shims.rb +0 -15
  224. data/lib/catissue/annotation/annotation_class.rb +0 -406
  225. data/lib/catissue/annotation/annotation_module.rb +0 -106
  226. data/lib/catissue/domain.rb +0 -26
  227. data/lib/catissue/extract/command.rb +0 -31
  228. data/lib/catissue/extract/delta.rb +0 -58
  229. data/lib/catissue/extract/extractor.rb +0 -99
  230. data/lib/catissue/migration/uniquify.rb +0 -2
  231. data/lib/catissue/util/collectible_event_parameters.rb +0 -71
  232. data/lib/catissue/util/controlled_value.rb +0 -29
  233. data/lib/catissue/util/uniquify.rb +0 -86
  234. data/test/fixtures/catissue/domain/conf/catissue_override.yaml +0 -9
  235. data/test/fixtures/catissue/extract/conf/scg_extract.yaml +0 -3
  236. data/test/fixtures/catissue/extract/conf/scg_fields.yaml +0 -3
  237. data/test/fixtures/catissue/extract/conf/spc_extract.yaml +0 -3
  238. data/test/fixtures/catissue/extract/conf/spc_fields.yaml +0 -4
  239. data/test/fixtures/lib/catissue/defaults_test_fixture.rb +0 -206
  240. data/test/fixtures/lib/examples/galena/migration/alt_key_shims.rb +0 -7
  241. data/test/lib/catissue/domain/base_haemotology_pathology_test.rb +0 -24
  242. data/test/lib/catissue/extract/delta_test.rb +0 -25
  243. data/test/lib/catissue/extract/extractor_test.rb +0 -43
  244. data/test/lib/catissue/import/importable_module_test.rb +0 -14
  245. data/test/lib/catissue/test_case.rb +0 -247
  246. data/test/lib/examples/galena/tissue/migration/annotation_test.rb +0 -29
  247. data/test/lib/examples/galena/tissue/migration/filter_test.rb +0 -29
  248. data/test/lib/examples/galena/tissue/migration/frozen_test.rb +0 -36
  249. data/test/lib/examples/galena/tissue/migration/general_test.rb +0 -56
  250. data/test/lib/examples/galena/tissue/migration/participant_test.rb +0 -61
  251. data/test/lib/examples/galena/tissue/migration/registration_test.rb +0 -17
  252. data/test/lib/examples/galena/tissue/migration/seedify.rb +0 -119
  253. data/test/lib/examples/galena/tissue/migration/simple_test.rb +0 -30
  254. data/test/lib/examples/galena/tissue/migration/test_case.rb +0 -72
  255. data/test/lib/examples/psbin/migration_test.rb +0 -153
@@ -1,406 +0,0 @@
1
- require 'catissue/annotation/annotation'
2
- require 'catissue/database/annotation/reference_writer'
3
-
4
- module CaTissue
5
- module AnnotationClass
6
- # @return [Symbol, nil] the annotation => proxy attribute, or nil if this is not a primary annotation
7
- attr_reader :proxy_attribute_metadata
8
-
9
- # @return [Integer, nil] the annotation class designator that is used by caTissue to persist primary
10
- # annotation objects, or nil if this is not a primary annotation
11
- attr_reader :entity_id
12
-
13
- # @return [Intger, nil] the container id, or nil if this is not a primary annotation
14
- attr_reader :container_id
15
-
16
- # @param [Class] klass the {Annotation} class to enable
17
- # @param [Module] mod the {AnnotationModule} which scopes the class
18
- def self.extend_class(klass, mod)
19
- # Enable the class meta-data.
20
- klass.extend(CaRuby::Domain::Metadata)
21
- # Extend with annotation meta-data.
22
- klass.extend(self).add_annotation_metadata(mod)
23
- end
24
-
25
- # @return [Module] the scoping annotation module
26
- def annotation_module
27
- domain_module
28
- end
29
-
30
- # @return [<AnnotationClass>] the annotation class hierarchy, including this class
31
- def annotation_hierarchy
32
- class_hierarchy.filter { |klass| klass < Annotation }
33
- end
34
-
35
- # Adds metadata to this annotation class.
36
- #
37
- # @param (see AnnotationClass.extend_class)
38
- def add_annotation_metadata(mod)
39
- @domain_module = mod
40
- alias_attribute(:annotation_module, :domain_module)
41
- efcd = Annotation::EntityFacade.instance
42
- @entity_id = efcd.annotation_entity_id(self, false)
43
- @is_primary = efcd.primary?(@entity_id) if @entity_id
44
- # A primary entity has a container id.
45
- if primary? then
46
- @container_id = efcd.container_id(@entity_id)
47
- if @container_id.nil? then raise AnnotationError.new("Primary annotation #{self} is missing a container id") end
48
- logger.debug { "Primary annotation #{self} has container id #{@container_id}." }
49
- end
50
- pxy = mod.proxy || return
51
- end
52
-
53
- # @return [Symbol] the domain attributes which include {Annotation}
54
- def annotation_attributes
55
- @ann_attrs ||= domain_attributes.compose { |attr_md| attr_md.type < Annotation }
56
- end
57
-
58
- # Filters {CaRuby::Domain::Attributes#loadable_attributes} to exclude all references,
59
- # since annotation lazy-loading is not supported.
60
- #
61
- # @return [Array] an empty array
62
- def loadable_attributes
63
- Array::EMPTY_ARRAY
64
- end
65
-
66
- # Saves the annotations referenced by the given annotation.
67
- #
68
- # @param [Annotation] annotation the subject annotation
69
- def save_dependent_attributes(annotation)
70
- dependent_attributes.each { |attr| save_dependent_attribute(annotation, attr) }
71
- end
72
-
73
- # @return [Boolean] whether this annotation refers to a {#primary?} annotation
74
- def secondary?
75
- ref = domain_attributes.detect_with_metadata { |attr_md| attr_md.type < Annotation and attr_md.type.primary? }
76
- not ref.nil?
77
- end
78
-
79
- # @return [Boolean] whether this annotation is neither a {#primary?} nor a #{secondary} annotation
80
- def tertiary_annotation
81
- not (primary? or secondary?)
82
- end
83
-
84
- # @return [ProxyClass] the annotation proxy class
85
- def proxy_class
86
- annotation_module.proxy
87
- end
88
-
89
- alias :proxy :proxy_class
90
-
91
- # @return [AnnotatableClass] the annotated domain object class
92
- def hook_class
93
- proxy.hook
94
- end
95
-
96
- alias :hook :hook_class
97
-
98
- # @return [Symbol, nil] the attribute which references the hook proxy,
99
- # or nil if this is not a primary annotation class
100
- def proxy_attribute
101
- @pxy_attr_md.to_sym if @pxy_attr_md
102
- end
103
-
104
- # @return [Symbol, nil] the hook proxy class attribute which references this annotation class,
105
- # or nil if this is not a primary annotation class
106
- def hook_proxy_attribute
107
- # The hook => primary attribute symbol is the same as the proxy => primary attribute symbol.
108
- @pxy_attr_md.inverse if @pxy_attr_md
109
- end
110
-
111
- # @return [Boolean] whether this annotation class references a hook proxy
112
- def primary?
113
- @is_primary
114
- end
115
-
116
- # @return [Array] an empty array, since no annotation reference is lazy-loaded by caTissue.
117
- def toxic_attributes
118
- Array::EMPTY_ARRAY
119
- end
120
-
121
- def proxy_attribute_metadata
122
- @pxy_attr_md
123
- end
124
-
125
- protected
126
-
127
- # @return [Symbol => ReferenceWriter] this class's attribute => writer hash
128
- def attribute_writer_hash
129
- @attr_writer_hash ||= map_writers
130
- end
131
-
132
- # Marks each of this annotation class's non-owner domain attributes as a dependent.
133
- def add_dependent_attributes
134
- # First infer the attribute inverses.
135
- infer_inverses
136
- # Select the annotation attributes to make dependent.
137
- attrs = domain_attributes.compose do |attr_md|
138
- attr_md != @pxy_attr_md and attr_md.type < Annotation and not (attr_md.dependent? or attr_md.owner?) and attr_md.declarer == self
139
- end
140
- # Copy the attributes to an array before iteration, since adding a dependent attribute
141
- # might also add another attribute in the case of a proxy.
142
- attrs.to_a.each do |attr|
143
- logger.debug { "Adding annotation #{qp} #{attr} attribute as a logical dependent..." }
144
- add_dependent_attribute(attr, :logical, :unsaved)
145
- end
146
- end
147
-
148
- # Infers this annotation class inverses attribute.
149
- # This method is called by the annotation module on each imported annotated class.
150
- def infer_inverses
151
- annotation_attributes.each_metadata do |attr_md|
152
- if attr_md.inverse.nil? and attr_md.declarer == self then
153
- attr_md.declarer.infer_attribute_inverse(attr_md)
154
- end
155
- end
156
- end
157
-
158
- # Recurses the dependency hierarchy to this annotation class's dependents in a
159
- # breadth-first manner.
160
- #
161
- # @param [<CaRuby::Domain::Attribute>] path the visited attributes
162
- def add_dependent_attribute_closure(path=[])
163
- return if path.include?(self)
164
- attrs = dependent_attributes(false)
165
- return if attrs.empty?
166
-
167
- # recurse to dependents
168
- path.push(self)
169
- dependent_attributes(false).each_metadata do |attr_md|
170
- klass = attr_md.type
171
- klass.add_dependent_attribute_closure(path)
172
- end
173
- path.pop
174
-
175
- # add breadth-first dependencies
176
- deps = dependent_attributes(false)
177
- logger.debug { "Adding #{qp} annotation dependents #{deps.qp}..." }
178
- deps.each_metadata { |attr_md| attr_md.type.add_dependent_attributes }
179
- logger.debug { "Added #{qp} dependents #{deps.qp}." }
180
- end
181
-
182
- # Creates the proxy attribute that references the given proxy class, if it is not
183
- # already defined.
184
- #
185
- # @param [Annotation::ProxyClass] klass the annotation module proxy class
186
- # @raise [AnnotationError] if this annotation is not {#primary?}
187
- # @raise [AnnotationError] if the proxy attribute is already set and references a different proxy class
188
- def define_proxy_attribute(klass)
189
- # must be primary
190
- unless primary? then raise AnnotationError.new("Can't set proxy for non-primary annotation class #{qp}") end
191
- # If the proxy is already set, then confirm that this call is redundant, which is tolerated as a no-op,
192
- # as opposed to conflicting, which is not allowed.
193
- if @pxy_attr_md then
194
- return if @pxy_attr_md.type == klass
195
- raise AnnotationError.new("Can't reset #{self} proxy from #{@pxy_attr_md.type} to #{klass}")
196
- end
197
- logger.debug { "Setting annotation #{qp} proxy to #{klass}..." }
198
- # the annotation => proxy reference attribute
199
- attr_md = obtain_proxy_attribute_metadata(klass)
200
- # The canonical proxy attribute is named after the annotation module, e.g. clinical.
201
- # caTissue 1.1.x confusingly names the proxy the same as the hook. Correct this by recasting the
202
- # proxy as the hook attribute and making a separate proxy attribute named by the annotation module.
203
- hook_attr = klass.hook.name.demodulize.underscore.to_sym
204
- if attr_md.to_sym == hook_attr then
205
- wrap_1_1_proxy_attribute(attr_md)
206
- else
207
- set_proxy_attribute_metadata(attr_md, hook_attr)
208
- end
209
- logger.debug { "Annotation #{qp} proxy reference attribute is #{@pxy_attr_md}." }
210
-
211
- # Alias 'proxy' to the proxy attribute.
212
- logger.debug { "Aliased annotation #{qp} :proxy to #{@pxy_attr_md}." }
213
- alias_attribute(:proxy, @pxy_attr_md.to_sym)
214
- # Alias 'hook' to the hook attribute.
215
- logger.debug { "Aliased annotation #{qp} :hook to #{hook_attr}." }
216
- alias_attribute(:hook, hook_attr)
217
- end
218
-
219
- private
220
-
221
- # Removes the superclass proxy reference attribute, if any from this annotation class,
222
- # since each proxy is class-specific.
223
- def occlude_superclass_proxy_attribute
224
- return unless superclass < Annotation
225
- attr = superclass.proxy_attribute || return
226
- remove_attribute(attr)
227
- logger.debug { "Occluded #{qp} superclass #{superclass.qp} proxy reference #{attr}." }
228
- end
229
-
230
- # Sets the caTissue 1.2 and higher proxy attribute. The attribute is aliased
231
- # to the demodulized annotation module name, e.g. +clinical+. A hook attribute
232
- # is created that is a shortcut for the annotation => proxy => hook reference.
233
- #
234
- # @param [CaRuby::Domain::Attribute] attr_md the proxy attribute
235
- # @param [Symbol, nil] the proxy => hook attribute (default is the underscore demodulized hook class name)
236
- def set_proxy_attribute_metadata(attr_md, hook_attr=nil)
237
- hook_attr ||= attr_md.type.hook.name.demodulize.underscore.to_sym
238
- @pxy_attr_md = attr_md
239
-
240
- # Alias the attribute with the proxy hook name, e.g. the
241
- # Participant::Clinical::AlcoholAnnotation -> Participant::Clinical::ParticipantRecordEntry
242
- # proxy reference attribute participant_record_entry is aliased by clinical.
243
- aliaz = annotation_module.name.demodulize.underscore.to_sym
244
- if aliaz != attr_md.to_sym then
245
- alias_attribute(aliaz, attr_md.to_sym)
246
- logger.debug { "Aliased #{qp} #{aliaz} to #{attr_md}." }
247
- end
248
-
249
- # Make the hook attribute.
250
- define_method(hook_attr) { pxy = send(aliaz); pxy.hook if pxy }
251
- define_method("#{hook_attr}=".to_sym) { |obj| pxy = obj.proxy_for(aliaz, self) if obj; send(attr_md.writer, pxy) }
252
- add_attribute(hook_attr, attr_md.type.hook)
253
- logger.debug { "Defined #{qp} => #{attr_md.type.hook.qp} hook attribute #{hook_attr}." }
254
-
255
- # Remove the superclass proxy attribute, if necessary.
256
- occlude_superclass_proxy_attribute
257
- end
258
-
259
- # Wraps the caTissue 1.1.x proxy attribute with a hook argument and return value.
260
- # If the superclass is a primary annotation, then this method delegates
261
- # to the superclass to set the proxy attribute. Otherwise, the proxy accessor
262
- # methods are modified as follows:
263
- # * the proxy writer converts a hook argument to its proxy
264
- # * the proxy reader converts a proxy to its hook
265
- # * the proxy is aliased as a hook attribute, if necessary, e.g. +participant+
266
- # is aliased to +participant_record_entry+
267
- #
268
- # @param [CaRuby::Domain::Attribute] attr_md the proxy attribute
269
- def wrap_1_1_proxy_attribute(attr_md)
270
- if attr_md.nil? then
271
- raise AnnotationError.new("Cannot convert #{qp} => #{klass.qp} argument to a proxy since no proxy attribute is defined.")
272
- end
273
- logger.debug { "Adding #{qp} #{attr_md} attribute to wrap the proxy Java accessor methods with the hook JRuby accessor methods..." }
274
- # Wrap the proxy reader with a proxy => hook converter.
275
- convert_proxy_reader_result_to_hook(attr_md.reader)
276
- # the proxy => hook attribute metadata
277
- pxy_hook_attr_md = annotation_module.proxy.owner_attribute_metadata
278
- # the hook => proxy attribute
279
- hook_pxy_attr = pxy_hook_attr_md.inverse
280
- # Wrap the proxy writer with a hook -> proxy converter.
281
- convert_proxy_writer_hook_argument_to_proxy(attr_md.writer, hook_pxy_attr)
282
- # Reset the attribute type.
283
- hook = pxy_hook_attr_md.type
284
- set_attribute_type(attr_md.to_sym, hook)
285
- logger.debug { "Reset #{qp} #{attr_md} type to the hook class #{hook}." }
286
- # Mark the hook attribute as unsaved. This is necessary because as a uni-directional
287
- # Java independent reference, the default is to save this attribute. Since we save the
288
- # proxy reference instead, the convenience hook reference is unsaved.
289
- attr_md.qualify(:unsaved)
290
-
291
- # Add the proxy reference attribute.
292
- pxy_attr = annotation_module.name.demodulize.underscore.to_sym
293
- @pxy_attr_md = add_attribute(pxy_attr, annotation_module.proxy, :saved)
294
- logger.debug { "Added #{qp} => #{@pxy_attr_md.type} proxy attribute #{@pxy_attr_md}." }
295
- end
296
-
297
- # @param [ProxyClass] klass the proxy class
298
- # @return [CaRuby::Domain::Attribute] the annotation -> proxy attribute
299
- def obtain_proxy_attribute_metadata(klass)
300
- attr_md = infer_proxy_attribute_metadata(klass) || create_proxy_attribute_metadata(klass)
301
- if attr_md.nil? then raise AnnotationError.new("Annotation #{qp} proxy attribute could not be found or created") end
302
- logger.debug { "Annotation class #{qp} has proxy reference attribute #{attr_md}." }
303
- attr_md
304
- end
305
-
306
- # @param [ProxyClass] klass the proxy class
307
- # @return [CaRuby::Domain::Attribute] the existing annotation -> proxy attribute
308
- def infer_proxy_attribute_metadata(klass)
309
- domain_attributes.each_metadata { |attr_md| return attr_md if attr_md.type == klass and attr_md.declarer == self }
310
- nil
311
- end
312
-
313
- # @param [ProxyClass] klass the proxy class
314
- # @return [CaRuby::Domain::Attribute] the new annotation -> proxy attribute
315
- def create_proxy_attribute_metadata(klass)
316
- # the proxy attribute symbol
317
- attr = annotation_module.name.demodulize.underscore.to_sym
318
- logger.debug { "Creating primary annotation #{qp} proxy #{klass} attribute #{attr}..." }
319
- # make the attribute
320
- attr_accessor(attr)
321
-
322
- # Add the attribute. Setting the saved flag ensures that the save template passed to
323
- # the annotation service includes a reference to the hook object. This in turn allows
324
- # the annotation service to call the integration service to associate the annotation
325
- # to the hook object.
326
- attr_md = add_attribute(attr, proxy, :saved)
327
- # make the inverse proxy -> annotation dependent attribute
328
- inverse = klass.create_annotation_attribute(self)
329
- logger.debug { "Created primary annotation #{qp} proxy #{klass} attribute #{attr} with inverse #{inverse}." }
330
-
331
- attr_md
332
- end
333
-
334
- # Recursively saves the annotation dependency hierarchy rooted at the given annotation attribute.
335
- #
336
- # @param annotation (see #save_annotation)
337
- # @param [Symbol] attribute the attribute to save
338
- def save_dependent_attribute(annotation, attribute)
339
- annotation.send(attribute).enumerate do |ref|
340
- logger.debug { "Saving #{annotation} #{attribute} dependent #{ref.qp}..." }
341
- wtr = writer(attribute)
342
- if wtr.nil? then raise AnnotationError.new("Annotation reference writer not found for #{qp} #{attribute}") end
343
- wtr.save(ref)
344
- ref.class.save_dependent_attributes(ref)
345
- end
346
- end
347
-
348
- # @param [Symbol] attribute the annotation attribute
349
- # @return [AnnotationWriter] the attribute writer for instances of this class
350
- def writer(attribute)
351
- attribute_writer_hash[attribute]
352
- end
353
-
354
- # @return [{Symbol => Annotation::ReferenceWriter}] the annotation attribute => writer hash
355
- def map_writers
356
- hash = {}
357
- dependent_attributes.each_pair do |attr, attr_md|
358
- # skip attributes defined in a superclass
359
- next unless attr_md.declarer == self
360
- if @entity_id.nil? then
361
- raise AnnotationError.new("Cannot define reference writers for #{qp} since it does not have an entity id.")
362
- end
363
- hash[attr] = Annotation::ReferenceWriter.new(@entity_id, attr_md)
364
- end
365
- # If the superclass is also an annotation, then form the union of its writers with the local writers.
366
- superclass < Annotation && superclass.primary? ? hash + superclass.attribute_writer_hash : hash
367
- end
368
-
369
- # Wraps the proxy reader method to convert a proxy to its hook.
370
- #
371
- # @param [Symbol] reader the proxy reader method
372
- def convert_proxy_reader_result_to_hook(reader)
373
- redefine_method(reader) do |old_mth|
374
- # Alias the annotation module attribute name to the old method.
375
- aliaz = annotation_module.name.demodulize.underscore.to_sym
376
- alias_method(aliaz, old_mth)
377
- # Convert the proxy to the hook.
378
- lambda do
379
- pxy = send(old_mth)
380
- pxy.hook if pxy
381
- end
382
- end
383
- logger.debug { "Redefined the #{qp} #{reader} reader method to convert a proxy parameter to its hook object." }
384
- end
385
-
386
- # Wraps the proxy writer method to convert a hook argument to its proxy.
387
- #
388
- # @param [Symbol] writer the proxy writer method
389
- # @param [Symbol] inverse the hook => proxy attribute
390
- def convert_proxy_writer_hook_argument_to_proxy(writer, inverse)
391
- klass = annotation_module.hook
392
- redefine_method(writer) do |old_mth|
393
- # Alias the annotation module attribute name to the old method.
394
- aliaz = "#{annotation_module.name.demodulize.underscore}=".to_sym
395
- alias_method(aliaz, old_mth)
396
- lambda do |value|
397
- # Convert the parameter from a hook to a proxy, if necessary.
398
- pxy = klass === value ? value.proxy_for(inverse, self) : value
399
- unless pxy == value then logger.debug { "Converted #{qp} #{writer} argument from hook #{value.qp} to proxy #{pxy.qp}" } end
400
- send(self.class.proxy_attribute_metadata.writer, pxy)
401
- end
402
- end
403
- logger.debug { "Redefined the #{klass.qp} #{inverse} proxy writer #{writer} to convert a hook #{klass.qp} parameter to the hook proxy." }
404
- end
405
- end
406
- end
@@ -1,106 +0,0 @@
1
- require 'caruby/domain'
2
- require 'catissue/annotation/annotation'
3
- require 'catissue/annotation/annotation_class'
4
- require 'catissue/annotation/proxy'
5
- require 'catissue/annotation/proxy_class'
6
- require 'catissue/annotation/de_integration'
7
-
8
- module CaTissue
9
- module AnnotationModule
10
- include CaRuby::Domain
11
-
12
- # @return [ProxyClass] the annotation proxy class
13
- attr_reader :proxy
14
-
15
- # @return [String] the group short name
16
- attr_reader :group
17
-
18
- # @return [Class] the hook-annotation association class, or nil for 1.1.x caTissue
19
- attr_reader :record_entry_class
20
-
21
- # @return [Symbol] the {#de_integration_proxy_class} hook writer method, or nil for 1.1.x caTissue
22
- attr_reader :record_entry_hook_writer
23
-
24
- # @param [AnnotationModule] mod the annotation module to build
25
- # @param [Class] hook the static hook class
26
- # @param [{Symbol => Object}] the options
27
- # @option opts [String] :package the DE package name
28
- # @option opts [String] :service the DE service name
29
- # @option opts [String] :group the DE group short name
30
- # @option opts [String] :record_entry the record entry name class for post-1.1.x caTissue
31
- def self.extend_module(mod, hook, opts)
32
- mod.extend(self)
33
- mod.initialize_annotation(hook, opts)
34
- end
35
-
36
- # Builds the annotation module.
37
- # This method intended to be called only by {AnnotationModule.extend_module}.
38
- #
39
- # @param (see AnnotationModule.extend_module)
40
- def initialize_annotation(hook, opts)
41
- logger.debug { "Building #{hook.qp} annotation #{qp}..." }
42
- pkg = opts[:package]
43
- @svc_nm = opts[:service]
44
- @group = opts[:group]
45
- # Enable the resource metadata aspect.
46
- md_proc = Proc.new { |klass| AnnotationClass.extend_class(klass, self) }
47
- CaRuby::Domain::Importer.extend_module(self, :mixin => Annotation, :metadata => md_proc, :package => pkg)
48
- dei = hook.de_integration_proxy_class
49
- if dei then
50
- import_record_entry_class(dei, hook)
51
- pxy_nm = dei.name.demodulize
52
- end
53
- @proxy = import_proxy(hook, pxy_nm)
54
- load_annotation_class_definitions(hook)
55
- logger.debug { "Built #{hook.qp} annotation #{qp}." }
56
- end
57
-
58
- # @return (ProxyClass#hook)
59
- def hook
60
- @proxy.hook
61
- end
62
-
63
- # @return [CaRuby::PersistenceService] this module's application service
64
- def persistence_service
65
- @ann_svc ||= Database.instance.annotator.create_annotation_service(self, @svc_nm)
66
- end
67
-
68
- private
69
-
70
- # The location of the domain class definitions.
71
- DOMAIN_DIR = File.join(File.dirname(File.dirname(__FILE__)), 'domain')
72
-
73
- def load_annotation_class_definitions(hook)
74
- dir = File.join(DOMAIN_DIR, hook.name.demodulize.underscore, name.demodulize.underscore)
75
- load_dir(dir)
76
- end
77
-
78
- # Sets the record entry instance variables for the given class name, if it exists
79
- # as a {Annotation::DEIntegration} proxy class. caTissue v1.1.x does not have
80
- # a record entry class.
81
- #
82
- # @param [String] the record entry class name specified in the
83
- # {CaTissue::AnnotatableClass#add_annotation} +:record_entry+ option
84
- def import_record_entry_class(klass, hook)
85
- @record_entry_class = const_get(klass.name.demodulize.to_sym)
86
- @record_entry_hook_writer = "#{hook.name.demodulize.underscore}=".to_sym
87
- end
88
-
89
- # @param hook (see #initialize_annotation)
90
- # @param [String] name the demodulized name of the proxy class
91
- # (default is the demodulized hook class name)
92
- def import_proxy(hook, name=nil)
93
- name ||= hook.name.demodulize
94
- logger.debug { "Importing #{qp} #{hook.qp} annotation proxy..." }
95
- begin
96
- klass = const_get(name.to_sym)
97
- rescue CaRuby::JavaImportError
98
- raise AnnotationError.new("#{hook.qp} annotation #{qp} does not have a hook proxy class - #{$!}")
99
- end
100
- klass.extend(Annotation::ProxyClass)
101
- klass.hook = hook
102
- logger.debug { "Built #{name} #{hook.qp} annotation proxy #{klass}." }
103
- klass
104
- end
105
- end
106
- end