Class: Inferno::DSL::MustSupportAssessment::InternalMustSupportLogic
- Inherits:
-
Object
- Object
- Inferno::DSL::MustSupportAssessment::InternalMustSupportLogic
show all
- Includes:
- FHIRResourceNavigation
- Defined in:
- lib/inferno/dsl/must_support_assessment.rb
Constant Summary
FHIRResourceNavigation::DAR_EXTENSION_URL, FHIRResourceNavigation::PRIMITIVE_DATA_TYPES
Instance Attribute Summary collapse
Instance Method Summary
collapse
-
#any_choice_supported?(choices) ⇒ Boolean
-
#any_elements_choice_supported?(choices) ⇒ Boolean
-
#any_extension_ids_choice_supported?(choices) ⇒ Boolean
-
#any_path_choice_supported?(choices) ⇒ Boolean
-
#any_slice_names_choice_supported?(choices) ⇒ Boolean
-
#extract_metadata(profile, ig, requirement_extension: nil) ⇒ Object
-
#find_missing_elements(resources, must_support_elements) ⇒ Object
-
#find_pattern_codeable_concept_slice(element, discriminator) ⇒ Object
-
#find_pattern_coding_slice(element, discriminator) ⇒ Object
-
#find_pattern_identifier_slice(element, discriminator) ⇒ Object
-
#find_required_binding_slice(element, discriminator) ⇒ Object
-
#find_slice(resource, path, discriminator) ⇒ Object
-
#find_slice_by_values(element, value_definitions) ⇒ Object
-
#find_type_slice(element, discriminator) ⇒ Object
-
#find_value_slice(element, discriminator) ⇒ Object
-
#handle_must_support_choices ⇒ Object
-
#handle_must_support_element_choices ⇒ Object
-
#handle_must_support_extension_choices ⇒ Object
-
#handle_must_support_slice_choices ⇒ Object
-
#initialize(metadata = nil) ⇒ InternalMustSupportLogic
constructor
A new instance of InternalMustSupportLogic.
-
#matches_fixed_value?(value, fixed_value) ⇒ Boolean
-
#matching_without_extensions?(value, ms_extension_urls, fixed_value) ⇒ Boolean
-
#missing_element_string(element_definition) ⇒ Object
-
#missing_elements(resources = []) ⇒ Object
-
#missing_extensions(resources = []) ⇒ Object
-
#missing_must_support_strings ⇒ Object
-
#missing_slices(resources = []) ⇒ Object
-
#must_support_elements ⇒ Object
-
#must_support_extensions ⇒ Object
-
#must_support_slices ⇒ Object
-
#perform_must_support_test_with_metadata(resources, profile_metadata, debug_metadata: false) ⇒ Array<String>
perform_must_support_test_with_metadata is invoked from check and perform_must_support_test, with the metadata to be used as the basis for the test.
-
#perform_test(resources) ⇒ Object
-
#process_must_support_element_in_extension(resource, path) ⇒ Object
-
#resource_populates_element?(resource, element_definition) ⇒ Boolean
-
#value_without_extensions?(value) ⇒ Boolean
-
#write_metadata_for_debugging ⇒ Object
#current_and_child_values_match?, #find_a_value_at, #find_in_elements, #find_slice_via_discriminator, #flatten_bundles, #get_next_value, #get_primitive_type_value, #local_field_name, #matching_pattern_codeable_concept_slice?, #matching_pattern_coding_slice?, #matching_pattern_identifier_slice?, #matching_required_binding_slice?, #matching_slice?, #matching_type_slice?, #matching_value_slice?, #resolve_path, #verify_slice_by_values
Constructor Details
Returns a new instance of InternalMustSupportLogic.
68
69
70
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 68
def initialize(metadata = nil)
@metadata = metadata
end
|
Instance Attribute Details
Returns the value of attribute metadata.
66
67
68
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 66
def metadata
@metadata
end
|
Instance Method Details
#any_choice_supported?(choices) ⇒ Boolean
145
146
147
148
149
150
151
152
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 145
def any_choice_supported?(choices)
return false unless choices.present?
any_path_choice_supported?(choices) ||
any_extension_ids_choice_supported?(choices) ||
any_slice_names_choice_supported?(choices) ||
any_elements_choice_supported?(choices)
end
|
#any_elements_choice_supported?(choices) ⇒ Boolean
174
175
176
177
178
179
180
181
182
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 174
def any_elements_choice_supported?(choices)
return false unless choices[:elements].present?
choices[:elements].any? do |choice|
missing_elements.none? do |element|
element[:path] == choice[:path] && element[:fixed_value] == choice[:fixed_value]
end
end
end
|
#any_extension_ids_choice_supported?(choices) ⇒ Boolean
160
161
162
163
164
165
166
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 160
def any_extension_ids_choice_supported?(choices)
return false unless choices[:extension_ids].present?
choices[:extension_ids].any? do |extension_id|
missing_extensions.none? { |extension| extension[:id] == extension_id }
end
end
|
#any_path_choice_supported?(choices) ⇒ Boolean
154
155
156
157
158
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 154
def any_path_choice_supported?(choices)
return false unless choices[:paths].present?
choices[:paths].any? { |path| missing_elements.none? { |element| element[:path] == path } }
end
|
#any_slice_names_choice_supported?(choices) ⇒ Boolean
168
169
170
171
172
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 168
def any_slice_names_choice_supported?(choices)
return false unless choices[:slice_names].present?
choices[:slice_names].any? { |slice_name| missing_slices.none? { |slice| slice[:name] == slice_name } }
end
|
89
90
91
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 89
def (profile, ig, requirement_extension: nil)
.new(profile.snapshot.element, profile, profile.type, ig, requirement_extension)
end
|
#find_missing_elements(resources, must_support_elements) ⇒ Object
229
230
231
232
233
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 229
def find_missing_elements(resources, must_support_elements)
must_support_elements.select do |element_definition|
resources.none? { |resource| resource_populates_element?(resource, element_definition) }
end
end
|
#find_pattern_codeable_concept_slice(element, discriminator) ⇒ Object
328
329
330
331
332
333
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 328
def find_pattern_codeable_concept_slice(element, discriminator)
coding_path = discriminator[:path].present? ? "#{discriminator[:path]}.coding" : 'coding'
find_a_value_at(element, coding_path) do |coding|
coding.code == discriminator[:code] && coding.system == discriminator[:system]
end
end
|
#find_pattern_coding_slice(element, discriminator) ⇒ Object
335
336
337
338
339
340
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 335
def find_pattern_coding_slice(element, discriminator)
coding_path = discriminator[:path].present? ? discriminator[:path] : ''
find_a_value_at(element, coding_path) do |coding|
coding.code == discriminator[:code] && coding.system == discriminator[:system]
end
end
|
#find_pattern_identifier_slice(element, discriminator) ⇒ Object
342
343
344
345
346
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 342
def find_pattern_identifier_slice(element, discriminator)
find_a_value_at(element, discriminator[:path]) do |identifier|
identifier.system == discriminator[:system]
end
end
|
#find_required_binding_slice(element, discriminator) ⇒ Object
379
380
381
382
383
384
385
386
387
388
389
390
391
392
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 379
def find_required_binding_slice(element, discriminator)
coding_path = discriminator[:path].present? ? "#{discriminator[:path]}.coding" : 'coding'
find_a_value_at(element, coding_path) do |coding|
discriminator[:values].any? do |value|
case value
when String
value == coding.code
when Hash
value[:system] == coding.system && value[:code] == coding.code
end
end
end
end
|
#find_slice(resource, path, discriminator) ⇒ Object
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 306
def find_slice(resource, path, discriminator)
find_a_value_at(resource, path) do |element|
case discriminator[:type]
when 'patternCodeableConcept'
find_pattern_codeable_concept_slice(element, discriminator)
when 'patternCoding'
find_pattern_coding_slice(element, discriminator)
when 'patternIdentifier'
find_pattern_identifier_slice(element, discriminator)
when 'value'
find_value_slice(element, discriminator)
when 'type'
find_type_slice(element, discriminator)
when 'requiredBinding'
find_required_binding_slice(element, discriminator)
end
end
end
|
#find_slice_by_values(element, value_definitions) ⇒ Object
394
395
396
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 394
def find_slice_by_values(element, value_definitions)
Array.wrap(element).find { |el| verify_slice_by_values(el, value_definitions) }
end
|
#find_type_slice(element, discriminator) ⇒ Object
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 353
def find_type_slice(element, discriminator)
case discriminator[:code]
when 'Date'
begin
Date.parse(element)
rescue ArgumentError, TypeError
false
end
when 'DateTime'
begin
DateTime.parse(element)
rescue ArgumentError, TypeError
false
end
when 'String'
element.is_a? String
else
if element.is_a? FHIR::Bundle::Entry
element = element.resource
end
element.is_a? FHIR.const_get(discriminator[:code])
end
end
|
#find_value_slice(element, discriminator) ⇒ Object
348
349
350
351
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 348
def find_value_slice(element, discriminator)
values = discriminator[:values].map { |value| value.merge(path: value[:path].split('.')) }
find_slice_by_values(element, values)
end
|
#handle_must_support_choices ⇒ Object
113
114
115
116
117
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 113
def handle_must_support_choices
handle_must_support_element_choices
handle_must_support_extension_choices
handle_must_support_slice_choices
end
|
#handle_must_support_element_choices ⇒ Object
119
120
121
122
123
124
125
126
127
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 119
def handle_must_support_element_choices
missing_elements.delete_if do |element|
choices = metadata.must_supports[:choices].find do |choice|
choice[:paths]&.include?(element[:path]) ||
choice[:elements]&.any? { |ms_element| ms_element[:path] == element[:path] }
end
any_choice_supported?(choices)
end
end
|
#handle_must_support_extension_choices ⇒ Object
129
130
131
132
133
134
135
136
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 129
def handle_must_support_extension_choices
missing_extensions.delete_if do |extension|
choices = metadata.must_supports[:choices].find do |choice|
choice[:extension_ids]&.include?(extension[:id])
end
any_choice_supported?(choices)
end
end
|
#handle_must_support_slice_choices ⇒ Object
138
139
140
141
142
143
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 138
def handle_must_support_slice_choices
missing_slices.delete_if do |slice|
choices = metadata.must_supports[:choices].find { |choice| choice[:slice_names]&.include?(slice[:name]) }
any_choice_supported?(choices)
end
end
|
#matches_fixed_value?(value, fixed_value) ⇒ Boolean
283
284
285
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 283
def matches_fixed_value?(value, fixed_value)
fixed_value.blank? || value == fixed_value
end
|
#matching_without_extensions?(value, ms_extension_urls, fixed_value) ⇒ Boolean
271
272
273
274
275
276
277
278
279
280
281
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 271
def matching_without_extensions?(value, ms_extension_urls, fixed_value)
if value.instance_of?(Inferno::DSL::PrimitiveType)
urls = value.extension&.map(&:url)
has_ms_extension = (urls & ms_extension_urls).present?
value = value.value
end
return false unless has_ms_extension || value_without_extensions?(value)
matches_fixed_value?(value, fixed_value)
end
|
#missing_element_string(element_definition) ⇒ Object
190
191
192
193
194
195
196
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 190
def missing_element_string(element_definition)
if element_definition[:fixed_value].present?
"#{element_definition[:path]}:#{element_definition[:fixed_value]}"
else
element_definition[:path]
end
end
|
#missing_elements(resources = []) ⇒ Object
225
226
227
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 225
def missing_elements(resources = [])
@missing_elements ||= find_missing_elements(resources, must_support_elements)
end
|
#missing_extensions(resources = []) ⇒ Object
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 202
def missing_extensions(resources = [])
@missing_extensions ||=
must_support_extensions.select do |extension_definition|
resources.none? do |resource|
path = extension_definition[:path]
if path == 'extension'
resource.extension.any? { |extension| extension.url == extension_definition[:url] }
else
extension = find_a_value_at(resource, path) do |el|
el.url == extension_definition[:url]
end
extension.present?
end
end
end
end
|
#missing_must_support_strings ⇒ Object
184
185
186
187
188
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 184
def missing_must_support_strings
missing_elements.map { |element_definition| missing_element_string(element_definition) } +
missing_slices.map { |slice_definition| slice_definition[:slice_id] } +
missing_extensions.map { |extension_definition| extension_definition[:id] }
end
|
#missing_slices(resources = []) ⇒ Object
296
297
298
299
300
301
302
303
304
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 296
def missing_slices(resources = [])
@missing_slices ||=
must_support_slices.select do |slice|
resources.none? do |resource|
path = slice[:path]
find_slice(resource, path, slice[:discriminator]).present?
end
end
end
|
#must_support_elements ⇒ Object
221
222
223
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 221
def must_support_elements
metadata.must_supports[:elements]
end
|
#must_support_extensions ⇒ Object
198
199
200
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 198
def must_support_extensions
metadata.must_supports[:extensions]
end
|
#must_support_slices ⇒ Object
292
293
294
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 292
def must_support_slices
metadata.must_supports[:slices]
end
|
perform_must_support_test_with_metadata is invoked from check and perform_must_support_test, with the metadata to be used as the basis for the test. It may also be invoked directly from a test if you want to completely overwrite the metadata.
79
80
81
82
83
84
85
86
87
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 79
def perform_must_support_test_with_metadata(resources, profile_metadata, debug_metadata: false)
return if resources.blank?
@metadata = profile_metadata
write_metadata_for_debugging if debug_metadata
perform_test(resources)
end
|
103
104
105
106
107
108
109
110
111
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 103
def perform_test(resources)
missing_elements(resources)
missing_slices(resources)
missing_extensions(resources)
handle_must_support_choices if metadata.must_supports[:choices].present?
missing_must_support_strings
end
|
#process_must_support_element_in_extension(resource, path) ⇒ Object
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 252
def process_must_support_element_in_extension(resource, path)
return [resource, path] unless path.start_with?('extension:')
path_without_prefix = path.delete_prefix('extension:')
extension_split = path_without_prefix.split('.')
extension_name = extension_split.first
extension_path = extension_split.last
found_extension_url = must_support_extensions.find { |ex| ex[:id].include?(extension_name) }[:url]
ms_element_extension = resource.extension.find { |ex| ex.url == found_extension_url }
if ms_element_extension.present?
resource = ms_element_extension
path = extension_path
end
[resource, path]
end
|
#resource_populates_element?(resource, element_definition) ⇒ Boolean
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 235
def resource_populates_element?(resource, element_definition)
path = element_definition[:path]
resource, path = process_must_support_element_in_extension(resource, path) if path.start_with?('extension:')
ms_extension_urls = must_support_extensions.select { |ex| ex[:path] == "#{path}.extension" }
.map { |ex| ex[:url] }
value_found = find_a_value_at(resource, path) do |potential_value|
matching_without_extensions?(potential_value, ms_extension_urls, element_definition[:fixed_value])
end
value_found.present? || value_found == false
end
|
#value_without_extensions?(value) ⇒ Boolean
287
288
289
290
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 287
def value_without_extensions?(value)
value_without_extensions = value.respond_to?(:to_hash) ? value.to_hash.except('extension') : value
value_without_extensions.present? || value_without_extensions == false
end
|
93
94
95
96
97
98
99
100
101
|
# File 'lib/inferno/dsl/must_support_assessment.rb', line 93
def write_metadata_for_debugging
outfile = "#{metadata.profile&.id}-#{SecureRandom.uuid}.yml"
File.open(File.join(Dir.tmpdir, outfile), 'w') do |f|
writable_metadata = { must_supports: @metadata.must_supports.to_hash }
f.write(YAML.dump(writable_metadata))
puts "Wrote MustSupport metadata to #{f.path}"
end
end
|