module Metanorma class Requirements class Modspec < Default def recommendation_label(elem, type, xrefs) @xrefs ||= xrefs.dup init_lookups(elem.document) label = elem.at(ns("./identifier"))&.text if inject_crossreference_reqt?(elem, label) recommendation_label_xref(elem, label, xrefs, type) else type = recommendation_class_label(elem) super end end def recommendation_label_xref(elem, label, xrefs, type) id = @reqtlabels[label] number = xrefs.anchor(id, :xref, false) number.nil? and return type elem.ancestors("requirement, recommendation, permission").empty? and return number "#{number}" end def init_lookups(doc) return if @init_lookups @init_lookups = true @reqtlabels = reqtlabels(doc) @reqt_ids = reqt_ids(doc) @reqt_links_class = reqt_links_class(doc) @reqt_links_test = reqt_links_test(doc) end def reqtlabels(doc) doc.xpath(ns("//requirement | //recommendation | //permission")) .each_with_object({}) do |r, m| l = r.at(ns("./identifier"))&.text and m[l] = r["id"] end end # embedded reqts xref to reqts via label lookup def inject_crossreference_reqt?(node, label) !node.ancestors("requirement, recommendation, permission").empty? and @reqtlabels[label] end def recommendation_class_label(node) case node["type"] when "verification" then @labels["modspec"]["#{node.name}test"] when "class" then @labels["modspec"]["#{node.name}class"] when "abstracttest" then @labels["modspec"]["abstracttest"] when "conformanceclass" then @labels["modspec"]["conformanceclass"] else case node.name when "recommendation" then @labels["default"]["recommendation"] when "requirement" then @labels["default"]["requirement"] when "permission" then @labels["default"]["permission"] end end end def reqt_ids(docxml) docxml.xpath(ns("//requirement | //recommendation | //permission")) .each_with_object({}) do |r, m| id = r.at(ns("./identifier")) or next m[id.text] = { id: r["id"], lbl: @xrefs.anchor(r["id"], :xref, false) } end end def reqt_links_test(docxml) docxml.xpath(ns("//requirement | //recommendation | //permission")) .each_with_object({}) do |r, m| next unless %w(conformanceclass verification).include?(r["type"]) subj = r.at(ns("./classification[tag = 'target']/value")) id = r.at(ns("./identifier")) or next lbl = @xrefs.anchor(@reqt_ids[id.text.strip][:id], :xref, false) next unless subj && lbl m[subj.text] = { lbl: lbl, id: r["id"] } end end def recommendation_link_test(ident) test = @reqt_links_test[ident&.strip] or return nil "#{test[:lbl]}" end def reqt_links_class(docxml) docxml.xpath(ns("//requirement | //recommendation | //permission")) .each_with_object({}) do |r, m| next unless %w(class conformanceclass).include?(r["type"]) id = r.at(ns("./identifier")) or next r.xpath(ns("./requirement | ./recommendation | ./permission")) .each do |r1| id1 = r1.at(ns("./identifier")) or next lbl = @xrefs.anchor(@reqt_ids[id.text.strip][:id], :xref, false) next unless lbl m[id1.text] = { lbl: lbl, id: r["id"] } end end end def recommendation_link_class(ident) test = @reqt_links_class[ident&.strip] or return nil "#{test[:lbl]}" end def recommendation_id(ident) test = @reqt_ids[ident&.strip] or return ident&.strip "#{test[:lbl]}" end end end end