Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
jhlee-mitre committed Nov 26, 2024
1 parent 1d4662d commit bd9aaa1
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 148 deletions.
4 changes: 2 additions & 2 deletions lib/inferno/apps/cli/evaluator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
module Inferno
module CLI
class Evaluator
def run(_log_level = Logger::DEBUG, ig_path, examples_path)
Inferno::DSL::FHIREvaluation::Evaluator.new(ig_path, examples_path)
def run(_log_level = Logger::DEBUG, ig_path, data_path)
Inferno::DSL::FHIREvaluation::Evaluator.new(ig_path, data_path)
end
end
end
Expand Down
31 changes: 18 additions & 13 deletions lib/inferno/apps/cli/main.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,30 +21,35 @@ class Main < Thor
Run the evaluation CLI with
`bundle exec evaluator evaluate ig_path [data_path]`
`bundle exec inferno evaluate ig_path [data_path]`
Examples:
# 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.
`bundle exec evaluator evaluate ./uscore.tgz ./package/example`
`bundle exec inferno evaluate ./uscore.tgz ./package/example`
# Loads the us core ig and evaluate the data included in the IG's example folder
`bundle exec evaluator evaluate ./uscore.tgz`
`bundle exec inferno evaluate ./uscore.tgz`
# 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
`bundle exec evaluator evaluate ./uscore.tgz --output outcome.json`
`bundle exec inferno evaluate ./uscore.tgz --output outcome.json`
LONGDESC
# ToDo: Add options below as arguments
# TODO: Add options below as arguments
option :ig_path,
aliases: ['-ig'],
type: :string,
desc: 'IG Path'
option :examples_path,
aliases: ['-ex'],
type: :string,
desc: 'Example data path'
aliases: ['-i'],
type: :string,
desc: 'FHIR IG Path'
option :data_path,
aliases: ['-d'],
type: :string,
desc: 'Example FHIR data path'
# TODO: implement option of exporting result as OperationOutcome
option :output,
aliases: ['-o'],
type: :string,
desc: 'Export evaluation result to outcome.json as an OperationOutcome'
def evaluate
Evaluator.new.run(Logger::INFO, options[:ig_path], options[:examples_path])
Evaluator.new.run(Logger::INFO, options[:ig_path], options[:data_path])
end

desc 'console', 'Start an interactive console session with Inferno'
Expand Down
22 changes: 11 additions & 11 deletions lib/inferno/dsl/fhir_evaluation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ def initialize(ig_path, examples_path)
require_relative file
end

config = Config.new
Config.new

ig_path = File.join(__dir__, 'fhir_evaluator', 'ig', 'uscore7.0.0.tgz')
validate_args(ig_path, examples_path)
ig = FhirEvaluator::IG.new(ig_path)

data = if examples_path
if examples_path
Dataset.from_path(examples_path)
else
ig.examples
Expand All @@ -40,17 +40,18 @@ def initialize(ig_path, examples_path)
# Rule execution and result output will be later integrated at phase 2 and 3.

# results = FhirEvaluator::Evaluator.new(ig).evaluate(data, config)

# output_results(results, options[:output])

# output_results(results, options[:output])
end

def validate_args(ig_path, examples_path)
raise 'A path to an IG is required!' unless ig_path

raise "Provided path '#{examples_path}' is not a directory" if examples_path && (!File.directory? examples_path)

return unless examples_path && (!File.directory? examples_path)

raise "Provided path '#{examples_path}' is not a directory"
end

def output_results(results, output)
if output&.end_with?('json')
oo = FhirEvaluator::EvaluationResult.to_operation_outcome(results)
Expand All @@ -63,7 +64,7 @@ def output_results(results, output)
puts results
end
end

def print(output_fields, title)
puts("╔══════════════ #{title} ═══════════════╗")
puts('║ ╭────────────────┬──────────────────────╮ ║')
Expand All @@ -76,11 +77,10 @@ def print(output_fields, title)
puts('║ ╰────────────────┴──────────────────────╯ ║')
puts('╚═══════════════════════════════════════════╝')
end

def pad(string, length)
format("%#{length}.#{length}s", string)
end

end
end
end
Expand Down
76 changes: 38 additions & 38 deletions lib/inferno/dsl/fhir_evaluator/config.rb
Original file line number Diff line number Diff line change
@@ -1,53 +1,53 @@
module Inferno
module DSL
module FHIREvaluation
class Config
DEFAULT_FILE = File.join(__dir__, 'config', 'default.yml')
attr_accessor :data
class Config
DEFAULT_FILE = File.join(__dir__, 'config', 'default.yml')
attr_accessor :data

# To-do: add config_file as arguments
def initialize(config_file = nil)
@data = if config_file.nil?
YAML.load_file(File.absolute_path(DEFAULT_FILE))
else
YAML.load_file(File.absolute_path(config_file))
end
# To-do: add config_file as arguments
def initialize(config_file = nil)
@data = if config_file.nil?
YAML.load_file(File.absolute_path(DEFAULT_FILE))
else
YAML.load_file(File.absolute_path(config_file))
end

raise(TypeError, 'Malformed configuration') unless @data.is_a?(Hash)
raise(TypeError, 'Malformed configuration') unless @data.is_a?(Hash)

def method_missing(name, *args, &)
section = @data[name.to_s]
if section
Section.new(section)
else
super
def method_missing(name, *args, &)
section = @data[name.to_s]
if section
Section.new(section)
else
super
end
end

def respond_to_missing?(name, include_private = false)
@data.key?(name.to_s) || super
end
end
end

def respond_to_missing?(name, include_private = false)
@data.key?(name.to_s) || super
end
end
class Section
def initialize(details)
@details = details
end

class Section
def initialize(details)
@details = details
end
def method_missing(name, *_args)
attribute = @details[name.to_s]
if attribute.is_a?(Hash)
Section.new(attribute)
else
attribute
end
end

def method_missing(name, *_args)
attribute = @details[name.to_s]
if attribute.is_a?(Hash)
Section.new(attribute)
else
attribute
def respond_to_missing?(name, include_private = false)
@details.key?(name.to_s) || super
end
end
end

def respond_to_missing?(name, include_private = false)
@details.key?(name.to_s) || super
end
end
end
end
end
end
161 changes: 78 additions & 83 deletions lib/inferno/dsl/fhir_evaluator/data_summary.rb
Original file line number Diff line number Diff line change
@@ -1,100 +1,95 @@
module FhirEvaluator
# DataSummary represents the results of performing data characterization.
# At this point DataSummary isn't actually used by the evaluator.
# We will bring back when we need it.

# class DataSummary
# attr_accessor :root_resource_ids, # All Example (root resource) Ids
# :root_bundle_resource_ids, # All Example (root resource) Ids that are Bundle
# :domain_resource_ids, # Domain resource Ids from root and child resources (exclude Bundle)
# :resource_profile_map, # Resources and corresponding profiles
# :resource_patient_map, # Resources and corresponding Patient Ids as subject
# :resource_subject_map # Resources and corresponding subject
class DataSummary
attr_accessor :root_resource_ids, # All Example (root resource) Ids
:root_bundle_resource_ids, # All Example (root resource) Ids that are Bundle
:domain_resource_ids, # Domain resource Ids from root and child resources (exclude Bundle)
:resource_profile_map, # Resources and corresponding profiles
:resource_patient_map, # Resources and corresponding Patient Ids as subject
:resource_subject_map # Resources and corresponding subject

# def initialize(data)
# @root_resource_ids = []
# @root_bundle_resource_ids = []
# @domain_resource_ids = []
# @resource_profile_map = []
# @resource_patient_map = []
# @resource_subject_map = []
def initialize(_data)
@root_resource_ids = []
@root_bundle_resource_ids = []
@domain_resource_ids = []
@resource_profile_map = []
@resource_patient_map = []
@resource_subject_map = []
end

# validate(data)
# summarize(data)
# end
def validate(data)
resource_ids = data.map { |r| extract_resources_ids(r) }.flatten

# def validate(data)
# # Check if duplicate Ids exist for same Resource Type in a data set
# r_ids = data.map { |r| resources_ids(r) }.flatten
if resource_ids.uniq == resource_ids
puts 'No duplicate Ids found. Proceed to evaluate..'
else
dup = resource_ids.detect { |r| resource_ids.count(r) > 1 }
puts "Warning: Found duplicate resource Ids: #{dup}. Please validate Examples before running FHIR Evaluator."
end
end

# if r_ids.uniq == r_ids
# puts 'No duplicate Ids found. Proceed to evaluate..'
# else
# dup = r_ids.detect { |r| r_ids.count(r) > 1 }
# puts "Warning: Found duplicate resource Ids: #{dup}. Please validate Examples before running FHIR Evaluator."
# end
# end
def summarize(data)
# @root_resource_ids = data.map { |r| { type: r.resourceType, id: r.id } }
# @root_bundle_resource_ids = data.map { |r| { type: r.resourceType, id: r.id } if r.resourceType == 'Bundle' }

# def summarize(data)
# # @root_resource_ids = data.map { |r| { type: r.resourceType, id: r.id } }
# # @root_bundle_resource_ids = data.map { |r| { type: r.resourceType, id: r.id } if r.resourceType == 'Bundle' }
# id_hash = Hash.new { |hash, key| hash[key] = [] }
# data.map { |e| resources(e) }.flatten.each do |item|
# id_hash[item[:type]] << item[:id]
# end
# @domain_resource_ids = id_hash.to_a

# # id_hash = Hash.new { |hash, key| hash[key] = [] }
# # data.map { |e| resources(e) }.flatten.each do |item|
# # id_hash[item[:type]] << item[:id]
# # end
# # @domain_resource_ids = id_hash.to_a
# @resource_profile_map = data.map { |e| resources_profiles(e) }.flatten.uniq
# @resource_patient_map = data.map { |e| resources_patients(e) }.flatten.uniq
# @resource_subject_map = data.map { |e| resources_subjects(e) }.flatten.uniq
end

# # @resource_profile_map = data.map { |e| resources_profiles(e) }.flatten.uniq
# # @resource_patient_map = data.map { |e| resources_patients(e) }.flatten.uniq
# # @resource_subject_map = data.map { |e| resources_subjects(e) }.flatten.uniq
# end
def extract_resources_ids(resource)
if resource.resourceType == 'Bundle'
resource.entry.map { |e| extract_resources_ids(e.resource) }.flatten
else
"#{resource.resourceType}/#{resource.id}"
end
end

# def resources_ids(resource)
# if resource.resourceType == 'Bundle'
# resource.entry.map { |e| resources_ids(e.resource) }.flatten
# else
# "#{resource.resourceType}/#{resource.id}"
# end
# end
def resources(resource)
if resource.resourceType == 'Bundle'
resource.entry.map { |e| resources(e.resource) }.flatten
else
{ type: resource.resourceType, id: resource.id }
end
end

# def resources(resource)
# if resource.resourceType == 'Bundle'
# resource.entry.map { |e| resources(e.resource) }.flatten
# else
# { type: resource.resourceType, id: resource.id }
# end
# end
def extract_resources_profiles(resource)
if resource.resourceType == 'Bundle'
resource.entry.map { |e| extract_resources_profiles(e.resource) }.flatten.uniq
elsif resource.meta&.profile
{ resource_id: resource.id, profile: resource.meta&.profile }
end
end

# def resources_profiles(resource)
# if resource.resourceType == 'Bundle'
# resource.entry.map { |e| resources_profiles(e.resource) }.flatten.uniq
# elsif resource.meta&.profile
# { resource_id: resource.id, profile: resource.meta&.profile }
# end
# end
def extract_resources_patients(resource)
if resource.resourceType == 'Bundle'
resource.entry.map { |e| extract_resources_patients(e.resource) }.flatten.uniq
elsif defined? resource.patient.reference
{ resource_id: resource.id, patient: resource.patient.reference }
end
end

# def resources_patients(resource)
# if resource.resourceType == 'Bundle'
# resource.entry.map { |e| resources_patients(e.resource) }.flatten.uniq
# elsif defined? resource.patient.reference
# { resource_id: resource.id, patient: resource.patient.reference }
# end
# end
def extract_resources_subjects(resource)
if resource.resourceType == 'Bundle'
resource.entry.map { |e| extract_resources_subjects(e.resource) }.flatten.uniq
elsif defined? resource.subject.reference
{ resource_id: resource.id, subject: resource.subject.reference }
end
end

# def resources_subjects(resource)
# if resource.resourceType == 'Bundle'
# resource.entry.map { |e| resources_subjects(e.resource) }.flatten.uniq
# elsif defined? resource.subject.reference
# { resource_id: resource.id, subject: resource.subject.reference }
# end
# end

# def to_json(*_args)
# {
# 'Resources' => domain_resource_ids.length,
# 'Root Resources' => root_resource_ids.length
# }
# end
# end
def to_json(*_args)
{
'Resources' => domain_resource_ids.length,
'Root Resources' => root_resource_ids.length
}
end
end
end
Loading

0 comments on commit bd9aaa1

Please sign in to comment.