class SimpleXml::Precondition
Constants
- AGE_AT
- DATA_CRITERIA_OP
- DATETIMEDIFF
- FUNCTIONAL_OP
- INTERSECTION
- LOGICAL_OP
- SATISFIES_ALL
- SATISFIES_ANY
- SET_OP
- SUB_TREE
- TEMPORAL_OP
- UNION
Attributes
comments[RW]
conjunction_code[R]
id[R]
negated_logical[RW]
negation[R]
preconditions[RW]
reference[RW]
Public Class Methods
new(entry, doc, negated=false)
click to toggle source
# File lib/model/precondition.rb, line 23 def initialize(entry, doc, negated=false) @doc = doc @entry = entry entry = nil @id = HQMF::Counter.instance.next @preconditions = [] @negation = negated @negated_logical = false @subset = nil if @entry.name == FUNCTIONAL_OP handle_functional end # if we have a subset then we want this to be a grouping data criteria if @entry.name == LOGICAL_OP && @subset.nil? handle_logical elsif @entry.name == SET_OP && @subset.nil? handle_set_op elsif @entry.name == TEMPORAL_OP && @entry["type"] == "FULFILLS" handle_fulfills elsif @entry.name == TEMPORAL_OP && @subset.nil? handle_temporal elsif attr_val('@type') == DATETIMEDIFF handle_grouping_functional elsif (attr_val('@type') == SATISFIES_ALL || attr_val('@type') == SATISFIES_ANY) && @subset.nil? handle_satisfies elsif @entry.name == DATA_CRITERIA_OP || @subset handle_data_criteria elsif @entry.name == SUB_TREE handle_sub_tree else raise "unknown precondition type: #{@entry.name}" end @comments = comments_on(@entry) unless comments_on(@entry).empty? end
Public Instance Methods
copy(other)
click to toggle source
# File lib/model/precondition.rb, line 297 def copy(other) @id = other.id @preconditions = other.preconditions @reference = other.reference @conjunction_code = other.conjunction_code # do not copy negation... we want the negation from the parent to remain #@negation = other.negation end
handle_age_at()
click to toggle source
# File lib/model/precondition.rb, line 84 def handle_age_at # find the birthdate QDM element, if it exists birthdate_hqmf_id = nil @doc.source_data_criteria.each do |sdc| birthdate_hqmf_id = sdc.hqmf_id if sdc.definition == 'patient_characteristic_birthdate' end # if it doesn't, create one and add it to the document if birthdate_hqmf_id.nil? criteria = create_birthdate_criteria birthdate_hqmf_id = criteria.hqmf_id @doc.source_data_criteria << criteria @doc.criteria_map[criteria.hqmf_id] = criteria end @entry = create_age_timing(birthdate_hqmf_id, children_of(@entry).first, attr_val('@operatorType'), attr_val('@quantity'), attr_val('@unit')) end
handle_data_criteria()
click to toggle source
# File lib/model/precondition.rb, line 228 def handle_data_criteria criteria = DataCriteria.get_criteria(@entry, @id, @doc, @subset, nil, true) @reference = Reference.new(criteria.id) end
handle_fulfills()
click to toggle source
# File lib/model/precondition.rb, line 215 def handle_fulfills type = attr_val('@type') children = children_of(@entry) left_child = children[0] right_child = children[1] right = DataCriteria.get_criteria(right_child, @id, @doc, @subset, type, false) left = DataCriteria.get_criteria(left_child, @id, @doc, @subset, nil, true) left.field_values ||= {} left.field_values["FLFS"] = TypedReference.new(right.id,"FLFS","") @reference = Reference.new(left.id) end
handle_functional()
click to toggle source
# File lib/model/precondition.rb, line 61 def handle_functional type = attr_val('@type') case type when 'NOT' @negation = true when SATISFIES_ALL, SATISFIES_ANY '' when AGE_AT handle_age_at else comparison = attr_val('@operatorType') quantity = attr_val('@quantity') unit = attr_val('@unit') @subset = SubsetOperator.new(type, Utilities.build_value(comparison, quantity, unit)) end children = children_of(@entry) if children.count == 1 @entry = children.first end end
handle_grouping_functional()
click to toggle source
# File lib/model/precondition.rb, line 163 def handle_grouping_functional children = children_of(@entry) @preconditions = [] children.collect do |precondition| @preconditions << Precondition.new(precondition, @doc) end @preconditions.select! {|p| !p.preconditions.empty? || p.reference } subsets = [@subset] # check if we have a functional wrapped by another if @subset.type != attr_val('@type') handle_functional subsets.unshift @subset end criteria = DataCriteria.convert_precondition_to_criteria(self, @doc, @subset.type) criteria.derivation_operator = HQMF::DataCriteria::XPRODUCT criteria.subset_operators ||= [] criteria.subset_operators.concat subsets @preconditions = [] @reference = Reference.new(criteria.id) end
handle_logical()
click to toggle source
# File lib/model/precondition.rb, line 135 def handle_logical @conjunction_code = translate_type(attr_val('@type')) if is_negated_logical(attr_val('@type')) @negation = true @negated_logical = true end @preconditions = [] children_of(@entry).collect do |precondition| # if we have a negated child with multiple logical children, then we want to make sure we don't infer an extra AND if negation_with_logical_children?(precondition) children_of(precondition).each do |child| @preconditions << Precondition.new(child, @doc, true) end else @preconditions << Precondition.new(precondition, @doc) end end @preconditions.select! {|p| !p.preconditions.empty? || p.reference } end
handle_negations(parent)
click to toggle source
# File lib/model/precondition.rb, line 312 def handle_negations(parent) negations = [] if @negated_logical # wrap the negation with an extra level so that it aligns with the display for non-logical negations @negation = false @preconditions = [ParsedPrecondition.new(HQMF::Counter.instance.next, @preconditions, nil, conjunction_code, true)] # we do not need to do a translation if it's a negated logical (it is already in the correct form) else @preconditions.delete_if {|p| negations << p if p.negation && !p.negated_logical} unless (negations.empty?) negations.each {|p| p.instance_variable_set(:@negation, false) } inverted_conjunction_code = HQMF::Precondition::INVERSIONS[conjunction_code] # if we only have negations, then do not create an extra element if @preconditions.empty? @negation = true @conjunction_code = inverted_conjunction_code @preconditions.concat negations else # create a new inverted element for the subset of the children that are negated @preconditions << ParsedPrecondition.new(HQMF::Counter.instance.next, negations, nil, inverted_conjunction_code, true) end end end @preconditions.each do |p| p.handle_negations(self) end end
handle_satisfies()
click to toggle source
# File lib/model/precondition.rb, line 102 def handle_satisfies children = children_of(@entry) # use shift to remove the left hand entry defining the left hand of the satisfies statement (we don't need that) children.shift @preconditions = [] children.collect do |precondition| # if we have a negated child with multiple logical children, then we want to make sure we don't infer an extra AND if negation_with_logical_children?(precondition) children_of(precondition).each do |child| @preconditions << Precondition.new(child, @doc, true) end else @preconditions << Precondition.new(precondition, @doc) end end @preconditions.select! {|p| !p.preconditions.empty? || p.reference } if attr_val('@type') == SATISFIES_ALL criteria = DataCriteria.convert_precondition_to_criteria(self, @doc, 'satisfiesAll') criteria.derivation_operator = HQMF::DataCriteria::INTERSECT criteria.instance_variable_set('@definition','satisfies_all') elsif attr_val('@type') == SATISFIES_ANY criteria = DataCriteria.convert_precondition_to_criteria(self, @doc, 'satisfiesAny') criteria.derivation_operator = HQMF::DataCriteria::UNION criteria.instance_variable_set('@definition','satisfies_any') end criteria.instance_variable_set('@description', children[0]['displayName'] || attr_val('@displayName')) @preconditions = [] @reference = Reference.new(criteria.id) end
handle_set_op()
click to toggle source
# File lib/model/precondition.rb, line 156 def handle_set_op handle_logical criteria = DataCriteria.convert_precondition_to_criteria(self, @doc, @conjunction_code) @reference = Reference.new(criteria.id) @preconditions = [] end
handle_sub_tree()
click to toggle source
# File lib/model/precondition.rb, line 233 def handle_sub_tree sub_tree = @doc.sub_tree_map[attr_val('@id')] copy(sub_tree.precondition) end
handle_temporal()
click to toggle source
# File lib/model/precondition.rb, line 187 def handle_temporal type = attr_val('@type') comparison = attr_val('@operatorType') quantity = attr_val('@quantity') unit = attr_val('@unit') children = children_of(@entry) left_child = children[0] right_child = children[1] right = DataCriteria.get_criteria(right_child, @id, @doc, @subset, type, false) temporal = TemporalReference.new(type, comparison, quantity, unit, right) # check to see if we are referening MP start or end and make sure that the timing is appropriate update_temporal_mp_reference(temporal, right) if (left_child.name == LOGICAL_OP) # make this the left and then push down the right... we have no current node to construct copy(Precondition.new(left_child, @doc)) push_down_temporal(self, temporal) else left = DataCriteria.get_criteria(left_child, @id, @doc, @subset, nil, true) left.add_temporal(temporal) @reference = Reference.new(left.id) end end
is_negated_logical(type)
click to toggle source
# File lib/model/precondition.rb, line 267 def is_negated_logical(type) case type when 'andNot' true when 'orNot' true else false end end
negation_with_logical_children?(precondition)
click to toggle source
# File lib/model/precondition.rb, line 259 def negation_with_logical_children?(precondition) if precondition.name == FUNCTIONAL_OP && precondition.at_xpath('@type').value == 'NOT' children = children_of(precondition) return children.length > 1 end false end
push_down_comments(precondition, comments)
click to toggle source
# File lib/model/precondition.rb, line 246 def push_down_comments(precondition, comments) return if comments.empty? if precondition.preconditions.empty? if @doc.data_criteria(precondition.reference.id).comments comments.each {|c| @doc.data_criteria(precondition.reference.id).comments << c unless @doc.data_criteria(precondition.reference.id).comments.include? c} else @doc.data_criteria(precondition.reference.id).comments = comments end else precondition.preconditions.each {|p| push_down_comments(p, comments)} end end
push_down_temporal(precondition, temporal)
click to toggle source
# File lib/model/precondition.rb, line 238 def push_down_temporal(precondition, temporal) if precondition.preconditions.empty? @doc.data_criteria(precondition.reference.id).push_down_temporal(temporal, @doc) else precondition.preconditions.each {|p| push_down_temporal(p, temporal)} end end
to_model()
click to toggle source
# File lib/model/precondition.rb, line 306 def to_model pcs = preconditions.collect {|p| p.to_model} mr = reference ? reference.to_model : nil HQMF::Precondition.new(id, pcs, mr, conjunction_code, negation, @comments) end
translate_type(type)
click to toggle source
# File lib/model/precondition.rb, line 278 def translate_type(type) case type when 'and' HQMF::Precondition::ALL_TRUE when 'intersection' SimpleXml::Precondition::INTERSECTION when 'andNot' HQMF::Precondition::AT_LEAST_ONE_TRUE when 'or' HQMF::Precondition::AT_LEAST_ONE_TRUE when 'union' SimpleXml::Precondition::UNION when 'orNot' HQMF::Precondition::ALL_TRUE else raise "Unknown population criteria type #{type}" end end
update_temporal_mp_reference(temporal, right)
click to toggle source
# File lib/model/precondition.rb, line 341 def update_temporal_mp_reference(temporal, right) if (right.id== HQMF::Document::MEASURE_PERIOD_ID) references_start = {'SBS'=>'SBE','SAS'=>'SAE','EBS'=>'EBE','EAS'=>'EAE','SCW'=>'SCWE'} references_end = {'EBE'=>'EBS','EAE'=>'EAS','SBE'=>'SBS','SAE'=>'SAS','ECW'=>'ECWS'} if @doc.measure_period_map[right.hqmf_id] == :measure_period_start && references_end[temporal.type] # before or after the END of the measurement period START. Convert to before or after the START of the measurement period. # SAE of MPS => SAS of MP # ends concurrent with measurement period START. Convert to concurrent with START of measurement period. # ECW of MPS => ECWS temporal.type = references_end[temporal.type] elsif @doc.measure_period_map[right.hqmf_id] == :measure_period_end && references_start[temporal.type] # before or after the START of the measurement period END. Convert to before or after the END of the measurement period. # SBS of MPE => SBE of MP # starts concurrent with measurement period END. Convert to concurrent with END of measurement period. # SCW of MPE => SCWE temporal.type = references_start[temporal.type] end end end