inferno_core 0.5.2 → 0.5.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/inferno/apps/cli/evaluate.rb +64 -0
- data/lib/inferno/apps/cli/main.rb +38 -0
- data/lib/inferno/apps/cli/templates/%library_name%.gemspec.tt +10 -3
- data/lib/inferno/apps/cli/templates/Dockerfile.tt +3 -2
- data/lib/inferno/apps/cli/templates/lib/%library_name%/metadata.rb.tt +18 -0
- data/lib/inferno/apps/cli/templates/lib/%library_name%/suite.rb.tt +59 -0
- data/lib/inferno/apps/cli/templates/lib/%library_name%/version.rb.tt +3 -0
- data/lib/inferno/apps/cli/templates/lib/%library_name%.rb.tt +1 -58
- data/lib/inferno/apps/web/serializers/input.rb +2 -1
- data/lib/inferno/apps/web/serializers/markdown_extractor.rb +16 -0
- data/lib/inferno/config/boot/presets.rb +18 -1
- data/lib/inferno/dsl/fhir_evaluation/config.rb +21 -0
- data/lib/inferno/dsl/fhir_evaluation/dataset_loader.rb +33 -0
- data/lib/inferno/dsl/fhir_evaluation/evaluation_context.rb +25 -0
- data/lib/inferno/dsl/fhir_evaluation/evaluation_result.rb +62 -0
- data/lib/inferno/dsl/fhir_evaluation/evaluator.rb +36 -0
- data/lib/inferno/dsl/fhir_evaluation/rule.rb +13 -0
- data/lib/inferno/dsl/suite_endpoint.rb +58 -58
- data/lib/inferno/dsl.rb +2 -0
- data/lib/inferno/entities/test_kit.rb +4 -2
- data/lib/inferno/entities/test_suite.rb +23 -3
- data/lib/inferno/entities.rb +1 -0
- data/lib/inferno/public/bundle.js +34 -34
- data/lib/inferno/repositories/presets.rb +12 -6
- data/lib/inferno/result_summarizer.rb +2 -0
- data/lib/inferno/utils/named_thor_actions.rb +5 -1
- data/lib/inferno/version.rb +1 -1
- metadata +14 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '090f68164e2fc19d1f97f62dd0fb13c12c77eb12c29bb9b528c9b9cb56f48770'
|
4
|
+
data.tar.gz: e239a1702ee11a85229db5355ad7c8a415d71b40018c052bb3e2c972c824d12c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2491100649bba23576a442fdeeef561b407e5f7b0b89fbd0827b55ced37e1dcf29c1f5b908c316e44c38301a74d760b5fa8bba4b2cfdf5e039d36fab4c3c181f
|
7
|
+
data.tar.gz: e05eb12863387acecd5782267f25700d3a2e233ed8f581bda98627a76822c33b5e6a1f0ed8e770a6a9d971c88be610453f0aac9a13245b8412f2cb7673431327
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require_relative '../../../inferno/dsl/fhir_evaluation/evaluator'
|
2
|
+
|
3
|
+
module Inferno
|
4
|
+
module CLI
|
5
|
+
class Evaluate
|
6
|
+
def run(ig_path, data_path, _log_level)
|
7
|
+
validate_args(ig_path, data_path)
|
8
|
+
|
9
|
+
# IG Import, rule execution, and result output below will be integrated at phase 2 and 3.
|
10
|
+
|
11
|
+
# @ig = File.join(__dir__, 'ig', ig_path)
|
12
|
+
# if data_path
|
13
|
+
# DatasetLoader.from_path(File.join(__dir__, data_path))
|
14
|
+
# else
|
15
|
+
# ig.examples
|
16
|
+
# end
|
17
|
+
|
18
|
+
# config = Config.new
|
19
|
+
# evaluator = Inferno::DSL::FHIREvaluation::Evaluator.new(data, config)
|
20
|
+
|
21
|
+
# results = evaluate()
|
22
|
+
# output_results(results, options[:output])
|
23
|
+
end
|
24
|
+
|
25
|
+
def validate_args(ig_path, data_path)
|
26
|
+
raise 'A path to an IG is required!' unless ig_path
|
27
|
+
|
28
|
+
return unless data_path && (!File.directory? data_path)
|
29
|
+
|
30
|
+
raise "Provided path '#{data_path}' is not a directory"
|
31
|
+
end
|
32
|
+
|
33
|
+
def output_results(results, output)
|
34
|
+
if output&.end_with?('json')
|
35
|
+
oo = FhirEvaluator::EvaluationResult.to_operation_outcome(results)
|
36
|
+
File.write(output, oo.to_json)
|
37
|
+
puts "Results written to #{output}"
|
38
|
+
else
|
39
|
+
counts = results.group_by(&:severity).transform_values(&:count)
|
40
|
+
print(counts, 'Result Count')
|
41
|
+
puts "\n"
|
42
|
+
puts results
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def print(output_fields, title)
|
47
|
+
puts("╔══════════════ #{title} ═══════════════╗")
|
48
|
+
puts('║ ╭────────────────┬──────────────────────╮ ║')
|
49
|
+
output_fields.each_with_index do |(key, value), i|
|
50
|
+
field_name = pad(key, 14)
|
51
|
+
field_value = pad(value.to_s, 20)
|
52
|
+
puts("║ │ #{field_name} │ #{field_value} │ ║")
|
53
|
+
puts('║ ├────────────────┼──────────────────────┤ ║') unless i == output_fields.length - 1
|
54
|
+
end
|
55
|
+
puts('║ ╰────────────────┴──────────────────────╯ ║')
|
56
|
+
puts('╚═══════════════════════════════════════════╝')
|
57
|
+
end
|
58
|
+
|
59
|
+
def pad(string, length)
|
60
|
+
format("%#{length}.#{length}s", string)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require_relative 'console'
|
2
|
+
require_relative 'evaluate'
|
2
3
|
require_relative 'migration'
|
3
4
|
require_relative 'services'
|
4
5
|
require_relative 'suite'
|
@@ -10,6 +11,43 @@ require_relative 'execute'
|
|
10
11
|
module Inferno
|
11
12
|
module CLI
|
12
13
|
class Main < Thor
|
14
|
+
desc 'evaluate', 'Run a FHIR Data Evaluator.'
|
15
|
+
long_desc <<-LONGDESC
|
16
|
+
Evaluate FHIR data in the context of a given Implementation Guide,
|
17
|
+
by applying a set of predefined rules designed to check that datasets are comprehensive.
|
18
|
+
Issues identified will be printed to console or to a json file.
|
19
|
+
|
20
|
+
You must have background services running: `bundle exec inferno services start`
|
21
|
+
|
22
|
+
Run the evaluation CLI with
|
23
|
+
|
24
|
+
`bundle exec inferno evaluate ig_path`
|
25
|
+
|
26
|
+
Examples:
|
27
|
+
|
28
|
+
# Load the us core ig and evaluate the data in the provided example folder. If there are examples in the IG already, they will be ignored.
|
29
|
+
`bundle exec inferno evaluate ./uscore.tgz -d ./package/example`
|
30
|
+
|
31
|
+
# Loads the us core ig and evaluate the data included in the IG's example folder
|
32
|
+
`bundle exec inferno evaluate ./uscore.tgz`
|
33
|
+
|
34
|
+
# Loads the us core ig and evaluate the data included in the IG's example folder, with results redirected to outcome.json as an OperationOutcome
|
35
|
+
`bundle exec inferno evaluate ./uscore.tgz --output outcome.json`
|
36
|
+
LONGDESC
|
37
|
+
# TODO: Add options below as arguments
|
38
|
+
option :data_path,
|
39
|
+
aliases: ['-d'],
|
40
|
+
type: :string,
|
41
|
+
desc: 'Example FHIR data path'
|
42
|
+
# TODO: implement option of exporting result as OperationOutcome
|
43
|
+
option :output,
|
44
|
+
aliases: ['-o'],
|
45
|
+
type: :string,
|
46
|
+
desc: 'Export evaluation result to outcome.json as an OperationOutcome'
|
47
|
+
def evaluate(ig_path)
|
48
|
+
Evaluate.new.run(ig_path, options[:data_path], Logger::INFO)
|
49
|
+
end
|
50
|
+
|
13
51
|
desc 'console', 'Start an interactive console session with Inferno'
|
14
52
|
def console
|
15
53
|
Migration.new.run(Logger::INFO)
|
@@ -1,11 +1,15 @@
|
|
1
|
+
require_relative 'lib/<%= library_name %>/version'
|
2
|
+
|
1
3
|
Gem::Specification.new do |spec|
|
2
4
|
spec.name = '<%= library_name %>'
|
3
|
-
spec.version =
|
5
|
+
spec.version = <%= module_name %>::VERSION
|
4
6
|
spec.authors = <%= authors %>
|
5
7
|
# spec.email = ['TODO']
|
6
8
|
spec.date = Time.now.utc.strftime('%Y-%m-%d')
|
7
|
-
spec.summary = '<%= title_name %>
|
8
|
-
spec.description =
|
9
|
+
spec.summary = '<%= title_name %>'
|
10
|
+
# spec.description = <<~DESCRIPTION
|
11
|
+
# This is a big markdown description of the test kit.
|
12
|
+
# DESCRIPTION
|
9
13
|
# spec.homepage = 'TODO'
|
10
14
|
spec.license = 'Apache-2.0'
|
11
15
|
spec.add_runtime_dependency 'inferno_core', '~> <%= Inferno::VERSION %>'
|
@@ -14,11 +18,14 @@ Gem::Specification.new do |spec|
|
|
14
18
|
spec.add_development_dependency 'rspec', '~> 3.10'
|
15
19
|
spec.add_development_dependency 'webmock', '~> 3.11'
|
16
20
|
spec.required_ruby_version = Gem::Requirement.new('>= 3.1.2')
|
21
|
+
spec.metadata['inferno_test_kit'] = 'true'
|
17
22
|
# spec.metadata['homepage_uri'] = spec.homepage
|
18
23
|
# spec.metadata['source_code_uri'] = 'TODO'
|
19
24
|
spec.files = [
|
20
25
|
Dir['lib/**/*.rb'],
|
21
26
|
Dir['lib/**/*.json'],
|
27
|
+
Dir['config/presets/*.json'],
|
28
|
+
Dir['config/presets/*.json.erb'],
|
22
29
|
'LICENSE'
|
23
30
|
].flatten
|
24
31
|
|
@@ -6,12 +6,13 @@ RUN mkdir -p $INSTALL_PATH
|
|
6
6
|
|
7
7
|
WORKDIR $INSTALL_PATH
|
8
8
|
|
9
|
+
ADD lib/<%= library_name %>/metadata.rb $INSTALL_PATH/lib/<%= library_name %>/metadata.rb
|
9
10
|
ADD *.gemspec $INSTALL_PATH
|
10
11
|
ADD Gemfile* $INSTALL_PATH
|
11
12
|
RUN gem install bundler
|
12
|
-
# The below RUN line is commented out for development purposes, because any change to the
|
13
|
+
# The below RUN line is commented out for development purposes, because any change to the
|
13
14
|
# required gems will break the dockerfile build process.
|
14
|
-
# If you want to run in Deploy mode, just run `bundle install` locally to update
|
15
|
+
# If you want to run in Deploy mode, just run `bundle install` locally to update
|
15
16
|
# Gemfile.lock, and uncomment the following line.
|
16
17
|
# RUN bundle config set --local deployment 'true'
|
17
18
|
RUN bundle install
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative 'version'
|
2
|
+
|
3
|
+
module <%= module_name %>
|
4
|
+
class Metadata < Inferno::TestKit
|
5
|
+
id :<%= test_kit_id %>
|
6
|
+
title '<%= title_name %>'
|
7
|
+
description <<~DESCRIPTION
|
8
|
+
This is a big markdown description of the test kit.
|
9
|
+
DESCRIPTION
|
10
|
+
suite_ids [:<%= test_suite_id %>]
|
11
|
+
# tags ['SMART App Launch', 'US Core']
|
12
|
+
# last_updated '2024-03-07'
|
13
|
+
version VERSION
|
14
|
+
maturity 'Low'
|
15
|
+
authors <%= authors %>
|
16
|
+
# repo 'TODO'
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require_relative 'metadata'
|
2
|
+
require_relative 'patient_group'
|
3
|
+
|
4
|
+
module <%= module_name %>
|
5
|
+
class Suite < Inferno::TestSuite
|
6
|
+
id :<%= test_suite_id %>
|
7
|
+
title '<%= title_name %> Test Suite'
|
8
|
+
description '<%= human_name %> test suite.'
|
9
|
+
|
10
|
+
# These inputs will be available to all tests in this suite
|
11
|
+
input :url,
|
12
|
+
title: 'FHIR Server Base Url'
|
13
|
+
|
14
|
+
input :credentials,
|
15
|
+
title: 'OAuth Credentials',
|
16
|
+
type: :oauth_credentials,
|
17
|
+
optional: true
|
18
|
+
|
19
|
+
# All FHIR requests in this suite will use this FHIR client
|
20
|
+
fhir_client do
|
21
|
+
url :url
|
22
|
+
oauth_credentials :credentials
|
23
|
+
end
|
24
|
+
|
25
|
+
# All FHIR validation requests will use this FHIR validator
|
26
|
+
fhir_resource_validator do
|
27
|
+
# igs 'identifier#version' # Use this method for published IGs/versions
|
28
|
+
# igs 'igs/filename.tgz' # Use this otherwise
|
29
|
+
|
30
|
+
exclude_message do |message|
|
31
|
+
message.message.match?(/\A\S+: \S+: URL value '.*' does not resolve/)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Tests and TestGroups can be defined inline
|
36
|
+
group do
|
37
|
+
id :capability_statement
|
38
|
+
title 'Capability Statement'
|
39
|
+
description 'Verify that the server has a CapabilityStatement'
|
40
|
+
|
41
|
+
test do
|
42
|
+
id :capability_statement_read
|
43
|
+
title 'Read CapabilityStatement'
|
44
|
+
description 'Read CapabilityStatement from /metadata endpoint'
|
45
|
+
|
46
|
+
run do
|
47
|
+
fhir_get_capability_statement
|
48
|
+
|
49
|
+
assert_response_status(200)
|
50
|
+
assert_resource_type(:capability_statement)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Tests and TestGroups can be written in separate files and then included
|
56
|
+
# using their id
|
57
|
+
group from: :patient_group
|
58
|
+
end
|
59
|
+
end
|
@@ -1,58 +1 @@
|
|
1
|
-
require_relative '<%= library_name %>/
|
2
|
-
|
3
|
-
module <%= module_name %>
|
4
|
-
class Suite < Inferno::TestSuite
|
5
|
-
id :<%= test_suite_id %>
|
6
|
-
title '<%= title_name %> Test Suite'
|
7
|
-
description '<%= human_name %> test suite.'
|
8
|
-
|
9
|
-
# These inputs will be available to all tests in this suite
|
10
|
-
input :url,
|
11
|
-
title: 'FHIR Server Base Url'
|
12
|
-
|
13
|
-
input :credentials,
|
14
|
-
title: 'OAuth Credentials',
|
15
|
-
type: :oauth_credentials,
|
16
|
-
optional: true
|
17
|
-
|
18
|
-
# All FHIR requests in this suite will use this FHIR client
|
19
|
-
fhir_client do
|
20
|
-
url :url
|
21
|
-
oauth_credentials :credentials
|
22
|
-
end
|
23
|
-
|
24
|
-
# All FHIR validation requests will use this FHIR validator
|
25
|
-
fhir_resource_validator do
|
26
|
-
# igs 'identifier#version' # Use this method for published IGs/versions
|
27
|
-
# igs 'igs/filename.tgz' # Use this otherwise
|
28
|
-
|
29
|
-
exclude_message do |message|
|
30
|
-
message.message.match?(/\A\S+: \S+: URL value '.*' does not resolve/)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
# Tests and TestGroups can be defined inline
|
35
|
-
group do
|
36
|
-
id :capability_statement
|
37
|
-
title 'Capability Statement'
|
38
|
-
description 'Verify that the server has a CapabilityStatement'
|
39
|
-
|
40
|
-
test do
|
41
|
-
id :capability_statement_read
|
42
|
-
title 'Read CapabilityStatement'
|
43
|
-
description 'Read CapabilityStatement from /metadata endpoint'
|
44
|
-
|
45
|
-
run do
|
46
|
-
fhir_get_capability_statement
|
47
|
-
|
48
|
-
assert_response_status(200)
|
49
|
-
assert_resource_type(:capability_statement)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
# Tests and TestGroups can be written in separate files and then included
|
55
|
-
# using their id
|
56
|
-
group from: :patient_group
|
57
|
-
end
|
58
|
-
end
|
1
|
+
require_relative '<%= library_name %>/suite'
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require_relative 'markdown_extractor'
|
1
2
|
require_relative 'serializer'
|
2
3
|
|
3
4
|
module Inferno
|
@@ -7,7 +8,7 @@ module Inferno
|
|
7
8
|
identifier :name
|
8
9
|
|
9
10
|
field :title, if: :field_present?
|
10
|
-
field :description, if: :field_present?
|
11
|
+
field :description, extractor: MarkdownExtractor, if: :field_present?
|
11
12
|
field :type, if: :field_present?
|
12
13
|
field :default, if: :field_present?
|
13
14
|
field :optional, if: :field_present?
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'blueprinter'
|
2
|
+
require_relative '../../../utils/markdown_formatter'
|
3
|
+
|
4
|
+
module Inferno
|
5
|
+
module Web
|
6
|
+
module Serializers
|
7
|
+
class MarkdownExtractor < Blueprinter::Extractor
|
8
|
+
include Inferno::Utils::MarkdownFormatter
|
9
|
+
|
10
|
+
def extract(field_name, object, _local_options, _options = {})
|
11
|
+
format_markdown(object.send(field_name))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -4,9 +4,26 @@ Inferno::Application.register_provider(:presets) do
|
|
4
4
|
prepare do
|
5
5
|
target_container.start :suites
|
6
6
|
|
7
|
+
presets_repo = Inferno::Repositories::Presets.new
|
8
|
+
|
9
|
+
test_kit_gems =
|
10
|
+
Bundler
|
11
|
+
.definition
|
12
|
+
.specs
|
13
|
+
.select { |spec| spec.metadata.fetch('inferno_test_kit', 'false').casecmp? 'true' }
|
14
|
+
|
7
15
|
files_to_load = Dir.glob(['config/presets/*.json', 'config/presets/*.json.erb'])
|
16
|
+
files_to_load +=
|
17
|
+
test_kit_gems.flat_map do |gem|
|
18
|
+
[
|
19
|
+
Dir.glob([File.join(gem.full_gem_path, 'config', 'presets', '*.json')]),
|
20
|
+
Dir.glob([File.join(gem.full_gem_path, 'config', 'presets', '*.json.erb')])
|
21
|
+
].flatten
|
22
|
+
end
|
23
|
+
|
24
|
+
files_to_load.compact!
|
25
|
+
files_to_load.uniq!
|
8
26
|
files_to_load.map! { |path| File.realpath(path) }
|
9
|
-
presets_repo = Inferno::Repositories::Presets.new
|
10
27
|
|
11
28
|
files_to_load.each do |path|
|
12
29
|
presets_repo.insert_from_file(path)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Inferno
|
2
|
+
module DSL
|
3
|
+
module FHIREvaluation
|
4
|
+
class Config
|
5
|
+
DEFAULT_FILE = File.join(__dir__, 'default.yml')
|
6
|
+
attr_accessor :data
|
7
|
+
|
8
|
+
# To-do: add config_file as arguments
|
9
|
+
def initialize(config_file = nil)
|
10
|
+
@data = if config_file.nil?
|
11
|
+
YAML.load_file(File.absolute_path(DEFAULT_FILE))
|
12
|
+
else
|
13
|
+
YAML.load_file(File.absolute_path(config_file))
|
14
|
+
end
|
15
|
+
|
16
|
+
raise(TypeError, 'Malformed configuration') unless @data.is_a?(Hash)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Inferno
|
2
|
+
module DSL
|
3
|
+
module FHIREvaluation
|
4
|
+
module DatasetLoader
|
5
|
+
def self.from_contents(source_array)
|
6
|
+
dataset = []
|
7
|
+
|
8
|
+
source_array.each do |json|
|
9
|
+
resource = FHIR::Json.from_json(json)
|
10
|
+
next if resource.nil?
|
11
|
+
|
12
|
+
dataset.push resource
|
13
|
+
end
|
14
|
+
|
15
|
+
dataset
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.from_path(path)
|
19
|
+
dataset = []
|
20
|
+
|
21
|
+
Dir["#{path}/*.json"].each do |f|
|
22
|
+
resource = FHIR::Json.from_json(File.read(f))
|
23
|
+
next if resource.nil?
|
24
|
+
|
25
|
+
dataset.push resource
|
26
|
+
end
|
27
|
+
|
28
|
+
dataset
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Inferno
|
2
|
+
module DSL
|
3
|
+
module FHIREvaluation
|
4
|
+
# EvaluationContext is a wrapper class around the concepts needed to perform an evaluation:
|
5
|
+
# - The IG used as the basis for evaluation
|
6
|
+
# - The data being evaluated
|
7
|
+
# - A summary/characterization of the data
|
8
|
+
# - Evaluation results
|
9
|
+
class EvaluationContext
|
10
|
+
attr_reader :ig, :data, :results, :config
|
11
|
+
|
12
|
+
def initialize(ig, data, config) # rubocop:disable Naming/MethodParameterName
|
13
|
+
@ig = ig
|
14
|
+
@data = data
|
15
|
+
@results = []
|
16
|
+
@config = config
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_result(result)
|
20
|
+
results.push result
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Inferno
|
2
|
+
module DSL
|
3
|
+
module FHIREvaluation
|
4
|
+
# The result of a Rule evaluating a data set.
|
5
|
+
class EvaluationResult
|
6
|
+
attr_accessor :message,
|
7
|
+
:severity, # fatal | error | warning | information | success
|
8
|
+
:issue_type, # https://www.hl7.org/fhir/valueset-issue-type.html
|
9
|
+
:threshold, # quantitative value that a rule checks for
|
10
|
+
:value, # actual observed value
|
11
|
+
:rule # Rule that produced this result
|
12
|
+
|
13
|
+
def initialize(message, severity: 'warning', issue_type: 'business-rule', threshold: nil, value: nil, rule: nil)
|
14
|
+
@message = message
|
15
|
+
@severity = severity
|
16
|
+
@issue_type = issue_type
|
17
|
+
@threshold = threshold
|
18
|
+
@value = value
|
19
|
+
@rule = rule
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
"#{severity.upcase}: #{message}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_oo_issue
|
27
|
+
issue = {
|
28
|
+
severity:,
|
29
|
+
code: issue_type,
|
30
|
+
details: { text: message }
|
31
|
+
}
|
32
|
+
|
33
|
+
if threshold
|
34
|
+
issue[:extension] ||= []
|
35
|
+
issue[:extension].push({
|
36
|
+
# TODO: pick real extension for this
|
37
|
+
url: 'https://inferno-framework.github.io/fhir_evaluator/StructureDefinition/operationoutcome-issue-threshold',
|
38
|
+
valueDecimal: threshold
|
39
|
+
})
|
40
|
+
end
|
41
|
+
|
42
|
+
if value
|
43
|
+
issue[:extension] ||= []
|
44
|
+
issue[:extension].push({
|
45
|
+
# TODO: pick real extension for this
|
46
|
+
url: 'https://inferno-framework.github.io/fhir_evaluator/StructureDefinition/operationoutcome-issue-value',
|
47
|
+
valueDecimal: value
|
48
|
+
})
|
49
|
+
end
|
50
|
+
|
51
|
+
issue
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.to_operation_outcome(results)
|
55
|
+
FHIR::OperationOutcome.new({
|
56
|
+
issue: results.map(&:to_oo_issue)
|
57
|
+
})
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'config'
|
4
|
+
require_relative 'rule'
|
5
|
+
require_relative 'evaluation_context'
|
6
|
+
require_relative 'evaluation_result'
|
7
|
+
require_relative 'dataset_loader'
|
8
|
+
|
9
|
+
module Inferno
|
10
|
+
module DSL
|
11
|
+
module FHIREvaluation
|
12
|
+
class Evaluator
|
13
|
+
attr_accessor :ig
|
14
|
+
|
15
|
+
def initialize(ig) # rubocop:disable Naming/MethodParameterName
|
16
|
+
@ig = ig
|
17
|
+
end
|
18
|
+
|
19
|
+
def evaluate(data, config = Config.new)
|
20
|
+
context = EvaluationContext.new(@ig, data, config)
|
21
|
+
|
22
|
+
active_rules = []
|
23
|
+
config.data['Rule'].each do |rulename, rule_details|
|
24
|
+
active_rules << rulename if rule_details['Enabled']
|
25
|
+
end
|
26
|
+
|
27
|
+
Rule.descendants.each do |rule|
|
28
|
+
rule.new.check(context) if active_rules.include?(rule.name.demodulize)
|
29
|
+
end
|
30
|
+
|
31
|
+
context.results
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|