ncs_mdes 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +8 -0
- data/README.md +7 -3
- data/documents/1.2/heuristic_overrides.yml +50 -0
- data/documents/2.0/heuristic_overrides.yml +405 -0
- data/lib/ncs_navigator/mdes/source_documents.rb +34 -1
- data/lib/ncs_navigator/mdes/specification.rb +54 -0
- data/lib/ncs_navigator/mdes/variable.rb +59 -0
- data/lib/ncs_navigator/mdes/version.rb +1 -1
- data/spec/ncs_navigator/mdes/source_documents_spec.rb +36 -8
- data/spec/ncs_navigator/mdes/specification_spec.rb +29 -13
- data/spec/ncs_navigator/mdes/variable_spec.rb +186 -0
- metadata +22 -20
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -4,8 +4,8 @@ NCS Navigator MDES Module
|
|
4
4
|
This gem provides a consistent computable interface to the National
|
5
5
|
Children's Study Master Data Element Specification. All of the data it
|
6
6
|
exposes is derived at runtime from the documents provided by the
|
7
|
-
National Children's Study Program Office, which
|
8
|
-
|
7
|
+
National Children's Study Program Office, which are embedded in the
|
8
|
+
distribution package.
|
9
9
|
|
10
10
|
Use
|
11
11
|
---
|
@@ -16,7 +16,11 @@ Use
|
|
16
16
|
mdes = NcsNavigator::Mdes('1.2')
|
17
17
|
pp mdes.transmission_tables.collect(&:name)
|
18
18
|
|
19
|
-
For more details see the API documentation, starting with
|
19
|
+
For more details see the API documentation, starting with
|
20
|
+
{NcsNavigator::Mdes::Specification}. (If you're not looking at this
|
21
|
+
document in the API documentation, try looking at [rubydoc.info][].)
|
22
|
+
|
23
|
+
[rubydoc.info]: http://rubydoc.info/github/NUBIC/ncs_mdes/master/frames
|
20
24
|
|
21
25
|
### Examine
|
22
26
|
|
@@ -0,0 +1,50 @@
|
|
1
|
+
foreign_keys:
|
2
|
+
staff_exp_mngmnt_tasks:
|
3
|
+
staff_weekly_expense_id: staff_weekly_expense
|
4
|
+
staff_exp_data_cllctn_tasks:
|
5
|
+
staff_weekly_expense_id: staff_weekly_expense
|
6
|
+
participant_consent:
|
7
|
+
person_who_consented_id: person
|
8
|
+
person_wthdrw_consent_id: person
|
9
|
+
event:
|
10
|
+
participant_id: participant
|
11
|
+
participant_vis_consent:
|
12
|
+
vis_person_who_consented_id: person
|
13
|
+
link_contact:
|
14
|
+
specimen_id: false
|
15
|
+
birth_visit:
|
16
|
+
new_address_id: address
|
17
|
+
mail_address_id: address
|
18
|
+
new_address_b_id: address
|
19
|
+
household_enumeration_hidden_du:
|
20
|
+
hdu_address_id: address
|
21
|
+
pb_recruitment:
|
22
|
+
address_pb_id: address
|
23
|
+
pre_preg:
|
24
|
+
c_addr1_id: address
|
25
|
+
c_addr2_id: address
|
26
|
+
preg_screen_eh:
|
27
|
+
mail_address_id: address
|
28
|
+
new_address_id: address
|
29
|
+
preg_screen_hi:
|
30
|
+
mail_address_id: address
|
31
|
+
new_address_id: address
|
32
|
+
preg_screen_pb:
|
33
|
+
mail_address_id: address
|
34
|
+
new_address_id: address
|
35
|
+
preg_visit_1:
|
36
|
+
b_address_id: address
|
37
|
+
c_addr1_id: address
|
38
|
+
c_addr2_id: address
|
39
|
+
preg_visit_2:
|
40
|
+
b_address_id: address
|
41
|
+
c_addr1_id: address
|
42
|
+
c_addr2_id: address
|
43
|
+
preg_visit_li:
|
44
|
+
b_address_id: address
|
45
|
+
six_mth_mother:
|
46
|
+
c_addr1_id: address
|
47
|
+
c_addr2_id: address
|
48
|
+
twelve_mth_mother:
|
49
|
+
c_addr1_id: address
|
50
|
+
c_addr2_id: address
|
@@ -0,0 +1,405 @@
|
|
1
|
+
foreign_keys:
|
2
|
+
birth_visit:
|
3
|
+
new_address_id: address
|
4
|
+
mail_address_id: address
|
5
|
+
new_address_b_id: address
|
6
|
+
|
7
|
+
birth_visit_2:
|
8
|
+
new_address_id: address
|
9
|
+
mail_address_id: address
|
10
|
+
new_address_b_id: address
|
11
|
+
|
12
|
+
birth_visit_baby_name:
|
13
|
+
bv_id: birth_visit
|
14
|
+
|
15
|
+
birth_visit_baby_name_2:
|
16
|
+
bv_id: birth_visit_2
|
17
|
+
|
18
|
+
birth_visit_decorate_room:
|
19
|
+
bv_id: birth_visit
|
20
|
+
|
21
|
+
birth_visit_decorate_room_2:
|
22
|
+
bv_id: birth_visit_2
|
23
|
+
|
24
|
+
birth_visit_li:
|
25
|
+
new_address_id: address
|
26
|
+
mail_address_id: address
|
27
|
+
new_address_b_id: address
|
28
|
+
|
29
|
+
birth_visit_renovate_room:
|
30
|
+
bv_id: birth_visit
|
31
|
+
|
32
|
+
birth_visit_renovate_room_2:
|
33
|
+
bv_id: birth_visit_2
|
34
|
+
|
35
|
+
drf_therm_verification:
|
36
|
+
equip_id: env_equipment
|
37
|
+
|
38
|
+
eighteen_mth_mother:
|
39
|
+
c_addr1_id: address
|
40
|
+
c_addr2_id: address
|
41
|
+
|
42
|
+
eighteen_mth_mother_cond:
|
43
|
+
eighteen_mth_habits_id: eighteen_mth_mother_habits
|
44
|
+
|
45
|
+
eighteen_mth_mother_saq:
|
46
|
+
asq18_address_id: address
|
47
|
+
|
48
|
+
env_equipment_prob_log:
|
49
|
+
equip_id: env_equipment
|
50
|
+
staff_id_reviewer: staff
|
51
|
+
|
52
|
+
event:
|
53
|
+
participant_id: participant
|
54
|
+
|
55
|
+
household_enumeration_hidden_du:
|
56
|
+
hdu_address_id: address
|
57
|
+
|
58
|
+
incident:
|
59
|
+
inc_staff_reporter_id: staff
|
60
|
+
inc_staff_supervisor_id: staff
|
61
|
+
inc_recip_is_participant: participant
|
62
|
+
inc_recip_is_du: dwelling_unit
|
63
|
+
inc_recip_is_staff: staff
|
64
|
+
inc_recip_is_family: person
|
65
|
+
inc_recip_is_acquaintance: person
|
66
|
+
inc_contact_person: person
|
67
|
+
|
68
|
+
participant_consent:
|
69
|
+
person_who_consented_id: person
|
70
|
+
person_wthdrw_consent_id: person
|
71
|
+
|
72
|
+
participant_vis_consent:
|
73
|
+
vis_person_who_consented_id: person
|
74
|
+
|
75
|
+
participant_rvis:
|
76
|
+
rvis_person: person
|
77
|
+
|
78
|
+
pb_recruitment:
|
79
|
+
address_pb_id: address
|
80
|
+
|
81
|
+
pb_recruitment_2:
|
82
|
+
address_pb_id: address
|
83
|
+
|
84
|
+
pb_recruitment_info_source:
|
85
|
+
pb_recruitment_id: pb_recruitment
|
86
|
+
|
87
|
+
pb_recruitment_info_source_2:
|
88
|
+
pb_recruitment_id: pb_recruitment_2
|
89
|
+
|
90
|
+
pb_recruitment_prov_source:
|
91
|
+
pb_recruitment_id: pb_recruitment
|
92
|
+
|
93
|
+
pb_recruitment_prov_source_2:
|
94
|
+
pb_recruitment_id: pb_recruitment_2
|
95
|
+
|
96
|
+
pb_recruitment_prov_svc:
|
97
|
+
pb_recruitment_id: pb_recruitment
|
98
|
+
|
99
|
+
pb_recruitment_prov_svc_2:
|
100
|
+
pb_recruitment_id: pb_recruitment_2
|
101
|
+
|
102
|
+
person:
|
103
|
+
new_address_id: address
|
104
|
+
|
105
|
+
prec_therm_cert:
|
106
|
+
equip_id: env_equipment
|
107
|
+
|
108
|
+
pre_preg:
|
109
|
+
c_addr1_id: address
|
110
|
+
c_addr2_id: address
|
111
|
+
|
112
|
+
preg_screen_eh:
|
113
|
+
mail_address_id: address
|
114
|
+
new_address_id: address
|
115
|
+
|
116
|
+
preg_screen_eh_2:
|
117
|
+
mail_address_id: address
|
118
|
+
new_address_id: address
|
119
|
+
|
120
|
+
preg_screen_eh_know_ncs:
|
121
|
+
ps_eh_id: preg_screen_eh
|
122
|
+
|
123
|
+
preg_screen_eh_know_ncs_2:
|
124
|
+
ps_eh_id: preg_screen_eh_2
|
125
|
+
|
126
|
+
preg_screen_eh_race:
|
127
|
+
ps_eh_id: preg_screen_eh
|
128
|
+
|
129
|
+
preg_screen_eh_race_2:
|
130
|
+
ps_eh_id: preg_screen_eh_2
|
131
|
+
|
132
|
+
preg_screen_hi:
|
133
|
+
mail_address_id: address
|
134
|
+
new_address_id: address
|
135
|
+
|
136
|
+
preg_screen_hi_2:
|
137
|
+
mail_address_id: address
|
138
|
+
new_address_id: address
|
139
|
+
|
140
|
+
preg_screen_hi_know_ncs:
|
141
|
+
ps_hi_id: preg_screen_hi
|
142
|
+
|
143
|
+
preg_screen_hi_know_ncs_2:
|
144
|
+
ps_hi_id: preg_screen_hi_2
|
145
|
+
|
146
|
+
preg_screen_hi_race:
|
147
|
+
ps_hi_id: preg_screen_hi
|
148
|
+
|
149
|
+
preg_screen_hi_race_2:
|
150
|
+
ps_hi_id: preg_screen_hi_2
|
151
|
+
|
152
|
+
preg_screen_pb:
|
153
|
+
mail_address_id: address
|
154
|
+
new_address_id: address
|
155
|
+
|
156
|
+
preg_screen_pb_2:
|
157
|
+
mail_address_id: address
|
158
|
+
new_address_id: address
|
159
|
+
|
160
|
+
preg_screen_pb_know_ncs:
|
161
|
+
ps_pb_id: preg_screen_pb
|
162
|
+
|
163
|
+
preg_screen_pb_know_ncs_2:
|
164
|
+
ps_pb_id: preg_screen_pb_2
|
165
|
+
|
166
|
+
preg_screen_pb_race:
|
167
|
+
ps_pb_id: preg_screen_pb
|
168
|
+
|
169
|
+
preg_screen_pb_race_2:
|
170
|
+
ps_pb_id: preg_screen_pb_2
|
171
|
+
|
172
|
+
preg_visit_1:
|
173
|
+
b_address_id: address
|
174
|
+
c_addr1_id: address
|
175
|
+
c_addr2_id: address
|
176
|
+
|
177
|
+
preg_visit_1_2:
|
178
|
+
b_address_id: address
|
179
|
+
c_addr1_id: address
|
180
|
+
c_addr2_id: address
|
181
|
+
|
182
|
+
preg_visit_1_commute:
|
183
|
+
pv1_id: preg_visit_1
|
184
|
+
|
185
|
+
preg_visit_1_commute_2:
|
186
|
+
pv1_id: preg_visit_1_2
|
187
|
+
|
188
|
+
preg_visit_1_cool:
|
189
|
+
pv1_id: preg_visit_1
|
190
|
+
|
191
|
+
preg_visit_1_cool_2:
|
192
|
+
pv1_id: preg_visit_1_2
|
193
|
+
|
194
|
+
preg_visit_1_diagnose_2:
|
195
|
+
pv1_id: preg_visit_1
|
196
|
+
|
197
|
+
preg_visit_1_diagnose_2_2:
|
198
|
+
pv1_id: preg_visit_1_2
|
199
|
+
|
200
|
+
preg_visit_1_heat2:
|
201
|
+
pv1_id: preg_visit_1
|
202
|
+
|
203
|
+
preg_visit_1_heat2_2:
|
204
|
+
pv1_id: preg_visit_2
|
205
|
+
|
206
|
+
preg_visit_1_local_trav:
|
207
|
+
pv1_id: preg_visit_1
|
208
|
+
|
209
|
+
preg_visit_1_local_trav_2:
|
210
|
+
pv1_id: preg_visit_1_2
|
211
|
+
|
212
|
+
preg_visit_1_nonenglish2_2:
|
213
|
+
pv1_id: preg_visit_1_2
|
214
|
+
|
215
|
+
preg_visit_1_pdecorate_room:
|
216
|
+
pv1_id: preg_visit_1
|
217
|
+
|
218
|
+
preg_visit_1_pdecorate_room_2:
|
219
|
+
pv1_id: preg_visit_1_2
|
220
|
+
|
221
|
+
preg_visit_1_pet_type:
|
222
|
+
pv1_id: preg_visit_1
|
223
|
+
|
224
|
+
preg_visit_1_pet_type_2:
|
225
|
+
pv1_id: preg_visit_1_2
|
226
|
+
|
227
|
+
preg_visit_1_prenovate2_room:
|
228
|
+
pv1_id: preg_visit_1
|
229
|
+
|
230
|
+
preg_visit_1_prenovate_room:
|
231
|
+
pv1_id: preg_visit_1
|
232
|
+
|
233
|
+
preg_visit_1_prenovate_room_2:
|
234
|
+
pv1_id: preg_visit_1_2
|
235
|
+
|
236
|
+
preg_visit_1_room_mold:
|
237
|
+
pv1_id: preg_visit_1
|
238
|
+
|
239
|
+
preg_visit_1_room_mold_2:
|
240
|
+
pv1_id: preg_visit_1_2
|
241
|
+
|
242
|
+
preg_visit_1_saq_2:
|
243
|
+
f_addr_id: address
|
244
|
+
|
245
|
+
preg_visit_1_sp_race:
|
246
|
+
pv1_id: preg_visit_1
|
247
|
+
|
248
|
+
preg_visit_1_sp_race_2:
|
249
|
+
pv1_id: preg_visit_1_2
|
250
|
+
|
251
|
+
preg_visit_2:
|
252
|
+
b_address_id: address
|
253
|
+
c_addr1_id: address
|
254
|
+
c_addr2_id: address
|
255
|
+
|
256
|
+
preg_visit_2_2:
|
257
|
+
b_address_id: address
|
258
|
+
c_addr1_id: address
|
259
|
+
c_addr2_id: address
|
260
|
+
|
261
|
+
preg_visit_2_cool:
|
262
|
+
pv2_id: preg_visit_2
|
263
|
+
|
264
|
+
preg_visit_2_cool_2:
|
265
|
+
pv2_id: preg_visit_2_2
|
266
|
+
|
267
|
+
preg_visit_2_diagnose_2:
|
268
|
+
pv2_id: preg_visit_2
|
269
|
+
|
270
|
+
preg_visit_2_diagnose_2_2:
|
271
|
+
pv2_id: preg_visit_2_2
|
272
|
+
|
273
|
+
preg_visit_2_heat2:
|
274
|
+
pv2_id: preg_visit_2
|
275
|
+
|
276
|
+
preg_visit_2_heat2_2:
|
277
|
+
pv2_id: preg_visit_2_2
|
278
|
+
|
279
|
+
preg_visit_2_pdecorate2_room:
|
280
|
+
pv2_id: preg_visit_2
|
281
|
+
|
282
|
+
preg_visit_2_pdecorate2_room_2:
|
283
|
+
pv2_id: preg_visit_2_2
|
284
|
+
|
285
|
+
preg_visit_2_prenovate_room:
|
286
|
+
pv2_id: preg_visit_2
|
287
|
+
|
288
|
+
preg_visit_2_prenovate_room_2:
|
289
|
+
pv2_id: preg_visit_2_2
|
290
|
+
|
291
|
+
preg_visit_2_room_mold:
|
292
|
+
pv2_id: preg_visit_2
|
293
|
+
|
294
|
+
preg_visit_2_room_mold_2:
|
295
|
+
pv2_id: preg_visit_2_2
|
296
|
+
|
297
|
+
preg_visit_li:
|
298
|
+
b_address_id: address
|
299
|
+
|
300
|
+
preg_visit_li_2:
|
301
|
+
b_address_id: address
|
302
|
+
|
303
|
+
preg_visit_li_cool:
|
304
|
+
pv_li_id: preg_visit_li
|
305
|
+
|
306
|
+
preg_visit_li_cool_2:
|
307
|
+
pv_li_id: preg_visit_li_2
|
308
|
+
|
309
|
+
ref_freezer_verification:
|
310
|
+
equip_id: env_equipment
|
311
|
+
|
312
|
+
sample_receipt_store:
|
313
|
+
equip_id: env_equipment
|
314
|
+
|
315
|
+
sample_shipping:
|
316
|
+
staff_id_track: staff
|
317
|
+
|
318
|
+
six_mth_mother:
|
319
|
+
c_addr1_id: address
|
320
|
+
c_addr2_id: address
|
321
|
+
|
322
|
+
six_mth_saq_formula_type:
|
323
|
+
six_mth_saq_id: six_mth_saq
|
324
|
+
|
325
|
+
six_mth_saq_formula_type_2:
|
326
|
+
six_mth_saq_id: six_mth_saq_2
|
327
|
+
|
328
|
+
six_mth_saq_supp:
|
329
|
+
six_mth_saq_id: six_mth_saq
|
330
|
+
|
331
|
+
six_mth_saq_supp_2:
|
332
|
+
six_mth_saq_id: six_mth_saq_2
|
333
|
+
|
334
|
+
six_mth_saq_water:
|
335
|
+
six_mth_saq_id: six_mth_saq
|
336
|
+
|
337
|
+
six_mth_saq_water_2:
|
338
|
+
six_mth_saq_id: six_mth_saq_2
|
339
|
+
|
340
|
+
spec_blood:
|
341
|
+
equip_id: spec_equipment
|
342
|
+
|
343
|
+
spec_receipt:
|
344
|
+
# Insufficient info to determine what this is supposed to link to
|
345
|
+
storage_container_id: false
|
346
|
+
equip_id: spec_equipment
|
347
|
+
|
348
|
+
spec_shipping:
|
349
|
+
shipper_id: false
|
350
|
+
|
351
|
+
spec_storage:
|
352
|
+
equip_id: spec_equipment
|
353
|
+
|
354
|
+
staff_exp_mngmnt_tasks:
|
355
|
+
staff_weekly_expense_id: staff_weekly_expense
|
356
|
+
|
357
|
+
staff_exp_data_cllctn_tasks:
|
358
|
+
staff_weekly_expense_id: staff_weekly_expense
|
359
|
+
|
360
|
+
trh_meter_calibration:
|
361
|
+
equip_id: spec_equipment
|
362
|
+
|
363
|
+
twelve_mth_mother:
|
364
|
+
c_addr1_id: address
|
365
|
+
c_addr2_id: address
|
366
|
+
|
367
|
+
twelve_mth_saq_formula_brand:
|
368
|
+
twelve_mth_saq_id: twelve_mth_saq
|
369
|
+
|
370
|
+
twelve_mth_saq_formula_brand_2:
|
371
|
+
twelve_mth_saq_id: twelve_mth_saq_2
|
372
|
+
|
373
|
+
twelve_mth_saq_formula_type:
|
374
|
+
twelve_mth_saq_id: twelve_mth_saq
|
375
|
+
|
376
|
+
twelve_mth_saq_formula_type_2:
|
377
|
+
twelve_mth_saq_id: twelve_mth_saq_2
|
378
|
+
|
379
|
+
twelve_mth_saq_supplement:
|
380
|
+
twelve_mth_saq_id: twelve_mth_saq
|
381
|
+
|
382
|
+
twelve_mth_saq_supplement_2:
|
383
|
+
twelve_mth_saq_id: twelve_mth_saq_2
|
384
|
+
|
385
|
+
twelve_mth_saq_water:
|
386
|
+
twelve_mth_saq_id: twelve_mth_saq
|
387
|
+
|
388
|
+
twelve_mth_saq_water_2:
|
389
|
+
twelve_mth_saq_id: twelve_mth_saq_2
|
390
|
+
|
391
|
+
twenty_four_mth_mother:
|
392
|
+
c_addr1_id: address
|
393
|
+
c_addr2_id: address
|
394
|
+
|
395
|
+
twenty_four_mth_mother_otc:
|
396
|
+
twenty_four_mth_mother_id: twenty_four_mth_mother
|
397
|
+
|
398
|
+
twenty_four_mth_mother_prescr:
|
399
|
+
twenty_four_mth_mother_id: twenty_four_mth_mother
|
400
|
+
|
401
|
+
twenty_four_mth_mother_suppl:
|
402
|
+
twenty_four_mth_mother_id: twenty_four_mth_mother
|
403
|
+
|
404
|
+
twenty_four_mth_saq:
|
405
|
+
asq24_address_id: address
|
@@ -55,6 +55,7 @@ module NcsNavigator::Mdes
|
|
55
55
|
self.new.tap do |sd|
|
56
56
|
sd.version = version
|
57
57
|
sd.schema = schema
|
58
|
+
sd.heuristic_overrides = "#{version}/heuristic_overrides.yml"
|
58
59
|
end
|
59
60
|
end
|
60
61
|
private :create
|
@@ -86,7 +87,7 @@ module NcsNavigator::Mdes
|
|
86
87
|
#
|
87
88
|
# @return [String]
|
88
89
|
def schema
|
89
|
-
|
90
|
+
absolutize(@schema)
|
90
91
|
end
|
91
92
|
|
92
93
|
##
|
@@ -99,5 +100,37 @@ module NcsNavigator::Mdes
|
|
99
100
|
def schema=(path)
|
100
101
|
@schema = path
|
101
102
|
end
|
103
|
+
|
104
|
+
##
|
105
|
+
# The absolute path to a YAML-formatted document defining
|
106
|
+
# overrides of heuristics this library uses to do mapping when
|
107
|
+
# there is insufficient computable information in the other source
|
108
|
+
# documents.
|
109
|
+
#
|
110
|
+
# This is path is optional; if one is not provided no overrides
|
111
|
+
# will be attempted.
|
112
|
+
#
|
113
|
+
# @return [String]
|
114
|
+
def heuristic_overrides
|
115
|
+
absolutize(@heuristic_overrides)
|
116
|
+
end
|
117
|
+
|
118
|
+
##
|
119
|
+
# Set the path to the heuristics override document.
|
120
|
+
# If the path is relative (i.e., it does not begin with `/`), it
|
121
|
+
# will be interpreted relative to {#base}.
|
122
|
+
#
|
123
|
+
# @param [String] path
|
124
|
+
# @return [String] the provided path
|
125
|
+
def heuristic_overrides=(path)
|
126
|
+
@heuristic_overrides = path
|
127
|
+
end
|
128
|
+
|
129
|
+
private
|
130
|
+
|
131
|
+
def absolutize(path)
|
132
|
+
return nil unless path
|
133
|
+
path[0, 1] == '/' ? path : File.join(base, path)
|
134
|
+
end
|
102
135
|
end
|
103
136
|
end
|
@@ -3,6 +3,7 @@ require 'ncs_navigator/mdes'
|
|
3
3
|
require 'forwardable'
|
4
4
|
require 'logger'
|
5
5
|
require 'nokogiri'
|
6
|
+
require 'yaml'
|
6
7
|
|
7
8
|
module NcsNavigator::Mdes
|
8
9
|
class Specification
|
@@ -42,6 +43,27 @@ module NcsNavigator::Mdes
|
|
42
43
|
@xsd ||= Nokogiri::XML(File.read source_documents.schema)
|
43
44
|
end
|
44
45
|
|
46
|
+
##
|
47
|
+
# @return [Hash] the loaded heuristic overrides, or a default
|
48
|
+
# (empty) set
|
49
|
+
def heuristic_overrides
|
50
|
+
@heuristic_overrides ||=
|
51
|
+
begin
|
52
|
+
if File.exist?(source_documents.heuristic_overrides)
|
53
|
+
empty_overrides.merge(YAML.load(File.read source_documents.heuristic_overrides))
|
54
|
+
else
|
55
|
+
empty_overrides
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def empty_overrides
|
61
|
+
{
|
62
|
+
'foreign_keys' => { }
|
63
|
+
}
|
64
|
+
end
|
65
|
+
private :empty_overrides
|
66
|
+
|
45
67
|
##
|
46
68
|
# @return [Array<TransmissionTable>] all the transmission tables
|
47
69
|
# in this version of the MDES.
|
@@ -57,10 +79,42 @@ module NcsNavigator::Mdes
|
|
57
79
|
TransmissionTable.from_element(table_elt, :log => @log)
|
58
80
|
}.tap { |tables|
|
59
81
|
tables.each { |t| t.variables.each { |v| v.resolve_type!(types, :log => @log) } }
|
82
|
+
# All types must be resolved before doing FK resolution or
|
83
|
+
# forward refs are missed.
|
84
|
+
tables.each { |t|
|
85
|
+
fk_overrides = heuristic_overrides['foreign_keys'][t.name] || { }
|
86
|
+
t.variables.each { |v|
|
87
|
+
v.resolve_foreign_key!(tables, fk_overrides[v.name], :log => @log)
|
88
|
+
}
|
89
|
+
}
|
60
90
|
}
|
61
91
|
end
|
62
92
|
private :read_transmission_tables
|
63
93
|
|
94
|
+
##
|
95
|
+
# A shortcut for accessing particular {#transmission_tables}.
|
96
|
+
#
|
97
|
+
# @overload [](table_name)
|
98
|
+
# Retrieves a single table by name.
|
99
|
+
# @param [String] table_name the transmission table to return.
|
100
|
+
# @return [TransmissionTable,nil] the matching table or nothing.
|
101
|
+
#
|
102
|
+
# @overload [](pattern)
|
103
|
+
# Searches the transmission tables by name.
|
104
|
+
# @param [Regexp] pattern the pattern to match the name against.
|
105
|
+
# @return [Array<TransmissionTable>] the matching tables (or an
|
106
|
+
# empty array).
|
107
|
+
def [](criterion)
|
108
|
+
case criterion
|
109
|
+
when Regexp
|
110
|
+
transmission_tables.select { |t| t.name =~ criterion }
|
111
|
+
when String
|
112
|
+
transmission_tables.detect { |t| t.name == criterion }
|
113
|
+
else
|
114
|
+
fail "Unexpected criterion #{criterion.inspect}"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
64
118
|
##
|
65
119
|
# @return [Array<VariableType>] all the named types in the
|
66
120
|
# MDES. This includes all the code lists.
|
@@ -37,6 +37,13 @@ module NcsNavigator::Mdes
|
|
37
37
|
attr_accessor :required
|
38
38
|
alias :required? :required
|
39
39
|
|
40
|
+
##
|
41
|
+
# If this variable is a foreign key, this is the {table
|
42
|
+
# TransmissionTable} to which it refers.
|
43
|
+
#
|
44
|
+
# @return [TransmissionTable,nil] the parent table.
|
45
|
+
attr_accessor :table_reference
|
46
|
+
|
40
47
|
class << self
|
41
48
|
##
|
42
49
|
# Examines the given parsed element and creates a new
|
@@ -115,5 +122,57 @@ module NcsNavigator::Mdes
|
|
115
122
|
log.warn("Undefined type #{type.name} for #{name}.") if log
|
116
123
|
end
|
117
124
|
end
|
125
|
+
|
126
|
+
##
|
127
|
+
# Attempts to resolve this variable as a {reference to another
|
128
|
+
# table #table_reference}. There are two mechanisms for performing
|
129
|
+
# the resolution:
|
130
|
+
#
|
131
|
+
# 1. If an `override_name` is provided, that table will be looked
|
132
|
+
# up in the provided table list. If it exists, it will be used,
|
133
|
+
# otherwise nothing will be set.
|
134
|
+
# 2. If the type of this variable is one of the NCS FK types and
|
135
|
+
# there exists exactly one table in `tables` whose primary key
|
136
|
+
# has the same name as this variable, that table will be used.
|
137
|
+
#
|
138
|
+
# Alternatively, to suppress the heuristics without providing a
|
139
|
+
# replacement, pass `false` as the `override_name`
|
140
|
+
#
|
141
|
+
# @param [Array<TransmissionTable>] tables the tables to search
|
142
|
+
# for a parent.
|
143
|
+
# @param [String,nil] override_name the name of a table to use as
|
144
|
+
# the parent. Supplying a value in this parameter bypasses the
|
145
|
+
# search heuristic.
|
146
|
+
# @return [void]
|
147
|
+
def resolve_foreign_key!(tables, override_name=nil, options={})
|
148
|
+
log = options[:log] || NcsNavigator::Mdes.default_logger
|
149
|
+
|
150
|
+
case override_name
|
151
|
+
when String
|
152
|
+
self.table_reference = tables.detect { |t| t.name == override_name }
|
153
|
+
unless table_reference
|
154
|
+
log.warn("Foreign key #{name.inspect} explicitly mapped " <<
|
155
|
+
"to unknown table #{override_name.inspect}.")
|
156
|
+
end
|
157
|
+
when nil
|
158
|
+
return unless (self.type && self.type.name =~ /^foreignKey/)
|
159
|
+
|
160
|
+
candidates = tables.select do |t|
|
161
|
+
t.variables.detect { |v| (v.name == name) && (v.type && (v.type.name =~ /^primaryKey/)) }
|
162
|
+
end
|
163
|
+
|
164
|
+
case candidates.size
|
165
|
+
when 0
|
166
|
+
log.warn("Foreign key not resolvable: " <<
|
167
|
+
"no tables have a primary key named #{name.inspect}.")
|
168
|
+
when 1
|
169
|
+
self.table_reference = candidates.first
|
170
|
+
else
|
171
|
+
log.warn(
|
172
|
+
"#{candidates.size} possible parent tables found for foreign key #{name.inspect}: " <<
|
173
|
+
"#{candidates.collect { |c| c.name.inspect }.join(', ')}. None used due to ambiguity.")
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
118
177
|
end
|
119
178
|
end
|
@@ -23,21 +23,41 @@ module NcsNavigator::Mdes
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
|
27
|
-
let(:docs) { SourceDocuments.new }
|
26
|
+
shared_examples 'an absolutizing path accessor' do
|
27
|
+
let(:docs) { SourceDocuments.new.tap { |d| d.base = '/baz' } }
|
28
|
+
|
29
|
+
def set(value)
|
30
|
+
docs.send("#{property}=", value)
|
31
|
+
end
|
28
32
|
|
29
|
-
|
30
|
-
docs.
|
33
|
+
def actual
|
34
|
+
docs.send(property)
|
31
35
|
end
|
32
36
|
|
33
37
|
it 'absolutizes a relative path against the base' do
|
34
|
-
|
35
|
-
|
38
|
+
set('1.3/bar.foo')
|
39
|
+
actual.should == '/baz/1.3/bar.foo'
|
36
40
|
end
|
37
41
|
|
38
42
|
it 'leaves an absolute path alone' do
|
39
|
-
|
40
|
-
|
43
|
+
set '/somewhere/particular.ext'
|
44
|
+
actual.should == '/somewhere/particular.ext'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe '#schema' do
|
49
|
+
let(:property) { :schema }
|
50
|
+
|
51
|
+
it_behaves_like 'an absolutizing path accessor'
|
52
|
+
end
|
53
|
+
|
54
|
+
describe '#heuristic_overrides' do
|
55
|
+
let(:property) { :heuristic_overrides }
|
56
|
+
|
57
|
+
it_behaves_like 'an absolutizing path accessor'
|
58
|
+
|
59
|
+
it 'is optional' do
|
60
|
+
SourceDocuments.new.heuristic_overrides.should be_nil
|
41
61
|
end
|
42
62
|
end
|
43
63
|
|
@@ -49,6 +69,10 @@ module NcsNavigator::Mdes
|
|
49
69
|
subject.schema.should =~ %r{1.2/Data_Transmission_Schema_V1.2.xsd$}
|
50
70
|
end
|
51
71
|
|
72
|
+
it 'has the correct path for the overrides' do
|
73
|
+
subject.heuristic_overrides.should =~ %r{1.2/heuristic_overrides.yml$}
|
74
|
+
end
|
75
|
+
|
52
76
|
it 'is of the specified version' do
|
53
77
|
subject.version.should == '1.2'
|
54
78
|
end
|
@@ -61,6 +85,10 @@ module NcsNavigator::Mdes
|
|
61
85
|
subject.schema.should =~ %r{2.0/NCS_Transmission_Schema_2.0.01.02.xml$}
|
62
86
|
end
|
63
87
|
|
88
|
+
it 'has the correct path for the overrides' do
|
89
|
+
subject.heuristic_overrides.should =~ %r{2.0/heuristic_overrides.yml$}
|
90
|
+
end
|
91
|
+
|
64
92
|
it 'is of the specified version' do
|
65
93
|
subject.version.should == '2.0'
|
66
94
|
end
|
@@ -31,13 +31,7 @@ module NcsNavigator::Mdes
|
|
31
31
|
should be_a TransmissionTable
|
32
32
|
end
|
33
33
|
|
34
|
-
|
35
|
-
let!(:tables) { Specification.new('1.2', :log => logger).transmission_tables }
|
36
|
-
|
37
|
-
it 'has 124 tables' do
|
38
|
-
tables.size.should == 124
|
39
|
-
end
|
40
|
-
|
34
|
+
shared_examples 'tables fully resolved' do
|
41
35
|
it 'emits no warnings' do
|
42
36
|
logger[:warn].should == []
|
43
37
|
end
|
@@ -49,6 +43,16 @@ module NcsNavigator::Mdes
|
|
49
43
|
end
|
50
44
|
end
|
51
45
|
|
46
|
+
context 'in version 1.2' do
|
47
|
+
let!(:tables) { Specification.new('1.2', :log => logger).transmission_tables }
|
48
|
+
|
49
|
+
it 'has 124 tables' do
|
50
|
+
tables.size.should == 124
|
51
|
+
end
|
52
|
+
|
53
|
+
include_examples 'tables fully resolved'
|
54
|
+
end
|
55
|
+
|
52
56
|
context 'in version 2.0' do
|
53
57
|
let!(:tables) { Specification.new('2.0', :log => logger).transmission_tables }
|
54
58
|
|
@@ -56,14 +60,26 @@ module NcsNavigator::Mdes
|
|
56
60
|
tables.size.should == 264
|
57
61
|
end
|
58
62
|
|
59
|
-
|
60
|
-
|
63
|
+
include_examples 'tables fully resolved'
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe '#[]' do
|
68
|
+
let(:spec) { Specification.new('2.0') }
|
69
|
+
|
70
|
+
describe 'with a string' do
|
71
|
+
it 'returns a single table if there is a match by name' do
|
72
|
+
spec['listing_unit'].should be_a TransmissionTable
|
61
73
|
end
|
62
74
|
|
63
|
-
it '
|
64
|
-
|
65
|
-
|
66
|
-
|
75
|
+
it 'returns nothing if there is no match' do
|
76
|
+
spec['fred'].should be_nil
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe 'with a regular expression' do
|
81
|
+
it 'returns a list of tables whose names match' do
|
82
|
+
spec[/^preg_visit_1.*2$/].should have(15).tables
|
67
83
|
end
|
68
84
|
end
|
69
85
|
end
|
@@ -212,5 +212,191 @@ XSD
|
|
212
212
|
end
|
213
213
|
end
|
214
214
|
end
|
215
|
+
|
216
|
+
describe '#resolve_foreign_key!' do
|
217
|
+
let(:variable) {
|
218
|
+
Variable.new('helicopter_id').tap { |v| v.type = variable_type }
|
219
|
+
}
|
220
|
+
|
221
|
+
let(:table) {
|
222
|
+
TransmissionTable.new('flights').tap do |t|
|
223
|
+
t.variables = [ variable ]
|
224
|
+
end
|
225
|
+
}
|
226
|
+
|
227
|
+
let(:table_with_matching_pk) {
|
228
|
+
TransmissionTable.new('helicopters').tap do |t|
|
229
|
+
t.variables = [
|
230
|
+
Variable.new('helicopter_id').tap do |v|
|
231
|
+
v.type = VariableType.new('primaryKeyType')
|
232
|
+
end
|
233
|
+
]
|
234
|
+
end
|
235
|
+
}
|
236
|
+
|
237
|
+
let(:table_with_nonmatching_pk) {
|
238
|
+
TransmissionTable.new('frogs').tap do |t|
|
239
|
+
t.variables = [
|
240
|
+
Variable.new('frog_id').tap do |v|
|
241
|
+
v.type = VariableType.new('primaryKeyType')
|
242
|
+
end
|
243
|
+
]
|
244
|
+
end
|
245
|
+
}
|
246
|
+
|
247
|
+
let(:table_with_same_fk) {
|
248
|
+
TransmissionTable.new('autorotation_events').tap do |t|
|
249
|
+
t.variables = [
|
250
|
+
Variable.new('helicopter_id').tap do |v|
|
251
|
+
v.type = VariableType.new('foreignKeyTypeRequired')
|
252
|
+
end
|
253
|
+
]
|
254
|
+
end
|
255
|
+
}
|
256
|
+
|
257
|
+
let(:all_tables) {
|
258
|
+
[table, table_with_matching_pk, table_with_nonmatching_pk, table_with_same_fk]
|
259
|
+
}
|
260
|
+
|
261
|
+
# These are overridden in nested contexts as necessary
|
262
|
+
let(:override) { nil }
|
263
|
+
let(:tables) { all_tables }
|
264
|
+
|
265
|
+
before do
|
266
|
+
variable.resolve_foreign_key!(tables, override, :log => logger)
|
267
|
+
end
|
268
|
+
|
269
|
+
shared_examples 'a foreign key' do
|
270
|
+
context 'when there is no table matching' do
|
271
|
+
context 'and there is no override' do
|
272
|
+
let(:tables) {
|
273
|
+
[table, table_with_same_fk, table_with_nonmatching_pk]
|
274
|
+
}
|
275
|
+
|
276
|
+
it 'does not set a table reference' do
|
277
|
+
variable.table_reference.should be_nil
|
278
|
+
end
|
279
|
+
|
280
|
+
it 'warns' do
|
281
|
+
logger[:warn].first.
|
282
|
+
should == 'Foreign key not resolvable: no tables have a primary key named "helicopter_id".'
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
include_examples 'for overrides'
|
287
|
+
end
|
288
|
+
|
289
|
+
context 'when there is exactly one matching table' do
|
290
|
+
let(:tables) { all_tables }
|
291
|
+
|
292
|
+
context 'and there is no override' do
|
293
|
+
it 'sets the table_reference to that matching table' do
|
294
|
+
variable.table_reference.should be table_with_matching_pk
|
295
|
+
end
|
296
|
+
|
297
|
+
it 'does not warn' do
|
298
|
+
logger[:warn].should be_empty
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
include_examples 'for overrides'
|
303
|
+
end
|
304
|
+
|
305
|
+
context 'when there is more than one matching table' do
|
306
|
+
let(:other_matches) {
|
307
|
+
[
|
308
|
+
TransmissionTable.new('helicopters_2').tap { |t|
|
309
|
+
t.variables = table_with_matching_pk.variables.dup
|
310
|
+
},
|
311
|
+
TransmissionTable.new('choppers').tap { |t|
|
312
|
+
t.variables = table_with_matching_pk.variables.dup
|
313
|
+
}
|
314
|
+
]
|
315
|
+
}
|
316
|
+
|
317
|
+
let(:tables) { all_tables + other_matches }
|
318
|
+
|
319
|
+
context 'and there is no override' do
|
320
|
+
it 'does not set a table reference' do
|
321
|
+
variable.table_reference.should be_nil
|
322
|
+
end
|
323
|
+
|
324
|
+
it 'warns' do
|
325
|
+
logger[:warn].first.
|
326
|
+
should == '3 possible parent tables found for foreign key "helicopter_id": "helicopters", "helicopters_2", "choppers". None used due to ambiguity.'
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
include_examples 'for overrides'
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
shared_examples 'for overrides' do
|
335
|
+
context 'and there is an override' do
|
336
|
+
context 'and the override is to a known table' do
|
337
|
+
let(:override) { table_with_same_fk.name }
|
338
|
+
|
339
|
+
it 'sets the table reference to the override' do
|
340
|
+
variable.table_reference.should be table_with_same_fk
|
341
|
+
end
|
342
|
+
|
343
|
+
it 'does not warn' do
|
344
|
+
logger[:warn].should == []
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
context 'and the override is to an unknown table' do
|
349
|
+
let(:override) { 'aircraft' }
|
350
|
+
|
351
|
+
it 'does not set a table reference' do
|
352
|
+
variable.table_reference.should be_nil
|
353
|
+
end
|
354
|
+
|
355
|
+
it 'warns' do
|
356
|
+
logger[:warn].first.
|
357
|
+
should == 'Foreign key "helicopter_id" explicitly mapped to unknown table "aircraft".'
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
context 'and the override is false' do
|
362
|
+
let(:override) { false }
|
363
|
+
|
364
|
+
it 'does not set a table reference' do
|
365
|
+
variable.table_reference.should be_nil
|
366
|
+
end
|
367
|
+
|
368
|
+
it 'does not warn' do
|
369
|
+
logger[:warn].should == []
|
370
|
+
end
|
371
|
+
end
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
context 'when a nullable FK' do
|
376
|
+
let(:variable_type) { VariableType.new('foreignKeyTypeNullable') }
|
377
|
+
|
378
|
+
it_behaves_like 'a foreign key'
|
379
|
+
end
|
380
|
+
|
381
|
+
context 'when a required FK' do
|
382
|
+
let(:variable_type) { VariableType.new('foreignKeyTypeRequired') }
|
383
|
+
|
384
|
+
it_behaves_like 'a foreign key'
|
385
|
+
end
|
386
|
+
|
387
|
+
context 'when not an FK' do
|
388
|
+
let(:variable_type) { VariableType.new('confirm_cl7') }
|
389
|
+
|
390
|
+
it 'does nothing' do
|
391
|
+
variable.table_reference.should be_nil
|
392
|
+
end
|
393
|
+
|
394
|
+
it 'does not warn' do
|
395
|
+
logger[:warn].should be_empty
|
396
|
+
end
|
397
|
+
|
398
|
+
include_examples 'for overrides'
|
399
|
+
end
|
400
|
+
end
|
215
401
|
end
|
216
402
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ncs_mdes
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 19
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 3
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.3.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Rhett Sutphin
|
@@ -15,13 +15,11 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-07-
|
18
|
+
date: 2011-07-25 00:00:00 -05:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
22
|
-
|
23
|
-
prerelease: false
|
24
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
22
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
25
23
|
none: false
|
26
24
|
requirements:
|
27
25
|
- - ~>
|
@@ -31,12 +29,12 @@ dependencies:
|
|
31
29
|
- 1
|
32
30
|
- 4
|
33
31
|
version: "1.4"
|
32
|
+
requirement: *id001
|
34
33
|
type: :runtime
|
35
|
-
|
36
|
-
- !ruby/object:Gem::Dependency
|
37
|
-
name: rspec
|
34
|
+
name: nokogiri
|
38
35
|
prerelease: false
|
39
|
-
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
version_requirements: &id002 !ruby/object:Gem::Requirement
|
40
38
|
none: false
|
41
39
|
requirements:
|
42
40
|
- - ~>
|
@@ -46,12 +44,12 @@ dependencies:
|
|
46
44
|
- 2
|
47
45
|
- 6
|
48
46
|
version: "2.6"
|
47
|
+
requirement: *id002
|
49
48
|
type: :development
|
50
|
-
|
51
|
-
- !ruby/object:Gem::Dependency
|
52
|
-
name: rake
|
49
|
+
name: rspec
|
53
50
|
prerelease: false
|
54
|
-
|
51
|
+
- !ruby/object:Gem::Dependency
|
52
|
+
version_requirements: &id003 !ruby/object:Gem::Requirement
|
55
53
|
none: false
|
56
54
|
requirements:
|
57
55
|
- - ~>
|
@@ -62,12 +60,12 @@ dependencies:
|
|
62
60
|
- 9
|
63
61
|
- 2
|
64
62
|
version: 0.9.2
|
63
|
+
requirement: *id003
|
65
64
|
type: :development
|
66
|
-
|
67
|
-
- !ruby/object:Gem::Dependency
|
68
|
-
name: yard
|
65
|
+
name: rake
|
69
66
|
prerelease: false
|
70
|
-
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
version_requirements: &id004 !ruby/object:Gem::Requirement
|
71
69
|
none: false
|
72
70
|
requirements:
|
73
71
|
- - ~>
|
@@ -78,8 +76,10 @@ dependencies:
|
|
78
76
|
- 7
|
79
77
|
- 2
|
80
78
|
version: 0.7.2
|
79
|
+
requirement: *id004
|
81
80
|
type: :development
|
82
|
-
|
81
|
+
name: yard
|
82
|
+
prerelease: false
|
83
83
|
description: |
|
84
84
|
|
85
85
|
Provides a consistent ruby interface to the project metainformation in the
|
@@ -103,7 +103,9 @@ files:
|
|
103
103
|
- Rakefile
|
104
104
|
- bin/mdes-console
|
105
105
|
- documents/1.2/Data_Transmission_Schema_V1.2.xsd
|
106
|
+
- documents/1.2/heuristic_overrides.yml
|
106
107
|
- documents/2.0/NCS_Transmission_Schema_2.0.01.02.xml
|
108
|
+
- documents/2.0/heuristic_overrides.yml
|
107
109
|
- lib/ncs_navigator/mdes.rb
|
108
110
|
- lib/ncs_navigator/mdes/source_documents.rb
|
109
111
|
- lib/ncs_navigator/mdes/specification.rb
|