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.
- data/Gemfile +17 -0
- data/History.md +5 -1
- data/README.md +2 -2
- data/bin/crtdump +2 -8
- data/bin/crtexample +2 -5
- data/bin/crtmigrate +3 -6
- data/bin/crtsmoke +3 -8
- data/conf/wustl/{log4j.properties → linux/log4j.properties} +3 -3
- data/conf/wustl/windows/log4j.properties +40 -0
- data/examples/galena/Gemfile +16 -0
- data/examples/galena/Gemfile.lock +88 -0
- data/examples/galena/README.md +16 -16
- data/examples/galena/Rakefile +30 -0
- data/examples/galena/bin/seed +5 -11
- data/examples/galena/conf/annotation/defaults.yaml +2 -0
- data/examples/galena/conf/{migration/annotation_fields.yaml → annotation/fields.yaml} +2 -4
- data/examples/galena/conf/defaults.yaml +9 -0
- data/examples/galena/conf/{migration/filter_fields.yaml → filter/fields.yaml} +0 -1
- data/examples/galena/conf/filter/values.yaml +8 -0
- data/examples/galena/conf/{migration/frozen_defaults.yaml → frozen/defaults.yaml} +0 -0
- data/examples/galena/conf/{migration/frozen_fields.yaml → frozen/fields.yaml} +0 -2
- data/examples/galena/conf/{migration/general_fields.yaml → general/fields.yaml} +0 -24
- data/examples/galena/conf/registration/fields.yaml +6 -0
- data/examples/galena/conf/{migration/simple_fields.yaml → simple/fields.yaml} +1 -6
- data/examples/galena/data/annotation.csv +1 -1
- data/examples/galena/data/filter.csv +1 -1
- data/examples/galena/data/frozen.csv +1 -1
- data/examples/galena/data/general.csv +1 -1
- data/examples/galena/data/registration.csv +1 -1
- data/examples/galena/data/simple.csv +1 -1
- data/examples/galena/galena.gemspec +24 -0
- data/examples/galena/lib/galena/filter.rb +25 -0
- data/examples/galena/lib/galena/{tissue/migration/frozen_shims.rb → frozen.rb} +6 -10
- data/examples/galena/lib/galena/seed.rb +126 -0
- data/examples/galena/lib/galena/version.rb +3 -0
- data/examples/galena/lib/galena.rb +18 -7
- data/examples/galena/log/galena.log +37351 -0
- data/examples/galena/log/galena.log.0 +147830 -0
- data/examples/galena/spec/annotation_spec.rb +46 -0
- data/examples/galena/spec/filter_spec.rb +94 -0
- data/examples/galena/spec/frozen_spec.rb +39 -0
- data/examples/galena/spec/general_spec.rb +62 -0
- data/examples/galena/spec/registration_spec.rb +37 -0
- data/examples/galena/spec/seed.rb +107 -0
- data/examples/galena/spec/simple_spec.rb +58 -0
- data/examples/galena/spec/spec_helper.rb +11 -0
- data/examples/galena/spec/support/migration.rb +70 -0
- data/lib/catissue/annotation/annotatable.rb +10 -8
- data/lib/catissue/annotation/annotation.rb +7 -7
- data/lib/catissue/annotation/de_integration.rb +9 -20
- data/lib/catissue/annotation/importer.rb +148 -0
- data/lib/catissue/annotation/introspector.rb +32 -0
- data/lib/catissue/annotation/metadata.rb +422 -0
- data/lib/catissue/annotation/proxy.rb +2 -2
- data/lib/catissue/annotation/proxy_class.rb +45 -30
- data/lib/catissue/annotation/record_entry_proxy.rb +2 -2
- data/lib/catissue/cli/command.rb +14 -24
- data/lib/catissue/cli/example.rb +5 -3
- data/lib/catissue/cli/migrate.rb +45 -37
- data/lib/catissue/cli/smoke.rb +2 -3
- data/lib/catissue/database/annotation/annotation_service.rb +8 -17
- data/lib/catissue/database/annotation/entity_facade.rb +33 -30
- data/lib/catissue/database/annotation/id_generator.rb +1 -1
- data/lib/catissue/database/annotation/integration_service.rb +11 -4
- data/lib/catissue/database/annotation/reference_writer.rb +38 -38
- data/lib/catissue/database/controlled_value_finder.rb +13 -28
- data/lib/catissue/database/controlled_values.rb +73 -45
- data/lib/catissue/database.rb +637 -277
- data/lib/catissue/domain/abstract_domain_object.rb +5 -0
- data/lib/catissue/domain/abstract_position.rb +3 -5
- data/lib/catissue/domain/abstract_specimen.rb +79 -65
- data/lib/catissue/domain/abstract_specimen_collection_group.rb +3 -6
- data/lib/catissue/domain/address.rb +0 -2
- data/lib/catissue/domain/cancer_research_group.rb +0 -3
- data/lib/catissue/domain/capacity.rb +2 -4
- data/lib/catissue/domain/check_in_check_out_event_parameter.rb +0 -3
- data/lib/catissue/domain/collection_event_parameters.rb +2 -7
- data/lib/catissue/domain/collection_protocol.rb +11 -16
- data/lib/catissue/domain/collection_protocol_event.rb +19 -12
- data/lib/catissue/domain/collection_protocol_registration.rb +8 -12
- data/lib/catissue/domain/consent_tier_response.rb +0 -4
- data/lib/catissue/domain/consent_tier_status.rb +1 -4
- data/lib/catissue/domain/container.rb +10 -10
- data/lib/catissue/domain/container_position.rb +4 -7
- data/lib/catissue/domain/container_type.rb +4 -7
- data/lib/catissue/domain/department.rb +0 -3
- data/lib/catissue/domain/disposal_event_parameters.rb +5 -5
- data/lib/catissue/domain/embedded_event_parameters.rb +1 -4
- data/lib/catissue/domain/external_identifier.rb +0 -12
- data/lib/catissue/domain/frozen_event_parameters.rb +1 -4
- data/lib/catissue/domain/institution.rb +0 -3
- data/lib/catissue/domain/new_specimen_array_order_item.rb +0 -5
- data/lib/catissue/domain/order_details.rb +0 -2
- data/lib/catissue/domain/participant/clinical/chemotherapy.rb +1 -3
- data/lib/catissue/domain/participant/clinical/duration.rb +2 -4
- data/lib/catissue/domain/participant/clinical/radiation_therapy.rb +2 -4
- data/lib/catissue/domain/participant.rb +22 -24
- data/lib/catissue/domain/participant_medical_identifier.rb +0 -4
- data/lib/catissue/domain/password.rb +0 -4
- data/lib/catissue/domain/race.rb +0 -3
- data/lib/catissue/domain/received_event_parameters.rb +3 -6
- data/lib/catissue/domain/site.rb +1 -4
- data/lib/catissue/domain/specimen/pathology/additional_finding.rb +12 -0
- data/lib/catissue/domain/specimen/pathology/details.rb +12 -0
- data/lib/catissue/domain/specimen/pathology/gleason_score.rb +12 -0
- data/lib/catissue/domain/specimen/pathology/histologic_grade.rb +12 -0
- data/lib/catissue/domain/specimen/pathology/histologic_type.rb +19 -0
- data/lib/catissue/domain/specimen/pathology/histologic_variant_type.rb +12 -0
- data/lib/catissue/domain/specimen/pathology/invasion.rb +12 -0
- data/lib/catissue/domain/specimen/pathology/prostate_specimen_gleason_score.rb +5 -11
- data/lib/catissue/domain/specimen/pathology/prostate_specimen_pathology_annotation.rb +12 -12
- data/lib/catissue/domain/specimen/pathology/specimen_additional_finding.rb +5 -14
- data/lib/catissue/domain/specimen/pathology/specimen_base_solid_tissue_pathology_annotation.rb +6 -21
- data/lib/catissue/domain/specimen/pathology/specimen_details.rb +4 -10
- data/lib/catissue/domain/specimen/pathology/specimen_histologic_grade.rb +4 -10
- data/lib/catissue/domain/specimen/pathology/specimen_histologic_type.rb +6 -14
- data/lib/catissue/domain/specimen/pathology/specimen_histologic_variant_type.rb +5 -11
- data/lib/catissue/domain/specimen/pathology/specimen_invasion.rb +5 -11
- data/lib/catissue/domain/specimen.rb +113 -76
- data/lib/catissue/domain/specimen_array.rb +0 -3
- data/lib/catissue/domain/specimen_array_content.rb +1 -4
- data/lib/catissue/domain/specimen_array_type.rb +1 -4
- data/lib/catissue/domain/specimen_characteristics.rb +0 -3
- data/lib/catissue/domain/specimen_collection_group/pathology/base_pathology_annotation.rb +2 -4
- data/lib/catissue/domain/specimen_collection_group/pathology/base_solid_tissue_pathology_annotation.rb +2 -4
- data/lib/catissue/domain/specimen_collection_group.rb +43 -53
- data/lib/catissue/domain/specimen_event_parameters.rb +24 -32
- data/lib/catissue/domain/specimen_position.rb +8 -5
- data/lib/catissue/domain/specimen_protocol.rb +3 -6
- data/lib/catissue/domain/specimen_requirement.rb +22 -20
- data/lib/catissue/domain/storage_container.rb +9 -12
- data/lib/catissue/domain/storage_type.rb +6 -10
- data/lib/catissue/domain/transfer_event_parameters.rb +3 -6
- data/lib/catissue/domain/user.rb +22 -29
- data/lib/catissue/{util → helpers}/collectible.rb +23 -18
- data/lib/catissue/helpers/collectible_event_parameters.rb +68 -0
- data/lib/catissue/helpers/controlled_value.rb +35 -0
- data/lib/catissue/{domain → helpers}/hash_code.rb +0 -0
- data/lib/catissue/{util → helpers}/location.rb +6 -5
- data/lib/catissue/helpers/log.rb +4 -0
- data/lib/catissue/{util → helpers}/person.rb +1 -1
- data/lib/catissue/{util → helpers}/position.rb +10 -8
- data/lib/catissue/helpers/properties_loader.rb +143 -0
- data/lib/catissue/{util → helpers}/storable.rb +2 -1
- data/lib/catissue/{util → helpers}/storage_type_holder.rb +9 -3
- data/lib/catissue/{annotation/annotatable_class.rb → metadata.rb} +73 -95
- data/lib/catissue/migration/migratable.rb +93 -44
- data/lib/catissue/migration/migrator.rb +26 -42
- data/lib/catissue/migration/shims.rb +1 -1
- data/lib/catissue/migration/unique.rb +76 -0
- data/lib/catissue/resource.rb +16 -20
- data/lib/catissue/version.rb +1 -1
- data/lib/catissue/wustl/logger.rb +52 -32
- data/lib/catissue.rb +38 -20
- data/test/lib/catissue/database/controlled_values_test.rb +22 -27
- data/test/lib/catissue/database/database_test.rb +18 -0
- data/test/lib/catissue/domain/address_test.rb +9 -11
- data/test/lib/catissue/domain/ca_tissue_test_defaults_test.rb +5 -16
- data/test/lib/catissue/domain/capacity_test.rb +2 -2
- data/test/lib/catissue/domain/collection_event_parameters_test.rb +16 -8
- data/test/lib/catissue/domain/collection_protocol_event_test.rb +1 -1
- data/test/lib/catissue/domain/collection_protocol_registration_test.rb +26 -16
- data/test/lib/catissue/domain/collection_protocol_test.rb +2 -2
- data/test/lib/catissue/domain/container_position_test.rb +7 -4
- data/test/lib/catissue/domain/department_test.rb +3 -3
- data/test/lib/catissue/domain/disposal_event_parameters_test.rb +1 -1
- data/test/lib/catissue/domain/external_identifier_test.rb +5 -1
- data/test/lib/catissue/domain/location_test.rb +4 -4
- data/test/lib/catissue/domain/participant_medical_identifier_test.rb +3 -3
- data/test/lib/catissue/domain/participant_test.rb +33 -20
- data/test/lib/catissue/domain/received_event_parameters_test.rb +19 -0
- data/test/lib/catissue/domain/site_test.rb +2 -2
- data/test/lib/catissue/domain/specimen_array_test.rb +3 -3
- data/test/lib/catissue/domain/specimen_array_type_test.rb +6 -6
- data/test/lib/catissue/domain/specimen_characteristics_test.rb +1 -1
- data/test/lib/catissue/domain/specimen_collection_group_test.rb +49 -13
- data/test/lib/catissue/domain/specimen_event_parameters_test.rb +4 -4
- data/test/lib/catissue/domain/specimen_position_test.rb +1 -1
- data/test/lib/catissue/domain/specimen_requirement_test.rb +2 -2
- data/test/lib/catissue/domain/specimen_test.rb +58 -24
- data/test/lib/catissue/domain/storage_container_test.rb +3 -16
- data/test/lib/catissue/domain/storage_type_test.rb +3 -3
- data/test/lib/catissue/domain/transfer_event_parameters_test.rb +17 -17
- data/test/lib/catissue/domain/user_test.rb +32 -34
- data/test/lib/catissue/helpers/properties_loader_test.rb +19 -0
- data/test/lib/catissue/migration/{test_case.rb → helpers/test_case.rb} +30 -20
- data/test/lib/examples/galena/tissue/domain/examples_test.rb +28 -38
- data/test/lib/examples/galena/tissue/helpers/test_case.rb +24 -0
- metadata +175 -99
- data/bin/crtextract +0 -47
- data/examples/galena/conf/extract/simple_fields.yaml +0 -4
- data/examples/galena/conf/migration/annotation_defaults.yaml +0 -2
- data/examples/galena/conf/migration/filter_defaults.yaml +0 -1
- data/examples/galena/conf/migration/filter_values.yaml +0 -13
- data/examples/galena/conf/migration/participant_fields.yaml +0 -4
- data/examples/galena/conf/migration/registration_fields.yaml +0 -5
- data/examples/galena/data/participant.csv +0 -1
- data/examples/galena/lib/galena/tissue/migration/filter_shims.rb +0 -41
- data/examples/galena/lib/galena/tissue/seed/defaults.rb +0 -127
- data/examples/psbin/README.md +0 -45
- data/examples/psbin/conf/adjuvant_hormone_defaults.yaml +0 -2
- data/examples/psbin/conf/adjuvant_radiation_defaults.yaml +0 -3
- data/examples/psbin/conf/biopsy_defaults.yaml +0 -3
- data/examples/psbin/conf/biopsy_fields.yaml +0 -9
- data/examples/psbin/conf/neoadjuvant_hormone_defaults.yaml +0 -2
- data/examples/psbin/conf/neoadjuvant_radiation_defaults.yaml +0 -3
- data/examples/psbin/conf/patient_defaults.yaml +0 -3
- data/examples/psbin/conf/patient_fields.yaml +0 -5
- data/examples/psbin/conf/surgery_defaults.yaml +0 -4
- data/examples/psbin/conf/surgery_fields.yaml +0 -15
- data/examples/psbin/conf/t_stage_defaults.yaml +0 -1
- data/examples/psbin/conf/t_stage_fields.yaml +0 -4
- data/examples/psbin/conf/therapy_fields.yaml +0 -5
- data/examples/psbin/data/adjuvant_hormone.csv +0 -1
- data/examples/psbin/data/adjuvant_radiation.csv +0 -1
- data/examples/psbin/data/biopsy.csv +0 -1
- data/examples/psbin/data/neoadjuvant_hormone.csv +0 -1
- data/examples/psbin/data/neoadjuvant_radiation.csv +0 -1
- data/examples/psbin/data/patient.csv +0 -1
- data/examples/psbin/data/surgery.csv +0 -1
- data/examples/psbin/data/t_stage.csv +0 -1
- data/examples/psbin/lib/psbin/biopsy_shims.rb +0 -15
- data/examples/psbin/lib/psbin/surgery_shims.rb +0 -15
- data/lib/catissue/annotation/annotation_class.rb +0 -406
- data/lib/catissue/annotation/annotation_module.rb +0 -106
- data/lib/catissue/domain.rb +0 -26
- data/lib/catissue/extract/command.rb +0 -31
- data/lib/catissue/extract/delta.rb +0 -58
- data/lib/catissue/extract/extractor.rb +0 -99
- data/lib/catissue/migration/uniquify.rb +0 -2
- data/lib/catissue/util/collectible_event_parameters.rb +0 -71
- data/lib/catissue/util/controlled_value.rb +0 -29
- data/lib/catissue/util/uniquify.rb +0 -86
- data/test/fixtures/catissue/domain/conf/catissue_override.yaml +0 -9
- data/test/fixtures/catissue/extract/conf/scg_extract.yaml +0 -3
- data/test/fixtures/catissue/extract/conf/scg_fields.yaml +0 -3
- data/test/fixtures/catissue/extract/conf/spc_extract.yaml +0 -3
- data/test/fixtures/catissue/extract/conf/spc_fields.yaml +0 -4
- data/test/fixtures/lib/catissue/defaults_test_fixture.rb +0 -206
- data/test/fixtures/lib/examples/galena/migration/alt_key_shims.rb +0 -7
- data/test/lib/catissue/domain/base_haemotology_pathology_test.rb +0 -24
- data/test/lib/catissue/extract/delta_test.rb +0 -25
- data/test/lib/catissue/extract/extractor_test.rb +0 -43
- data/test/lib/catissue/import/importable_module_test.rb +0 -14
- data/test/lib/catissue/test_case.rb +0 -247
- data/test/lib/examples/galena/tissue/migration/annotation_test.rb +0 -29
- data/test/lib/examples/galena/tissue/migration/filter_test.rb +0 -29
- data/test/lib/examples/galena/tissue/migration/frozen_test.rb +0 -36
- data/test/lib/examples/galena/tissue/migration/general_test.rb +0 -56
- data/test/lib/examples/galena/tissue/migration/participant_test.rb +0 -61
- data/test/lib/examples/galena/tissue/migration/registration_test.rb +0 -17
- data/test/lib/examples/galena/tissue/migration/seedify.rb +0 -119
- data/test/lib/examples/galena/tissue/migration/simple_test.rb +0 -30
- data/test/lib/examples/galena/tissue/migration/test_case.rb +0 -72
- data/test/lib/examples/psbin/migration_test.rb +0 -153
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'caruby/helpers/controlled_value'
|
2
|
+
|
3
|
+
module CaTissue
|
4
|
+
class ControlledValue < CaRuby::ControlledValue
|
5
|
+
# @param [String, Symbol] public_id_or_alias the public id value or the
|
6
|
+
# standard alias +:tissue_site+ or +:clinical_diagnosis+
|
7
|
+
# @return [String] the standard public id value for the given string or alias
|
8
|
+
def self.standard_public_id(public_id_or_alias)
|
9
|
+
PID_ALIAS_HASH[public_id_or_alias.to_sym] or public_id_or_alias.to_s
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_accessor :identifier
|
13
|
+
|
14
|
+
attr_reader :public_id
|
15
|
+
|
16
|
+
# @return [Integer] the identifier of the parent
|
17
|
+
def parent_identifier
|
18
|
+
parent.identifier if parent
|
19
|
+
end
|
20
|
+
|
21
|
+
# @param public_id_or_alias (see ControlledValue.standard_public_id)
|
22
|
+
def public_id=(public_id_or_alias)
|
23
|
+
@public_id = self.class.standard_public_id(public_id_or_alias)
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_s
|
27
|
+
"#{value}"
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
# The public id symbol => name hash.
|
33
|
+
PID_ALIAS_HASH = {:tissue_site => 'Tissue_Site_PID', :clinical_diagnosis => 'Clinical_Diagnosis_PID'}
|
34
|
+
end
|
35
|
+
end
|
File without changes
|
@@ -1,5 +1,5 @@
|
|
1
|
-
require 'caruby/
|
2
|
-
require '
|
1
|
+
require 'caruby/helpers/coordinate'
|
2
|
+
require 'jinx/helpers/validation'
|
3
3
|
|
4
4
|
module CaTissue
|
5
5
|
# A Location is a non-Resource utility class which represents a Container row and column.
|
@@ -20,7 +20,7 @@ module CaTissue
|
|
20
20
|
Options.validate(params, INIT_OPTS)
|
21
21
|
@container = Options.get(:in, params)
|
22
22
|
coord = Options.get(:at, params, Coordinate.new)
|
23
|
-
# turn an
|
23
|
+
# turn an +:at+ Array value into a Coordinate
|
24
24
|
if Array === coord and not Coordinate === coord then
|
25
25
|
coord = Coordinate.new(*coord)
|
26
26
|
end
|
@@ -50,13 +50,13 @@ module CaTissue
|
|
50
50
|
|
51
51
|
# @return [Boolean] whether other is a Location and has the same content as this Location
|
52
52
|
def ==(other)
|
53
|
-
|
53
|
+
container == other.container and coordinate == other.coordinate
|
54
54
|
end
|
55
55
|
|
56
56
|
# @return [Location, nil] a new Location at the next slot in this Location's {#container},
|
57
57
|
# or nil if there are no more locations
|
58
58
|
def succ
|
59
|
-
self.class.new(:in => container, :at => @coordinate).succ! rescue nil
|
59
|
+
self.class.new(:in => container, :at => @coordinate.dup).succ! rescue nil
|
60
60
|
end
|
61
61
|
|
62
62
|
# Sets this Location to the next slot in this Location's {#container}.
|
@@ -89,6 +89,7 @@ module CaTissue
|
|
89
89
|
|
90
90
|
private
|
91
91
|
|
92
|
+
# @private
|
92
93
|
INIT_OPTS = [:in, :at].to_set
|
93
94
|
|
94
95
|
# @param [CaRuby::Coordinate] coord the coordinate to validate
|
@@ -1,5 +1,5 @@
|
|
1
|
-
require 'catissue/
|
2
|
-
require '
|
1
|
+
require 'catissue/helpers/location'
|
2
|
+
require 'jinx/helpers/validation'
|
3
3
|
|
4
4
|
module CaTissue
|
5
5
|
# The Position mix-in encapsulates the location of an occupant in a holder.
|
@@ -15,7 +15,8 @@ module CaTissue
|
|
15
15
|
self.class === other and occupant == other.occupant and location == other.location
|
16
16
|
end
|
17
17
|
|
18
|
-
# @return [Coordinate] the read-only coordinate with this AbstractPosition's #row
|
18
|
+
# @return [Coordinate] the read-only coordinate with this AbstractPosition's {Location#row}
|
19
|
+
# and {Location#column}.
|
19
20
|
def coordinate
|
20
21
|
location.coordinate
|
21
22
|
end
|
@@ -38,17 +39,18 @@ module CaTissue
|
|
38
39
|
self.column = @location.column
|
39
40
|
end
|
40
41
|
|
41
|
-
# @return whether either the column or the row is nil
|
42
|
+
# @return [Boolean] whether either the column or the row is nil
|
42
43
|
def unspecified?
|
43
44
|
column.nil? or row.nil?
|
44
45
|
end
|
45
46
|
|
46
|
-
# @return [(Integer, Integer)] this Position's zero-based ({#column}, {#row})
|
47
|
+
# @return [(Integer, Integer)] this Position's zero-based ({Location#column}, {Location#row})
|
48
|
+
# tuple
|
47
49
|
def to_a
|
48
50
|
[column, row]
|
49
51
|
end
|
50
52
|
|
51
|
-
# @raise [ValidationError] if the holder cannot hold the occupant type
|
53
|
+
# @raise [Jinx::ValidationError] if the holder cannot hold the occupant type
|
52
54
|
def validate
|
53
55
|
super
|
54
56
|
logger.debug { "Validating that #{holder} can hold #{occupant}..." }
|
@@ -56,10 +58,10 @@ module CaTissue
|
|
56
58
|
if curr_occ.nil? then
|
57
59
|
unless holder.can_hold_child?(occupant) then
|
58
60
|
reason = holder.full? ? "it is full" : "the occupant type is not among the supported types #{holder.container_type.child_types.qp}"
|
59
|
-
raise ValidationError.new("#{holder} cannot hold #{occupant} since #{reason}")
|
61
|
+
raise Jinx::ValidationError.new("#{holder} cannot hold #{occupant} since #{reason}")
|
60
62
|
end
|
61
63
|
elsif curr_occ != occupant
|
62
|
-
raise ValidationError.new("#{holder} cannot hold #{occupant} since the location #{[colum, row]} is already occupied by #{curr_occ}")
|
64
|
+
raise Jinx::ValidationError.new("#{holder} cannot hold #{occupant} since the location #{[colum, row]} is already occupied by #{curr_occ}")
|
63
65
|
end
|
64
66
|
end
|
65
67
|
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
module CaTissue
|
2
|
+
# The caTissue classpath and connection parameters properties loader mix-in.
|
3
|
+
module PropertiesLoader
|
4
|
+
class ConfigurationError < StandardError; end
|
5
|
+
|
6
|
+
# @return [{Symbol => [String, <String>]}] the application properties
|
7
|
+
def properties
|
8
|
+
@properties ||= load_properties
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
# Loads the caTissue classpath and connection properties.
|
14
|
+
#
|
15
|
+
# @quirk caTissue The classpath remoteServices.xml stream is corrupted, e.g. with a line:
|
16
|
+
# at top level in <value>http://cabig4 at line 8080
|
17
|
+
# instead of the expected:
|
18
|
+
# <property name="serviceUrl">http://cabig4:8080<\/property>
|
19
|
+
# This might be a classpath order side-effect or an install jar corruption, e.g. as
|
20
|
+
# occurs when building the caCORE API with a custom DE jar.
|
21
|
+
def load_properties
|
22
|
+
# the properties file
|
23
|
+
file = default_properties_file
|
24
|
+
# the access properties
|
25
|
+
props = file && File.exists?(file) ? load_properties_file(file) : {}
|
26
|
+
# Load the Java application jar path.
|
27
|
+
path = props[:classpath] || props[:path] || infer_classpath
|
28
|
+
if path then
|
29
|
+
Java.expand_to_class_path(path)
|
30
|
+
end
|
31
|
+
# TODO - below doesn't work because of caTissue bug described in the method rubydoc.
|
32
|
+
# Augment the application login properties with the remoteService.xml url property.
|
33
|
+
# path[:url] ||= remote_service_url
|
34
|
+
# def remote_service_url
|
35
|
+
# is = Java::edu.wustl.catissuecore.domain.Specimen.java_class.class_loader.getResourceAsStream('remoteService.xml')
|
36
|
+
# xml = Java::java.util.Scanner.new(is).useDelimiter("\\A").next
|
37
|
+
# /<property.+serviceUrl['"]?>(.+)<\/property>/.match(xml).captures.first
|
38
|
+
# end
|
39
|
+
props
|
40
|
+
end
|
41
|
+
|
42
|
+
def load_properties_file(file)
|
43
|
+
props = {}
|
44
|
+
logger.info("Loading application properties from #{file}...")
|
45
|
+
File.open(file).each do |line|
|
46
|
+
# match the tolerant property definition
|
47
|
+
match = PROP_DEF_REGEX.match(line.chomp.strip) || next
|
48
|
+
# the property [name, value] tokens
|
49
|
+
tokens = match.captures
|
50
|
+
pname = tokens.first.to_sym
|
51
|
+
# :path is deprecated; if there is a :path entry, then
|
52
|
+
# set :classpath with the :path value instead.
|
53
|
+
name = pname == :path ? :classpath : pname
|
54
|
+
value = tokens.last
|
55
|
+
# capture the property
|
56
|
+
props[name] = value
|
57
|
+
end
|
58
|
+
props
|
59
|
+
end
|
60
|
+
|
61
|
+
# The property/value matcher, e.g.:
|
62
|
+
# host: jacardi
|
63
|
+
# host = jacardi
|
64
|
+
# host=jacardi
|
65
|
+
# name: J. Edgar Hoover
|
66
|
+
# but not:
|
67
|
+
# # host: jacardi
|
68
|
+
# The captures are the trimmed property and value.
|
69
|
+
PROP_DEF_REGEX = /^(\w+)(?:\s*[:=]\s*)([^#]+)/
|
70
|
+
|
71
|
+
# @return [String] the default application properties file, given by +~/.+_name_,
|
72
|
+
# where _name_ is the underscore unqualified module name, e.g. +~/.catissue+
|
73
|
+
# for module +CaTissue+
|
74
|
+
def default_properties_file
|
75
|
+
home = ENV['HOME'] || ENV['USERPROFILE'] || '~'
|
76
|
+
file = File.expand_path('.catissue', home)
|
77
|
+
file if File.exists?(file)
|
78
|
+
end
|
79
|
+
|
80
|
+
# @quirk caTissue 1.2 the caTissue API class path is sensitive to order in subtle ways that
|
81
|
+
# caTissue 1.1.2 is not. The caTissue client +build.xml+ defines a +cp+ classpath
|
82
|
+
# property which was used to run a caTissue 1.1.1 example.
|
83
|
+
#
|
84
|
+
# However, the example was removed in caTissue 1.1.2. As of 1.1.2, the +cp+ property is no
|
85
|
+
# longer referenced in the client +build.xml+. Rather, the classpath is defined inline
|
86
|
+
# in the task with a small but important change: +cp+ placed the config directories
|
87
|
+
# before the jar files, whereas the inline definition placed the configs after the jars.
|
88
|
+
#
|
89
|
+
# This difference does not present a problem in caTissue 1.1.2, but the confusion was
|
90
|
+
# carried over to caTissue 1.2 where it does cause a problem. Unlike caTissue 1.1.2,
|
91
|
+
# in 1.2 the +DynamicExtension.jar+ is redundantly included in both the client and the
|
92
|
+
# declient lib. Furthermore, +DynamicExtension.jar+ contains an invalid and unnecessary
|
93
|
+
# +remoteServices.xml+, which references a non-existent +RemoteSDKApplicationService+.
|
94
|
+
#
|
95
|
+
# If the caTissue path is defined with the jars preceding the configs, then in 1.2 an
|
96
|
+
# obscure +PropertyAccessExceptionsException+ exception is raised indicating that
|
97
|
+
# +RemoteSDKApplicationService+ is an invalid class name. The cause is the classpath
|
98
|
+
# precedence of jars prior to configs.
|
99
|
+
#
|
100
|
+
# The caRuby FAQ shows an example +~/.catissue+ +path+ property that was originally
|
101
|
+
# borrowed from the caTissue 1.1.1 client example. This incorrect precedence was a time
|
102
|
+
# bomb that exploded in 1.2. This 1.2 regression is now noted in the FAQ.
|
103
|
+
#
|
104
|
+
# @quirk caTissue 1.2 per the caTissue API client Ant build file, the +catissuecore.jar+
|
105
|
+
# should not be included in the client class path, even though it is in the client lib
|
106
|
+
# directory.
|
107
|
+
def infer_classpath
|
108
|
+
dir = ENV['CATISSUE_CLIENT_HOME'] || '.'
|
109
|
+
logger.info("Inferring the class path from directory #{dir}...")
|
110
|
+
# Hunt for the client directories
|
111
|
+
clt_dir = client_directory(dir, 'caTissueSuite_Client')
|
112
|
+
de_dir = client_directory(dir, 'catissue_de_integration_client')
|
113
|
+
dirs = [client_subdirectory(clt_dir, 'conf'),
|
114
|
+
client_subdirectory(de_dir, 'conf'),
|
115
|
+
client_subdirectory(clt_dir, 'lib'),
|
116
|
+
client_subdirectory(de_dir, 'lib')
|
117
|
+
]
|
118
|
+
# caTissue 1.1.2 has an extra directory.
|
119
|
+
clt_lib = File.expand_path('lib', dir)
|
120
|
+
dirs << clt_lib if File.directory?(clt_lib)
|
121
|
+
# Make a semi-colon separated path string.
|
122
|
+
path = dirs.join(';')
|
123
|
+
logger.info("Inferred the class path #{path}.")
|
124
|
+
path
|
125
|
+
end
|
126
|
+
|
127
|
+
def client_directory(dir, subdir)
|
128
|
+
clt_dir = File.expand_path(subdir, dir)
|
129
|
+
unless File.directory?(clt_dir) then
|
130
|
+
raise ConfigurationError.new("caTissue installation client directory not found: #{clt_dir}")
|
131
|
+
end
|
132
|
+
clt_dir
|
133
|
+
end
|
134
|
+
|
135
|
+
def client_subdirectory(dir, subdir)
|
136
|
+
clt_subdir = File.expand_path(subdir, dir)
|
137
|
+
unless File.directory?(clt_subdir) then
|
138
|
+
raise ConfigurationError.new("caTissue client directory #{dir} does not include the #{subdir} subdirectory.")
|
139
|
+
end
|
140
|
+
clt_subdir
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -1,9 +1,9 @@
|
|
1
|
-
require '
|
1
|
+
require 'jinx/helpers/partial_order'
|
2
2
|
|
3
3
|
module CaTissue
|
4
4
|
# The StorageTypeHolder mix-in adds common methods for the StorageType or StorageContainer child type accessors.
|
5
5
|
module StorageTypeHolder
|
6
|
-
include PartialOrder
|
6
|
+
include Jinx::PartialOrder
|
7
7
|
|
8
8
|
# @return [StorageType] the allowable child storage types
|
9
9
|
def child_storage_types
|
@@ -20,10 +20,16 @@ module CaTissue
|
|
20
20
|
holds_specimen_array_types
|
21
21
|
end
|
22
22
|
|
23
|
+
# Returns the {CaTissue::SpecimenArrayType} or {CaTissue::StorageType} children which this StorageTypeHolder
|
24
|
+
# can hold.
|
25
|
+
def child_container_types
|
26
|
+
child_storage_types.union(child_specimen_array_types)
|
27
|
+
end
|
28
|
+
|
23
29
|
# Returns the {CaTissue::SpecimenArrayType}, {CaTissue::AbstractSpecimen#specimen_class} or {CaTissue::StorageType}
|
24
30
|
# children which this StorageTypeHolder can hold.
|
25
31
|
def child_types
|
26
|
-
|
32
|
+
child_container_types.union(child_specimen_classes)
|
27
33
|
end
|
28
34
|
|
29
35
|
# Adds the given subtype to the list of subtypes which this StorageType can hold.
|
@@ -1,41 +1,20 @@
|
|
1
|
-
require 'caruby/
|
2
|
-
require '
|
3
|
-
require 'catissue/annotation/annotation_module'
|
1
|
+
require 'caruby/metadata'
|
2
|
+
require 'catissue/annotation/importer'
|
4
3
|
require 'catissue/annotation/de_integration'
|
5
4
|
|
6
5
|
module CaTissue
|
7
|
-
# Mix-in for extending a caTissue domain class with annotations.
|
8
|
-
module
|
6
|
+
# Mix-in for extending a caTissue domain class with +Jinx::Metadata+ introspection and annotations.
|
7
|
+
module Metadata
|
8
|
+
include CaRuby::Metadata
|
9
9
|
|
10
10
|
# @return [Integer, nil] the the hook class designator that is used by caTissue to persist primary
|
11
11
|
# annotation objects, or nil if this is not a primary annotation class
|
12
12
|
attr_reader :entity_id
|
13
|
-
|
14
|
-
# @return [Class] the {DEIntegration} proxy class (nil for 1.1 caTissue)
|
13
|
+
|
14
|
+
# @return [Class] the {Annotation::DEIntegration} proxy class (nil for 1.1 caTissue)
|
15
15
|
def de_integration_proxy_class
|
16
16
|
@de_integration_proxy_class or (superclass.de_integration_proxy_class if superclass < Annotatable)
|
17
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
|
27
|
-
|
28
|
-
def self.extended(klass)
|
29
|
-
super
|
30
|
-
# Initialize the class annotation hashes.
|
31
|
-
klass.class_eval do
|
32
|
-
# Enable the class meta-data.
|
33
|
-
# the annotation name => spec hash
|
34
|
-
@ann_spec_hash = {}
|
35
|
-
# the annotation module => proxy hash
|
36
|
-
@ann_mod_pxy_hash = {}
|
37
|
-
end
|
38
|
-
end
|
39
18
|
|
40
19
|
# @return [Integer, nil] this class's entity id, if it exists, otherwise the superclass effective entity id
|
41
20
|
# if the superclass is an annotation class
|
@@ -61,21 +40,21 @@ module CaTissue
|
|
61
40
|
annotation_defined?(symbol)
|
62
41
|
end
|
63
42
|
|
64
|
-
# Refines the
|
43
|
+
# Refines the +CaRuby::Propertied.toxic_attributes+ to exclude annotation attributes.
|
65
44
|
#
|
66
45
|
# @return [<Symbol>] the non-annotation unfetched attributes
|
67
46
|
def toxic_attributes
|
68
|
-
@
|
47
|
+
@anbl_toxic_attrs ||= unfetched_attributes.compose { |prop| not prop.type < Annotation }
|
69
48
|
end
|
70
49
|
|
71
50
|
# @param [AnnotationModule] mod the annotation module
|
72
51
|
# @return [Symbol] the corresponding annotation proxy reference attribute
|
73
52
|
def annotation_proxy_attribute(mod)
|
74
|
-
@ann_mod_pxy_hash[mod] or
|
53
|
+
(@ann_mod_pxy_hash and @ann_mod_pxy_hash[mod]) or
|
75
54
|
(superclass.annotation_proxy_attribute(mod) if superclass < Annotatable) or
|
76
55
|
raise AnnotationError.new("#{qp} #{mod} proxy attribute not found.")
|
77
56
|
end
|
78
|
-
|
57
|
+
|
79
58
|
# Loads the annotations, if necessary, and tries to get the constant again.
|
80
59
|
#
|
81
60
|
# @param [Symbol] symbol the missing constant
|
@@ -90,60 +69,58 @@ module CaTissue
|
|
90
69
|
end
|
91
70
|
end
|
92
71
|
|
93
|
-
# Filters
|
72
|
+
# Filters +CaRuby::Propertied#loadable_attributes} to exclude the {.annotation_attributes+
|
94
73
|
# since annotation lazy-loading is not supported.
|
95
74
|
#
|
96
|
-
# @return (see CaRuby::
|
75
|
+
# @return (see CaRuby::Propertied#loadable_attributes)
|
97
76
|
def loadable_attributes
|
98
|
-
@antbl_ld_attrs ||=
|
77
|
+
@antbl_ld_attrs ||= unfetched_attributes.compose do |prop|
|
78
|
+
# JRuby bug - Copied super body to avoid infinite loop. See const_missing.
|
79
|
+
prop.java_property? and not prop.type.abstract? and not prop.type < Annotation
|
80
|
+
end
|
99
81
|
end
|
100
|
-
|
82
|
+
|
101
83
|
def printable_attributes
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
def attribute_metadata(attribute)
|
106
|
-
begin
|
107
|
-
super
|
108
|
-
rescue
|
109
|
-
if annotation_attribute?(attribute) then
|
110
|
-
attribute_metadata(attribute)
|
111
|
-
else
|
112
|
-
raise
|
113
|
-
end
|
114
|
-
end
|
84
|
+
# JRuby bug - Copied super body to avoid infinite loop. See const_missing.
|
85
|
+
@prbl_attrs ||= java_attributes.union(annotation_attributes)
|
115
86
|
end
|
116
|
-
|
87
|
+
|
117
88
|
def annotation_attributes
|
89
|
+
@ann_mod_pxy_hash ||= {}
|
118
90
|
@ann_attrs ||= append_ancestor_enum(@ann_mod_pxy_hash.enum_values) do |sc|
|
119
91
|
sc.annotation_attributes if sc < Annotatable
|
120
92
|
end
|
121
93
|
end
|
122
|
-
|
94
|
+
|
123
95
|
protected
|
124
|
-
|
96
|
+
|
125
97
|
# @return [<AnnotationModule>] the annotation modules in the class hierarchy
|
126
98
|
def annotation_modules
|
127
99
|
@ann_mods ||= load_annotations
|
128
100
|
end
|
129
|
-
|
101
|
+
|
130
102
|
private
|
131
|
-
|
103
|
+
|
104
|
+
# @return [Boolean] whenter this class's annotations are loaded
|
105
|
+
def annotations_loaded?
|
106
|
+
!!@ann_mods
|
107
|
+
end
|
108
|
+
|
132
109
|
# @param [String] name the proxy record entry class name
|
133
110
|
def annotation_proxy_class_name=(name)
|
134
111
|
@de_integration_proxy_class = Annotation::DEIntegration.proxy(name)
|
135
112
|
if @de_integration_proxy_class then
|
136
113
|
# hide the internal caTissue proxy collection attribute
|
137
|
-
|
138
|
-
if
|
139
|
-
remove_attribute(
|
140
|
-
logger.debug { "Hid the internal caTissue #{qp} annotation record-keeping attribute #{
|
114
|
+
pa = detect_attribute_with_type(@de_integration_proxy_class)
|
115
|
+
if pa then
|
116
|
+
remove_attribute(pa)
|
117
|
+
logger.debug { "Hid the internal caTissue #{qp} annotation record-keeping attribute #{pa}." }
|
141
118
|
end
|
142
119
|
else
|
143
120
|
logger.debug { "Ignored the missing caTissue #{qp} proxy class name #{name}, presumably unsupported in this caTissue release." }
|
144
121
|
end
|
145
122
|
end
|
146
|
-
|
123
|
+
|
147
124
|
# Loads the annotation modules in the class hierarchy.
|
148
125
|
#
|
149
126
|
# @return [<AnnotationModule>] an Enumerable on the loaded annotation modules
|
@@ -151,15 +128,15 @@ module CaTissue
|
|
151
128
|
@local_ann_mods = load_local_annotations
|
152
129
|
superclass < Annotatable ? @local_ann_mods.union(superclass.annotation_modules) : @local_ann_mods
|
153
130
|
end
|
154
|
-
|
131
|
+
|
155
132
|
def parent_entity_id
|
156
133
|
superclass.entity_id if superclass < Annotatable
|
157
134
|
end
|
158
|
-
|
135
|
+
|
159
136
|
def annotatable_class_hierarchy
|
160
137
|
class_hierarchy.filter { |klass| klass < Annotatable }
|
161
138
|
end
|
162
|
-
|
139
|
+
|
163
140
|
# Declares an annotation scoped by this class.
|
164
141
|
#
|
165
142
|
# @param [String] name the name of the annotation module
|
@@ -167,6 +144,7 @@ module CaTissue
|
|
167
144
|
# @option opts [String] :package the package name (default is the lower-case underscore name)
|
168
145
|
# @option opts [String] :service the service name (default is the lower-case underscore name)
|
169
146
|
# @option opts [String] :group the DE group short name (default is the package)
|
147
|
+
# @option opts [String] :proxy_name the DE proxy class name (default is the class name followed by +RecordEntry+)
|
170
148
|
def add_annotation(name, opts={})
|
171
149
|
# the module symbol
|
172
150
|
mod_sym = name.camelize.to_sym
|
@@ -174,35 +152,39 @@ module CaTissue
|
|
174
152
|
pkg = opts[:package] ||= name.underscore
|
175
153
|
svc = opts[:service] ||= name.underscore
|
176
154
|
grp = opts[:group] ||= pkg
|
155
|
+
pxy_nm = opts[:proxy_name] || "#{self.name.demodulize}RecordEntry"
|
156
|
+
self.annotation_proxy_class_name = pxy_nm
|
177
157
|
# add the annotation entry
|
158
|
+
@ann_spec_hash ||= {}
|
178
159
|
@ann_spec_hash[mod_sym] = opts
|
179
160
|
logger.info("Added #{qp} annotation #{name} with module #{mod_sym}, package #{pkg}, service #{svc} and group #{grp}.")
|
180
161
|
end
|
181
|
-
|
162
|
+
|
182
163
|
# @return [Boolean] whether this annotatable class's annotations are loaded
|
183
164
|
def annotations_loaded?
|
184
|
-
|
165
|
+
!!@ann_mods
|
185
166
|
end
|
186
|
-
|
167
|
+
|
187
168
|
# Loads this class's annotations.
|
188
169
|
#
|
189
170
|
# @return [<AnnotationModule>] the loaded annotation modules
|
190
171
|
def load_local_annotations
|
172
|
+
return Array::EMPTY_ARRAY if @ann_spec_hash.nil?
|
191
173
|
# an annotated class has a hook entity id
|
192
|
-
|
174
|
+
initialize_annotation_holder
|
193
175
|
# build the annotations
|
194
176
|
@ann_spec_hash.map { |name, opts| import_annotation(name, opts) }
|
195
|
-
end
|
196
|
-
|
177
|
+
end
|
178
|
+
|
197
179
|
# Determines this annotated class's {#entity_id} and {#de_integration_proxy_class}.
|
198
180
|
def initialize_annotation_holder
|
199
181
|
@entity_id = Annotation::EntityFacade.instance.hook_entity_id(self)
|
200
182
|
end
|
201
|
-
|
183
|
+
|
202
184
|
# @param [Symbol] attribute the annotation accessor
|
203
185
|
# @return [Module] the annotation module which implements the attribute
|
204
186
|
def annotation_attribute_module(attribute)
|
205
|
-
annotation_modules.detect { |mod| mod.proxy.
|
187
|
+
annotation_modules.detect { |mod| mod.proxy.property_defined?(attribute) }
|
206
188
|
end
|
207
189
|
|
208
190
|
# Builds a new annotation module for the given module name and options.
|
@@ -213,19 +195,14 @@ module CaTissue
|
|
213
195
|
# @raise [AnnotationError] if there is no annotation proxy class
|
214
196
|
def import_annotation(name, opts)
|
215
197
|
logger.debug { "Importing #{qp} annotation #{name}..." }
|
216
|
-
# Make the annotation module scoped by this Annotatable class.
|
217
|
-
class_eval("
|
218
|
-
|
198
|
+
# Make the annotation module class scoped by this Annotatable class.
|
199
|
+
class_eval("module #{name}; end")
|
200
|
+
mod = const_get(name)
|
219
201
|
# Append the AnnotationModule methods.
|
220
|
-
|
221
|
-
#
|
222
|
-
|
223
|
-
|
224
|
-
add_dependent_attribute(attr, :logical)
|
225
|
-
logger.debug { "Created #{qp} annotation proxy logical dependent reference attribute #{attr}." }
|
226
|
-
# Fill out the dependency hierarchy.
|
227
|
-
klass.proxy.build_annotation_dependency_hierarchy
|
228
|
-
klass
|
202
|
+
mod.extend(Annotation::Importer)
|
203
|
+
# Build the annnotation module.
|
204
|
+
mod.initialize_annotation(self, opts) { |pxy| create_proxy_attribute(mod, pxy) }
|
205
|
+
mod
|
229
206
|
end
|
230
207
|
|
231
208
|
# Returns whether this class has an annotation whose proxy accessor is the
|
@@ -235,28 +212,29 @@ module CaTissue
|
|
235
212
|
# @return (see #annotation?)
|
236
213
|
# @see #annotation?
|
237
214
|
def annotation_defined?(symbol)
|
238
|
-
|
215
|
+
property_defined?(symbol) and property(symbol).type < Annotation
|
239
216
|
end
|
240
|
-
|
217
|
+
|
241
218
|
# Makes an attribute whose name is the demodulized underscored given module name.
|
242
219
|
# The attribute reader creates an {Annotation::Proxy} instance of the method
|
243
220
|
# receiver {Annotatable} instance on demand.
|
244
221
|
#
|
245
|
-
# @param [AnnotationModule]
|
246
|
-
# @return [
|
247
|
-
def create_proxy_attribute(
|
248
|
-
# the proxy class
|
249
|
-
pxy = klass.proxy
|
222
|
+
# @param [AnnotationModule] mod the subject annotation
|
223
|
+
# @return [ProxyClass] proxy the proxy class
|
224
|
+
def create_proxy_attribute(mod, proxy)
|
250
225
|
# the proxy attribute symbol
|
251
|
-
|
226
|
+
pa = mod.name.demodulize.underscore.to_sym
|
252
227
|
# Define the proxy attribute.
|
253
|
-
attr_create_on_demand_accessor(
|
228
|
+
attr_create_on_demand_accessor(pa) { Set.new }
|
254
229
|
# Register the attribute.
|
255
|
-
add_attribute(
|
256
|
-
logger.debug { "Added #{qp} #{klass.qp} annotation proxy attribute #{attr} of type #{pxy}." }
|
230
|
+
add_attribute(pa, proxy, :collection, :saved, :nosync)
|
257
231
|
# the annotation module => proxy attribute association
|
258
|
-
@ann_mod_pxy_hash
|
259
|
-
|
232
|
+
@ann_mod_pxy_hash ||= {}
|
233
|
+
@ann_mod_pxy_hash[mod] = pa
|
234
|
+
# The proxy is a logical dependent.
|
235
|
+
add_dependent_attribute(pa, :logical)
|
236
|
+
logger.debug { "Created #{qp} #{mod.qp} annotation proxy logical dependent reference attribute #{pa} to #{proxy}." }
|
237
|
+
pa
|
260
238
|
end
|
261
239
|
end
|
262
240
|
end
|