class Measures::MATMeasureFiles

Attributes

components[RW]
cql_libraries[RW]
hqmf_xml[RW]
human_readable[RW]

Public Class Methods

create_from_zip_file(zip_file) click to toggle source
# File lib/measure-loader/mat_measure_files.rb, line 28
def self.create_from_zip_file(zip_file)
  folders = unzip_measure_zip_into_hash(zip_file).values
  raise MeasureLoadingInvalidPackageException.new("No measure found") if folders.empty?
  folders.sort_by! { |h| h[:depth] }
  raise MeasureLoadingInvalidPackageException.new("Multiple measure folders at top level") if folders[0][:depth] == folders.dig(1,:depth)

  measure_folder, *component_measure_folders = folders
  measure_assets = make_measure_artifacts(parse_measure_files(measure_folder))
  measure_assets.components = component_measure_folders.collect {|f| make_measure_artifacts(parse_measure_files(f))}

  return measure_assets
rescue StandardError => e
  raise MeasureLoadingInvalidPackageException.new("Error processing package file: #{e.message}")
end
new(hqmf_xml, cql_libraries, human_readable) click to toggle source
# File lib/measure-loader/mat_measure_files.rb, line 18
def initialize(hqmf_xml, cql_libraries, human_readable)
  @hqmf_xml = hqmf_xml
  @cql_libraries = cql_libraries
  @human_readable = human_readable

  raise MeasureLoadingInvalidPackageException.new("Measure package missing required element: HQMF XML File") if @hqmf_xml.nil?
  raise MeasureLoadingInvalidPackageException.new("Measure package missing required element: Human Readable Document") if @human_readable.nil?
  raise MeasureLoadingInvalidPackageException.new("Measure package missing required element: CQL Libraries") if @cql_libraries.nil? || @cql_libraries.empty?
end
valid_zip?(zip_file) click to toggle source
# File lib/measure-loader/mat_measure_files.rb, line 43
def self.valid_zip?(zip_file)
  create_from_zip_file(zip_file)
  return true
rescue MeasureLoadingInvalidPackageException
  return false
end

Private Class Methods

make_measure_artifacts(measure_files) click to toggle source
# File lib/measure-loader/mat_measure_files.rb, line 68
def make_measure_artifacts(measure_files)
  library_count = measure_files[:cqls].length
  unless (measure_files[:elm_xmls].length == library_count && measure_files[:elms].length == library_count)
    raise MeasureLoadingInvalidPackageException.new("Each library must have a CQL file, an ELM JSON file, and an ELM XML file.")
  end

  cql_libraries = []
  library_count.times do |i|
    elm_annotation = measure_files[:elm_xmls][i]
    elm = measure_files[:elms][i]
    cql = measure_files[:cqls][i]

    id, version = verify_library_versions_match_and_get_version(cql, elm, elm_annotation)
    cql_libraries << CqlLibraryFiles.new(id, version, cql, elm, elm_annotation)
  end

  return new(measure_files[:hqmf_xml], cql_libraries, measure_files[:human_readable])
end
parse_measure_files(folder) click to toggle source
# File lib/measure-loader/mat_measure_files.rb, line 87
def parse_measure_files(folder)
  measure_files = { cqls: [], elms: [], elm_xmls: [] }
  folder[:files].sort_by! { |h| h[:basename] }
  folder[:files].each do |file|
    case file[:basename].extname.to_s
    when '.cql'
      measure_files[:cqls] << file[:contents]
    when '.json'
      begin
        measure_files[:elms] << JSON.parse(file[:contents], max_nesting: 1000)
      rescue StandardError
        raise MeasureLoadingInvalidPackageException.new("Unable to parse json file #{basename}")
      end
    when '.html'
      raise MeasureLoadingInvalidPackageException.new("Multiple HumanReadable docs found in same folder") unless measure_files[:human_readable].nil?
      measure_files[:human_readable] = file[:contents]
    when '.xml'
      begin
        doc = Nokogiri::XML(file[:contents]) { |config| config.noblanks }
      rescue StandardError
        raise MeasureLoadingInvalidPackageException.new("Unable to parse xml file #{basename}")
      end
      if doc.root.name == 'QualityMeasureDocument'
        raise MeasureLoadingInvalidPackageException.new("Multiple QualityMeasureDocuments found in same folder") unless measure_files[:hqmf_xml].nil?
        measure_files[:hqmf_xml] = doc
      elsif doc.root.name == 'library'
        measure_files[:elm_xmls] << doc
      end
    end
  end
  raise MeasureLoadingInvalidPackageException.new("Measure folder found with no hqmf") if measure_files[:hqmf_xml].nil?
  return measure_files
end
unzip_measure_zip_into_hash(zip_file) click to toggle source
# File lib/measure-loader/mat_measure_files.rb, line 54
def unzip_measure_zip_into_hash(zip_file)
  folders = Hash.new { |h, k| h[k] = {files: []} }
  Zip::File.open zip_file.path do |file|
    file.each do |f|
      pn = Pathname(f.name)
      next if '__MACOSX'.in? pn.each_filename  # ignore anything in a __MACOSX folder
      next unless pn.basename.extname.in? ['.xml','.cql','.json','.html']
      folders[pn.dirname][:files] << { basename: pn.basename, contents: f.get_input_stream.read }
      folders[pn.dirname][:depth] =  pn.each_filename.count # this is just a count of how many folders are in the path
    end
  end
  return folders
end
verify_library_versions_match_and_get_version(cql, elm, elm_annotation) click to toggle source
# File lib/measure-loader/mat_measure_files.rb, line 121
def verify_library_versions_match_and_get_version(cql, elm, elm_annotation)
  identifier = elm_annotation.at_xpath('/xmlns:library/xmlns:identifier')
  id = identifier['id']
  version = identifier['version']

  if (Helpers.elm_id(elm)!= id ||
      Helpers.elm_version(elm) != version ||
      !(cql.include?("library #{id} version '#{version}'") || cql.include?("<library>#{id}</library><version>#{version}</version>"))
     )
    raise MeasureLoadingInvalidPackageException.new("Cql library assets must all have same version.")
  end

  return id, version
end