inferno_core 0.5.1 → 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/execute.rb +49 -4
- data/lib/inferno/apps/cli/main.rb +48 -2
- 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/application.rb +4 -0
- data/lib/inferno/apps/web/index.html.erb +12 -4
- 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/executor.rb +1 -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/ext/json_parser.rb +11 -0
- 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 -2
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
|
@@ -44,10 +44,12 @@ module Inferno
|
|
44
44
|
|
45
45
|
self.options = options
|
46
46
|
|
47
|
-
outputter.print_start_message(options)
|
47
|
+
outputter.print_start_message(self.options)
|
48
|
+
|
49
|
+
load_preset_file_and_set_preset_id
|
48
50
|
|
49
51
|
results = []
|
50
|
-
outputter.print_around_run(options) do
|
52
|
+
outputter.print_around_run(self.options) do
|
51
53
|
if all_selected_groups_and_tests.empty?
|
52
54
|
test_run = create_test_run(suite)
|
53
55
|
run_one(suite, test_run)
|
@@ -102,6 +104,18 @@ module Inferno
|
|
102
104
|
@outputter ||= OUTPUTTERS[options[:outputter]].new
|
103
105
|
end
|
104
106
|
|
107
|
+
def load_preset_file_and_set_preset_id
|
108
|
+
return unless options[:preset_file]
|
109
|
+
raise StandardError, 'Cannot use `--preset-id` and `--preset-file` options together' if options[:preset_id]
|
110
|
+
|
111
|
+
raise StandardError, "File #{options[:preset_file]} not found" unless File.exist? options[:preset_file]
|
112
|
+
|
113
|
+
options[:preset_id] = JSON.parse(File.read(options[:preset_file]))['id']
|
114
|
+
raise StandardError, "Preset #{options[:preset_file]} is missing id" if options[:preset_id].nil?
|
115
|
+
|
116
|
+
presets_repo.insert_from_file(options[:preset_file])
|
117
|
+
end
|
118
|
+
|
105
119
|
def all_selected_groups_and_tests
|
106
120
|
@all_selected_groups_and_tests ||= runnables_by_short_id + groups + tests
|
107
121
|
end
|
@@ -109,7 +123,7 @@ module Inferno
|
|
109
123
|
def run_one(runnable, test_run)
|
110
124
|
verify_runnable(
|
111
125
|
runnable,
|
112
|
-
thor_hash_to_inputs_array(
|
126
|
+
thor_hash_to_inputs_array(inputs_and_preset),
|
113
127
|
test_session.suite_options
|
114
128
|
)
|
115
129
|
|
@@ -118,6 +132,33 @@ module Inferno
|
|
118
132
|
dispatch_job(test_run)
|
119
133
|
end
|
120
134
|
|
135
|
+
def inputs_and_preset
|
136
|
+
if preset
|
137
|
+
preset_inputs = preset.inputs.to_h do |preset_input|
|
138
|
+
[preset_input[:name], preset_input[:value]]
|
139
|
+
end
|
140
|
+
|
141
|
+
options.fetch(:inputs, {}).reverse_merge(preset_inputs)
|
142
|
+
else
|
143
|
+
options.fetch(:inputs, {})
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def preset
|
148
|
+
return unless options[:preset_id]
|
149
|
+
|
150
|
+
@preset ||= presets_repo.find(options[:preset_id])
|
151
|
+
|
152
|
+
raise StandardError, "Preset #{options[:preset_id]} not found" if @preset.nil?
|
153
|
+
|
154
|
+
unless presets_repo.presets_for_suite(suite.id).include?(@preset)
|
155
|
+
raise StandardError,
|
156
|
+
"Preset #{options[:preset_id]} is incompatible with suite #{suite.id}"
|
157
|
+
end
|
158
|
+
|
159
|
+
@preset
|
160
|
+
end
|
161
|
+
|
121
162
|
def suite
|
122
163
|
@suite ||= Inferno::Repositories::TestSuites.new.find(options[:suite])
|
123
164
|
|
@@ -156,6 +197,10 @@ module Inferno
|
|
156
197
|
@session_data_repo ||= Inferno::Repositories::SessionData.new
|
157
198
|
end
|
158
199
|
|
200
|
+
def presets_repo
|
201
|
+
@presets_repo ||= Inferno::Repositories::Presets.new
|
202
|
+
end
|
203
|
+
|
159
204
|
def test_session
|
160
205
|
@test_session ||= test_sessions_repo.create({
|
161
206
|
test_suite_id: suite.id,
|
@@ -169,7 +214,7 @@ module Inferno
|
|
169
214
|
{
|
170
215
|
test_session_id: test_session.id,
|
171
216
|
runnable_id_key(runnable) => runnable.id,
|
172
|
-
inputs: thor_hash_to_inputs_array(
|
217
|
+
inputs: thor_hash_to_inputs_array(inputs_and_preset)
|
173
218
|
}
|
174
219
|
end
|
175
220
|
|
@@ -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)
|
@@ -125,7 +163,15 @@ module Inferno
|
|
125
163
|
option :inputs,
|
126
164
|
aliases: ['-i'],
|
127
165
|
type: :hash,
|
128
|
-
desc: 'Inputs (i.e: --inputs=foo:bar goo:baz)'
|
166
|
+
desc: 'Inputs (i.e: --inputs=foo:bar goo:baz); will merge and override preset inputs'
|
167
|
+
option :preset_id,
|
168
|
+
aliases: ['-P'],
|
169
|
+
type: :string,
|
170
|
+
desc: 'Inferno preset id; cannot be used with `--preset-file`'
|
171
|
+
option :preset_file,
|
172
|
+
aliases: ['-p'],
|
173
|
+
type: :string,
|
174
|
+
desc: 'Path to an Inferno preset file for inputs; cannot be used with `--preset-id`'
|
129
175
|
option :outputter,
|
130
176
|
aliases: ['-o'],
|
131
177
|
default: 'console',
|
@@ -142,7 +188,7 @@ module Inferno
|
|
142
188
|
desc: 'Display this message'
|
143
189
|
def execute
|
144
190
|
Execute.boot_full_inferno
|
145
|
-
Execute.new.run(options)
|
191
|
+
Execute.new.run(options.dup) # dup to unfreeze Thor options
|
146
192
|
end
|
147
193
|
|
148
194
|
# https://github.com/rails/thor/issues/244 - Make Thor exit(1) on Errors/Exceptions
|
@@ -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,6 +1,10 @@
|
|
1
1
|
require 'hanami/middleware/body_parser'
|
2
2
|
require_relative 'router'
|
3
3
|
|
4
|
+
# Only required to monkey patch the JSON parser to support application/fhir+json
|
5
|
+
require 'hanami/middleware/body_parser/json_parser'
|
6
|
+
require_relative '../../ext/json_parser'
|
7
|
+
|
4
8
|
module Inferno
|
5
9
|
module Web
|
6
10
|
def self.app
|
@@ -9,10 +9,18 @@
|
|
9
9
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
10
10
|
<meta name="theme-color" content="#000000" />
|
11
11
|
<meta id="base-path" name="base-path" content="<%= Inferno::Application['base_path'] %>">
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
/>
|
12
|
+
|
13
|
+
<!-- Social media link unfurling meta tags -->
|
14
|
+
<title>Inferno Test Session</title>
|
15
|
+
<link rel="canonical" href="<%= Inferno::Application['base_url'] %>" />
|
16
|
+
<meta name="application-name" content="Inferno" />
|
17
|
+
<meta name="og:image" content="<%= Inferno::Application['inferno_host'] %><%= Inferno::Application['public_path'] %>/logo192.png" />
|
18
|
+
<meta name="og:type" content="website" />
|
19
|
+
<meta name="og:url" content="<%= Inferno::Application['base_url'] %>" />
|
20
|
+
<meta name="og:site_name" content="Inferno" />
|
21
|
+
<meta name="twitter:card" content="summary" />
|
22
|
+
<meta name="twitter:image" content="<%= Inferno::Application['inferno_host'] %><%= Inferno::Application['public_path'] %>/logo192.png" />
|
23
|
+
|
16
24
|
<link rel="apple-touch-icon" href="<%= Inferno::Application['public_path'] %>/logo192.png" />
|
17
25
|
<!--
|
18
26
|
manifest.json provides metadata used when your web app is installed on a
|
@@ -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
|
@@ -9,54 +9,54 @@ module Inferno
|
|
9
9
|
# endpoint](https://github.com/hanami/controller/tree/v2.0.0).
|
10
10
|
#
|
11
11
|
# @example
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
12
|
+
# class AuthorizedEndpoint < Inferno::DSL::SuiteEndpoint
|
13
|
+
# # Identify the incoming request based on a bearer token
|
14
|
+
# def test_run_identifier
|
15
|
+
# request.header['authorization']&.delete_prefix('Bearer ')
|
16
|
+
# end
|
17
17
|
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
18
|
+
# # Return a json FHIR Patient resource
|
19
|
+
# def make_response
|
20
|
+
# response.status = 200
|
21
|
+
# response.body = FHIR::Patient.new(id: 'abcdef').to_json
|
22
|
+
# response.format = :json
|
23
|
+
# end
|
24
24
|
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
25
|
+
# # Update the waiting test to pass when the incoming request is received.
|
26
|
+
# # This will resume the test run.
|
27
|
+
# def update_result
|
28
|
+
# results_repo.update(result.id, result: 'pass')
|
29
|
+
# end
|
30
30
|
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
31
|
+
# # Apply the 'authorized' tag to the incoming request so that it may be
|
32
|
+
# # used by later tests.
|
33
|
+
# def tags
|
34
|
+
# ['authorized']
|
35
|
+
# end
|
36
|
+
# end
|
37
37
|
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
38
|
+
# class AuthorizedRequestSuite < Inferno::TestSuite
|
39
|
+
# id :authorized_suite
|
40
|
+
# suite_endpoint :get, '/authorized_endpoint', AuthorizedEndpoint
|
41
41
|
#
|
42
|
-
#
|
43
|
-
#
|
42
|
+
# group do
|
43
|
+
# title 'Authorized Request Group'
|
44
44
|
#
|
45
|
-
#
|
46
|
-
#
|
45
|
+
# test do
|
46
|
+
# title 'Wait for authorized request'
|
47
47
|
#
|
48
|
-
#
|
48
|
+
# input :bearer_token
|
49
49
|
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
#
|
50
|
+
# run do
|
51
|
+
# wait(
|
52
|
+
# identifier: bearer_token,
|
53
|
+
# message: "Waiting to receive a request with bearer_token: #{bearer_token}" \
|
54
|
+
# "at `#{Inferno::Application['base_url']}/custom/authorized_suite/authorized_endpoint`"
|
55
|
+
# )
|
56
|
+
# end
|
57
|
+
# end
|
56
58
|
# end
|
57
59
|
# end
|
58
|
-
# end
|
59
|
-
# end
|
60
60
|
class SuiteEndpoint < Hanami::Action
|
61
61
|
attr_reader :req, :res
|
62
62
|
|
@@ -69,11 +69,11 @@ module Inferno
|
|
69
69
|
# @return [String]
|
70
70
|
#
|
71
71
|
# @example
|
72
|
-
#
|
73
|
-
#
|
74
|
-
#
|
75
|
-
#
|
76
|
-
#
|
72
|
+
# def test_run_identifier
|
73
|
+
# # Identify the test session of an incoming request based on the bearer
|
74
|
+
# # token
|
75
|
+
# request.headers['authorization']&.delete_prefix('Bearer ')
|
76
|
+
# end
|
77
77
|
def test_run_identifier
|
78
78
|
nil
|
79
79
|
end
|
@@ -83,11 +83,11 @@ module Inferno
|
|
83
83
|
# @return [Void]
|
84
84
|
#
|
85
85
|
# @example
|
86
|
-
#
|
87
|
-
#
|
88
|
-
#
|
89
|
-
#
|
90
|
-
#
|
86
|
+
# def make_response
|
87
|
+
# response.status = 200
|
88
|
+
# response.body = { abc: 123 }.to_json
|
89
|
+
# response.format = :json
|
90
|
+
# end
|
91
91
|
def make_response
|
92
92
|
nil
|
93
93
|
end
|
@@ -113,9 +113,9 @@ module Inferno
|
|
113
113
|
# @return [Void]
|
114
114
|
#
|
115
115
|
# @example
|
116
|
-
#
|
117
|
-
#
|
118
|
-
#
|
116
|
+
# def update_result
|
117
|
+
# results_repo.update(result.id, result: 'pass')
|
118
|
+
# end
|
119
119
|
def update_result
|
120
120
|
nil
|
121
121
|
end
|
@@ -165,9 +165,9 @@ module Inferno
|
|
165
165
|
# @return [Hanami::Action::Request]
|
166
166
|
#
|
167
167
|
# @example
|
168
|
-
#
|
169
|
-
#
|
170
|
-
#
|
168
|
+
# request.params # Get url/query params
|
169
|
+
# request.body.read # Get body
|
170
|
+
# request.headers['accept'] # Get Accept header
|
171
171
|
def request
|
172
172
|
req
|
173
173
|
end
|
@@ -178,10 +178,10 @@ module Inferno
|
|
178
178
|
# @return [Hanami::Action::Response]
|
179
179
|
#
|
180
180
|
# @example
|
181
|
-
#
|
182
|
-
#
|
183
|
-
#
|
184
|
-
#
|
181
|
+
# response.status = 200 # Set the status
|
182
|
+
# response.body = 'Ok' # Set the body
|
183
|
+
# # Set headers
|
184
|
+
# response.headers.merge!('X-Custom-Header' => 'CUSTOM_HEADER_VALUE')
|
185
185
|
def response
|
186
186
|
res
|
187
187
|
end
|
data/lib/inferno/dsl.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require_relative 'dsl/assertions'
|
2
2
|
require_relative 'dsl/fhir_client'
|
3
3
|
require_relative 'dsl/fhir_validation'
|
4
|
+
require_relative 'dsl/fhir_evaluation/evaluator'
|
4
5
|
require_relative 'dsl/fhir_resource_validation'
|
5
6
|
require_relative 'dsl/fhirpath_evaluation'
|
6
7
|
require_relative 'dsl/http_client'
|
@@ -18,6 +19,7 @@ module Inferno
|
|
18
19
|
HTTPClient,
|
19
20
|
Results,
|
20
21
|
FHIRValidation,
|
22
|
+
FHIREvaluation,
|
21
23
|
FHIRResourceValidation,
|
22
24
|
FhirpathEvaluation,
|
23
25
|
Messages
|
@@ -6,7 +6,7 @@ module Inferno
|
|
6
6
|
# @example
|
7
7
|
#
|
8
8
|
# module USCoreTestKit
|
9
|
-
# class
|
9
|
+
# class Metadata < Inferno::Entities::TestKit
|
10
10
|
# id :us_core
|
11
11
|
# title 'US Core Test Kit'
|
12
12
|
# description <<~DESCRIPTION
|
@@ -156,7 +156,7 @@ module Inferno
|
|
156
156
|
|
157
157
|
# @private
|
158
158
|
def repository
|
159
|
-
@repository ||= Inferno::Repositories::TestKits
|
159
|
+
@repository ||= Inferno::Repositories::TestKits.new
|
160
160
|
end
|
161
161
|
|
162
162
|
# @private
|
@@ -168,4 +168,6 @@ module Inferno
|
|
168
168
|
end
|
169
169
|
end
|
170
170
|
end
|
171
|
+
|
172
|
+
TestKit = Entities::TestKit
|
171
173
|
end
|
@@ -84,15 +84,16 @@ module Inferno
|
|
84
84
|
}
|
85
85
|
end
|
86
86
|
|
87
|
-
# Set/get the version of this test suite.
|
87
|
+
# Set/get the version of this test suite. Defaults to the TestKit
|
88
|
+
# version.
|
88
89
|
#
|
89
90
|
# @param version [String]
|
90
91
|
#
|
91
92
|
# @return [String, nil]
|
92
93
|
def version(version = nil)
|
93
|
-
|
94
|
+
@version = version if version.present?
|
94
95
|
|
95
|
-
@version
|
96
|
+
@version || test_kit&.version
|
96
97
|
end
|
97
98
|
|
98
99
|
# @private
|
@@ -186,6 +187,25 @@ module Inferno
|
|
186
187
|
|
187
188
|
@suite_summary = format_markdown(suite_summary)
|
188
189
|
end
|
190
|
+
|
191
|
+
# Get the TestKit this suite belongs to
|
192
|
+
#
|
193
|
+
# @return [Inferno::Entities::TestKit]
|
194
|
+
def test_kit
|
195
|
+
return @test_kit if @test_kit
|
196
|
+
|
197
|
+
module_name = name
|
198
|
+
|
199
|
+
while module_name.present? && @test_kit.nil?
|
200
|
+
module_name = module_name.deconstantize
|
201
|
+
|
202
|
+
next unless const_defined?("#{module_name}::Metadata")
|
203
|
+
|
204
|
+
@test_kit = const_get("#{module_name}::Metadata")
|
205
|
+
end
|
206
|
+
|
207
|
+
@test_kit
|
208
|
+
end
|
189
209
|
end
|
190
210
|
end
|
191
211
|
end
|
data/lib/inferno/entities.rb
CHANGED
@@ -8,6 +8,7 @@ require_relative 'entities/result'
|
|
8
8
|
require_relative 'entities/session_data'
|
9
9
|
require_relative 'entities/test'
|
10
10
|
require_relative 'entities/test_group'
|
11
|
+
require_relative 'entities/test_kit'
|
11
12
|
require_relative 'entities/test_run'
|
12
13
|
require_relative 'entities/test_session'
|
13
14
|
require_relative 'entities/test_suite'
|
@@ -8,14 +8,20 @@ module Inferno
|
|
8
8
|
# Repository that deals with persistence for the `Preset` entity.
|
9
9
|
class Presets < InMemoryRepository
|
10
10
|
def insert_from_file(path)
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
11
|
+
raw_contents =
|
12
|
+
case path
|
13
|
+
when /\.json$/
|
14
|
+
File.read(path)
|
15
|
+
when /\.erb$/
|
16
|
+
ERB.new(File.read(path)).result
|
17
|
+
end
|
18
|
+
|
19
|
+
if Application['base_url'].start_with? 'https://inferno-qa.healthit.gov'
|
20
|
+
raw_contents.gsub!('https://inferno.healthit.gov', 'https://inferno-qa.healthit.gov')
|
17
21
|
end
|
18
22
|
|
23
|
+
preset_hash = JSON.parse(raw_contents)
|
24
|
+
|
19
25
|
preset_hash.deep_symbolize_keys!
|
20
26
|
preset_hash[:id] ||= SecureRandom.uuid
|
21
27
|
preset = Entities::Preset.new(preset_hash)
|
@@ -12,6 +12,8 @@ module Inferno
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def summarize
|
15
|
+
return 'wait' if results.any? { |result| result.result == 'wait' }
|
16
|
+
|
15
17
|
return 'pass' if optional_results_passing_criteria_met?
|
16
18
|
|
17
19
|
prioritized_result_strings.find { |result_string| unique_result_strings.include? result_string }
|
data/lib/inferno/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: inferno_core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen MacVicar
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2024-
|
13
|
+
date: 2024-12-17 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activesupport
|
@@ -390,6 +390,7 @@ files:
|
|
390
390
|
- lib/inferno.rb
|
391
391
|
- lib/inferno/apps/cli.rb
|
392
392
|
- lib/inferno/apps/cli/console.rb
|
393
|
+
- lib/inferno/apps/cli/evaluate.rb
|
393
394
|
- lib/inferno/apps/cli/execute.rb
|
394
395
|
- lib/inferno/apps/cli/execute/console_outputter.rb
|
395
396
|
- lib/inferno/apps/cli/execute/json_outputter.rb
|
@@ -432,7 +433,10 @@ files:
|
|
432
433
|
- lib/inferno/apps/cli/templates/lib/%library_name%/igs/.keep
|
433
434
|
- lib/inferno/apps/cli/templates/lib/%library_name%/igs/README.md
|
434
435
|
- lib/inferno/apps/cli/templates/lib/%library_name%/igs/put_ig_package_dot_tgz_here
|
436
|
+
- lib/inferno/apps/cli/templates/lib/%library_name%/metadata.rb.tt
|
435
437
|
- lib/inferno/apps/cli/templates/lib/%library_name%/patient_group.rb.tt
|
438
|
+
- lib/inferno/apps/cli/templates/lib/%library_name%/suite.rb.tt
|
439
|
+
- lib/inferno/apps/cli/templates/lib/%library_name%/version.rb.tt
|
436
440
|
- lib/inferno/apps/cli/templates/run.sh
|
437
441
|
- lib/inferno/apps/cli/templates/setup.sh
|
438
442
|
- lib/inferno/apps/cli/templates/spec/%library_name%/patient_group_spec.rb.tt
|
@@ -461,6 +465,7 @@ files:
|
|
461
465
|
- lib/inferno/apps/web/serializers/hash_value_extractor.rb
|
462
466
|
- lib/inferno/apps/web/serializers/header.rb
|
463
467
|
- lib/inferno/apps/web/serializers/input.rb
|
468
|
+
- lib/inferno/apps/web/serializers/markdown_extractor.rb
|
464
469
|
- lib/inferno/apps/web/serializers/message.rb
|
465
470
|
- lib/inferno/apps/web/serializers/preset.rb
|
466
471
|
- lib/inferno/apps/web/serializers/request.rb
|
@@ -500,6 +505,12 @@ files:
|
|
500
505
|
- lib/inferno/dsl/configurable.rb
|
501
506
|
- lib/inferno/dsl/fhir_client.rb
|
502
507
|
- lib/inferno/dsl/fhir_client_builder.rb
|
508
|
+
- lib/inferno/dsl/fhir_evaluation/config.rb
|
509
|
+
- lib/inferno/dsl/fhir_evaluation/dataset_loader.rb
|
510
|
+
- lib/inferno/dsl/fhir_evaluation/evaluation_context.rb
|
511
|
+
- lib/inferno/dsl/fhir_evaluation/evaluation_result.rb
|
512
|
+
- lib/inferno/dsl/fhir_evaluation/evaluator.rb
|
513
|
+
- lib/inferno/dsl/fhir_evaluation/rule.rb
|
503
514
|
- lib/inferno/dsl/fhir_resource_validation.rb
|
504
515
|
- lib/inferno/dsl/fhir_validation.rb
|
505
516
|
- lib/inferno/dsl/fhirpath_evaluation.rb
|
@@ -539,6 +550,7 @@ files:
|
|
539
550
|
- lib/inferno/exceptions.rb
|
540
551
|
- lib/inferno/ext/fhir_client.rb
|
541
552
|
- lib/inferno/ext/fhir_models.rb
|
553
|
+
- lib/inferno/ext/json_parser.rb
|
542
554
|
- lib/inferno/ext/rack.rb
|
543
555
|
- lib/inferno/jobs.rb
|
544
556
|
- lib/inferno/jobs/execute_test_run.rb
|