Class: Asciidoctor::BSI::Converter
- Inherits:
-
ISO::Converter
- Object
- ISO::Converter
- Asciidoctor::BSI::Converter
- Defined in:
- lib/asciidoctor/bsi/front.rb,
lib/asciidoctor/bsi/cleanup.rb,
lib/asciidoctor/bsi/validate.rb,
lib/asciidoctor/bsi/converter.rb,
lib/asciidoctor/bsi/cleanup_ref.rb,
lib/asciidoctor/bsi/validate_list.rb,
lib/asciidoctor/bsi/validate_requirement.rb
Constant Summary collapse
- BSI_PUBLISHER_XPATH =
"./contributor[role/@type = 'publisher']/"\ "organization[abbreviation = 'ISO' or abbreviation = 'IEC' or "\ "abbreviation = 'BSI' or abbreviation = 'CEN' or "\ "abbreviation = 'CENELEC']".freeze
- NORM_BSI_WARN =
"reference other than BSI, CEN, CENELEC, ISO, IEC "\ "not expected as normative".freeze
- XML_ROOT_TAG =
"bsi-standard".freeze
- XML_NAMESPACE =
"https://www.metanorma.org/ns/bsi".freeze
- REQUIREMENT_RE_STR =
Rules for Structure 7.1
"\\b(shall)\\b".freeze
- RECOMMENDATION_RE_STR =
"\\b(should)\\b".freeze
- PERMISSION_RE_STR =
"\\b(may)\\b".freeze
- POSSIBILITY_RE_STR =
"\\b(can|might)\\b".freeze
- PARENT_PARA =
"./ancestor-or-self::*[./parent::clause or "\ "./parent::annex or ./parent::terms or ./parent::definitions or "\ "./parent::references or ./parent::*[./parent::preface]]".freeze
Instance Method Summary collapse
-
#admonition_style(node, text) ⇒ Object
Rules for Structure 24.8.
-
#annex_normative_validate(root) ⇒ Object
Rules for Structure 20.2.
-
#annex_ordering_validate(root) ⇒ Object
Rules for Structure 20.4.
- #annex_validate(root) ⇒ Object
- #asset_style(root) ⇒ Object
-
#avoid_must(root) ⇒ Object
Rules for Structure 7.1.
- #avoid_must_check(text) ⇒ Object
- #biblio_cleanup(xmldoc) ⇒ Object
- #biblio_metanorma_ids1(bib, idx) ⇒ Object
-
#biblio_metanorma_ids_informative(xmldoc) ⇒ Object
Rules for Structure 21.4.
-
#biblio_metanorma_ids_normative(xmldoc) ⇒ Object
Rules for Structure 15.4.
-
#biblio_preface(ref) ⇒ Object
Rules for Structure 21.5.
- #biblio_renumber(xmldoc) ⇒ Object
- #biblio_reorder(xmldoc) ⇒ Object
- #boilerplate_cleanup(xmldoc) ⇒ Object
- #boilerplate_file(_x_orig) ⇒ Object
- #citation_order(bib) ⇒ Object
- #cleanup(xmldoc) ⇒ Object
- #commentary(node) ⇒ Object
- #commentary_attrs(node) ⇒ Object
- #commentary_cleanup(xmldoc) ⇒ Object
- #content_validate(doc) ⇒ Object
-
#docidentifier_cleanup(xmldoc) ⇒ Object
BS as a prefix goes first.
-
#doctype_validate(xmldoc) ⇒ Object
BSI 0:2016 9.4.1.
-
#example_style(node) ⇒ Object
Rules for Structure 25.5.
- #external_constraint(text) ⇒ Object
- #get_id_prefix(xmldoc) ⇒ Object
- #html_converter(node) ⇒ Object
- #id_to_num(bib, ids) ⇒ Object
- #image_name_validate(xmldoc) ⇒ Object
-
#informative_text_style(root) ⇒ Object
Rules for Structure 7.2, 7.3, 24.5.
- #iso_id(node, xml) ⇒ Object
- #list_full_sentence(elem) ⇒ Object
-
#list_punctuation(doc) ⇒ Object
Rules for Structure 23.5.
- #list_punctuation1(list, prectext) ⇒ Object
- #list_semicolon_phrase(elem, last) ⇒ Object
-
#listcount_validate(doc) ⇒ Object
Rules for Structure 23.3.
- #metadata_author(node, xml) ⇒ Object
- #metadata_copyright(node, xml) ⇒ Object
- #metadata_doctype(node, xml) ⇒ Object
- #metadata_publisher(node, xml) ⇒ Object
- #new_ref(title, norm) ⇒ Object
-
#norm_bibitem_style(root) ⇒ Object
Rules for Structure 10.2.
- #norm_ref_validate(doc) ⇒ Object
-
#normative_text_style(root) ⇒ Object
Rules for Structure 7.2.
-
#normref_cleanup(xmldoc) ⇒ Object
Rules for Structure 15.4.
-
#note(node) ⇒ Object
TODO: we will not implement sections for now (Rules for Structure 6.4).
-
#note_style(node) ⇒ Object
requirement language taken care of in informative_text_style.
- #ol_cleanup(doc) ⇒ Object
- #ol_cleanup1(list, idx) ⇒ Object
-
#ordinal_check(node) ⇒ Object
Rules for Structure 9.1.
- #org_abbrev ⇒ Object
- #pdf_converter(node) ⇒ Object
- #presentation_xml_converter(node) ⇒ Object
- #relaton_relations ⇒ Object
- #section_style(root) ⇒ Object
- #see_xrefs_validate(root) ⇒ Object
- #sort_biblio(bib) ⇒ Object
- #sort_biblio_appearance(bib) ⇒ Object
-
#sort_biblio_key(bib) ⇒ Object
Rules for Structure 15.4 Normative references ordering sort by: alphanumeric prefix, then docnumber if present, numeric sort else alphanumeric metanorma id (abbreviation) then doc part number if present, numeric sort then doc id (not DOI &c) then title.
- #sort_norm_appearance(bib) ⇒ Object
-
#spec_normative_text_style(node) ⇒ Object
Rules for Structure 7.3, 7.4, 7.5.
- #split_ref(ref, norm) ⇒ Object
- #sts_converter(node) ⇒ Object
- #style(node, text) ⇒ Object
-
#style_number(node, text) ⇒ Object
protest decimal comma not decimal point TODO we will not yet override decimal comma warning if this is a National Annex to Eurocode (Rules for Structure Annex B).
-
#style_plusminus(node, text) ⇒ Object
Rules for Structure 27.5.
-
#style_subscript(node) ⇒ Object
Rules for Structure 27.6.
-
#subclause_validate(root) ⇒ Object
Rules for Structure 22.3.2.
-
#symbol_style(xmldoc) ⇒ Object
Rules for Structure 17.5.
- #table_footnote_renumber1(fn, i, seen) ⇒ Object
-
#table_validate(xmldoc) ⇒ Object
Rules for Structure 29.6.
-
#tech_report_style(root) ⇒ Object
Rules for Structure 7.2.
-
#termdef_style(xmldoc) ⇒ Object
Rules for Structure 16.5.5.
-
#title_names_type_validate(root) ⇒ Object
Rules for Structure 11.5.2.
- #validate(doc) ⇒ Object
-
#xrefs_annex_validate(xref, target) ⇒ Object
Rules for Structure 20.5.
Instance Method Details
#admonition_style(node, text) ⇒ Object
Rules for Structure 24.8
70 71 72 73 74 75 76 77 78 79 |
# File 'lib/asciidoctor/bsi/validate_requirement.rb', line 70 def admonition_style(node, text) r = requirement_check(text) and style_warning(node, "admonition may contain requirement", r) r = (text) and style_warning(node, "admonition may contain permission", r) r = recommendation_check(text) and style_warning(node, "admonition may contain recommendation", r) r = possibility_check(text) and style_warning(node, "admonition may contain possibility", r) end |
#annex_normative_validate(root) ⇒ Object
Rules for Structure 20.2
97 98 99 100 101 102 103 |
# File 'lib/asciidoctor/bsi/validate.rb', line 97 def annex_normative_validate(root) @doctype == "guide" and root.xpath("//annex[@obligation = 'normative']") .each do |s| style_warning(s, "Guide contains normative annex", s&.at("./title")&.text) end end |
#annex_ordering_validate(root) ⇒ Object
Rules for Structure 20.4
106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/asciidoctor/bsi/validate.rb', line 106 def annex_ordering_validate(root) ids = citation_order(root.xpath("//annex")) cite_order = ids.keys.sort { |a, b| ids[a] <=> ids[b] } annex_order = root.xpath("//annex").map { |x| x["id"] } cite_order.each_with_index do |a, i| next if annex_order[i] == a annex = root.at("//annex[@id = '#{a}']") title = annex&.at("./title")&.text || "Annex #{a}" style_warning(annex, "#{title} should be annex ##{i + 1}", nil) end end |
#annex_validate(root) ⇒ Object
91 92 93 94 |
# File 'lib/asciidoctor/bsi/validate.rb', line 91 def annex_validate(root) annex_normative_validate(root) annex_ordering_validate(root) end |
#asset_style(root) ⇒ Object
62 63 64 65 66 67 |
# File 'lib/asciidoctor/bsi/validate_requirement.rb', line 62 def asset_style(root) root.xpath("//admonition[not(@type = 'commentary')]").each do |e| admonition_style(e, extract_text(e)) end super end |
#avoid_must(root) ⇒ Object
Rules for Structure 7.1
16 17 18 19 20 21 22 |
# File 'lib/asciidoctor/bsi/validate_requirement.rb', line 16 def avoid_must(root) root.xpath("//sections/clause[not(@type = 'scope')] | //annex") .each do |s| r = avoid_must_check(extract_text(s)) style_warning(s, "text contains ambiguous 'must'", r) if r end end |
#avoid_must_check(text) ⇒ Object
24 25 26 27 28 29 |
# File 'lib/asciidoctor/bsi/validate_requirement.rb', line 24 def avoid_must_check(text) text.split(/\.\s+/).each do |t| return t if /\b(must|will)\b/xi.match? t end nil end |
#biblio_cleanup(xmldoc) ⇒ Object
4 5 6 7 8 9 10 11 12 13 14 15 16 |
# File 'lib/asciidoctor/bsi/cleanup_ref.rb', line 4 def biblio_cleanup(xmldoc) (xmldoc) super xmldoc.xpath("//bibliography//references | //clause//references | "\ "//annex//references").each do |r| next if r["normative"] == "true" if r.at("./bibitem/docidentifier[@type = 'metanorma']") && r.at("./bibitem[not(docidentifier[@type = 'metanorma'])]") split_ref(r, false) end end end |
#biblio_metanorma_ids1(bib, idx) ⇒ Object
33 34 35 36 37 38 39 |
# File 'lib/asciidoctor/bsi/cleanup_ref.rb', line 33 def (bib, idx) bib.at("./docidentifier[@type][not(@type = 'DOI' or "\ "@type = 'ISSN' or @type = 'ISBN')]") and return bib&.at("./docidentifier[@type = 'metanorma']")&.remove bib.at("./docidentifier").previous = "<docidentifier type='metanorma'>[#{idx}]</docidentifier>" end |
#biblio_metanorma_ids_informative(xmldoc) ⇒ Object
Rules for Structure 21.4
42 43 44 45 46 47 |
# File 'lib/asciidoctor/bsi/cleanup_ref.rb', line 42 def (xmldoc) xmldoc.xpath("//references[@normative = 'false']/bibitem") .each_with_index do |b, i| (b, i) end end |
#biblio_metanorma_ids_normative(xmldoc) ⇒ Object
Rules for Structure 15.4
19 20 21 22 23 24 |
# File 'lib/asciidoctor/bsi/cleanup_ref.rb', line 19 def (xmldoc) xmldoc.xpath("//references[@normative = 'true']/bibitem") .each_with_index do |b, i| (b, i) end end |
#biblio_preface(ref) ⇒ Object
Rules for Structure 21.5
178 179 180 |
# File 'lib/asciidoctor/bsi/cleanup_ref.rb', line 178 def biblio_preface(ref) ref.at("./title").next = "<p>#{@i18n.biblio_pref}</p>" end |
#biblio_renumber(xmldoc) ⇒ Object
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/asciidoctor/bsi/cleanup_ref.rb', line 123 def biblio_renumber(xmldoc) ["true", "false"].each do |norm| i = 0 xmldoc.xpath("//bibliography//references | //clause//references | "\ "//annex//references").each do |r| next if r["normative"] != norm r.xpath("./bibitem").each do |b| next unless docid = b.at("./docidentifier[@type = 'metanorma']") next unless /^\[\d+\]$/.match?(docid.text) i += 1 docid.children = "[#{norm == 'true' ? 'N' : ''}#{i}]" end end end end |
#biblio_reorder(xmldoc) ⇒ Object
49 50 51 52 53 54 55 56 57 58 |
# File 'lib/asciidoctor/bsi/cleanup_ref.rb', line 49 def biblio_reorder(xmldoc) @sort_bib_by_appearance = true xmldoc.xpath("//references[@normative = 'false']").each do |r| biblio_reorder1(r) end @sort_bib_by_appearance = false xmldoc.xpath("//references[@normative = 'true']").each do |r| biblio_reorder1(r) end end |
#boilerplate_cleanup(xmldoc) ⇒ Object
170 171 172 173 174 175 |
# File 'lib/asciidoctor/bsi/cleanup_ref.rb', line 170 def boilerplate_cleanup(xmldoc) super f = xmldoc.at("//bibliography//references[@normative = 'false']"\ "[not(references)]") f and biblio_preface(f) end |
#boilerplate_file(_x_orig) ⇒ Object
15 16 17 |
# File 'lib/asciidoctor/bsi/converter.rb', line 15 def boilerplate_file(_x_orig) File.join(@libdir, "bsi_intro_en.xml") end |
#citation_order(bib) ⇒ Object
65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/asciidoctor/bsi/cleanup_ref.rb', line 65 def citation_order(bib) return {} if bib.empty? ids = bib.each_with_object({}) { |b, m| m[b["id"]] = nil } bib.first.document.xpath(".//xref").each_with_index do |b, i| next unless ids.has_key?(b["target"]) ids[b["target"]] ||= i + 1 end ids end |
#cleanup(xmldoc) ⇒ Object
6 7 8 9 10 11 |
# File 'lib/asciidoctor/bsi/cleanup.rb', line 6 def cleanup(xmldoc) super ol_cleanup(xmldoc) commentary_cleanup(xmldoc) xmldoc end |
#commentary(node) ⇒ Object
37 38 39 40 41 42 43 44 |
# File 'lib/asciidoctor/bsi/converter.rb', line 37 def commentary(node) noko do |xml| xml.admonition **commentary_attrs(node) do |a| node.title.nil? or a.name { |name| name << node.title } wrap_in_para(node, a) end end.join("\n") end |
#commentary_attrs(node) ⇒ Object
28 29 30 31 32 33 34 35 |
# File 'lib/asciidoctor/bsi/converter.rb', line 28 def commentary_attrs(node) attr_code(keep_attrs(node).merge( id: Metanorma::Utils::anchor_or_uuid(node), type: "commentary", target: node.attr("target"), beforeclauses: node.attr("beforeclauses") == "true" ? "true" : nil )) end |
#commentary_cleanup(xmldoc) ⇒ Object
31 32 33 34 35 36 37 |
# File 'lib/asciidoctor/bsi/cleanup.rb', line 31 def commentary_cleanup(xmldoc) @isodoc ||= isodoc(@lang, @script) xmldoc.xpath("//admonition[@type = 'commentary'][not(@target)]") .each do |a| a["target"] = @isodoc.get_clause_id(a) end end |
#content_validate(doc) ⇒ Object
170 171 172 173 174 175 176 |
# File 'lib/asciidoctor/bsi/validate.rb', line 170 def content_validate(doc) super symbol_style(doc) table_validate(doc) listcount_validate(doc) list_punctuation(doc) end |
#docidentifier_cleanup(xmldoc) ⇒ Object
BS as a prefix goes first
50 51 52 53 54 55 56 |
# File 'lib/asciidoctor/bsi/cleanup.rb', line 50 def docidentifier_cleanup(xmldoc) prefix = get_id_prefix(xmldoc) id = xmldoc.at("//bibdata/docidentifier[@type = 'BS']") or return id.content = id_prefix(prefix, id) id = xmldoc.at("//bibdata/ext/structuredidentifier/project-number") and id.content = id_prefix(prefix, id) end |
#doctype_validate(xmldoc) ⇒ Object
BSI 0:2016 9.4.1
8 9 10 11 12 13 14 15 |
# File 'lib/asciidoctor/bsi/validate.rb', line 8 def doctype_validate(xmldoc) doctype = xmldoc&.at("//bibdata/ext/doctype")&.text %w(specification management-systems-standard code-of-practice guide method-of-test method-of-specifying vocabulary classification).include? doctype or @log.add("Document Attributes", nil, "#{doctype} is not a recognised document type") end |
#example_style(node) ⇒ Object
Rules for Structure 25.5
54 55 56 57 58 59 60 |
# File 'lib/asciidoctor/bsi/validate_requirement.rb', line 54 def example_style(node) return if @novalid r = requirement_check(extract_text(node)) and style_warning(node, "Example may contain requirement", r) style(node, extract_text(node)) end |
#external_constraint(text) ⇒ Object
4 |
# File 'lib/asciidoctor/bsi/validate_requirement.rb', line 4 def external_constraint(text); end |
#get_id_prefix(xmldoc) ⇒ Object
39 40 41 42 43 44 45 46 47 |
# File 'lib/asciidoctor/bsi/cleanup.rb', line 39 def get_id_prefix(xmldoc) prefix = [] xmldoc.xpath("//bibdata/contributor[role/@type = 'publisher']"\ "/organization").each do |x| x1 = x.at("abbreviation")&.text || x.at("name")&.text x1 == "BSI" and prefix.unshift("BS") or prefix << x1 end prefix end |
#html_converter(node) ⇒ Object
46 47 48 49 50 51 52 |
# File 'lib/asciidoctor/bsi/converter.rb', line 46 def html_converter(node) if node.nil? IsoDoc::BSI::HtmlConvert.new({}) else IsoDoc::BSI::HtmlConvert.new(html_extract_attributes(node)) end end |
#id_to_num(bib, ids) ⇒ Object
77 78 79 80 81 |
# File 'lib/asciidoctor/bsi/cleanup_ref.rb', line 77 def id_to_num(bib, ids) return "000000000" if bib["id"].nil? sprintf("%09d", ids[bib["id"]] || 0) end |
#image_name_validate(xmldoc) ⇒ Object
23 |
# File 'lib/asciidoctor/bsi/validate.rb', line 23 def image_name_validate(xmldoc); end |
#informative_text_style(root) ⇒ Object
Rules for Structure 7.2, 7.3, 24.5
35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/asciidoctor/bsi/validate_requirement.rb', line 35 def informative_text_style(root) root.xpath("//note | //admonition[@type = 'commentary'] | "\ "//annex[@obligation = 'informative']").each do |s| if r = requirement_check(extract_text(s)) style_warning(s, "#{@type} clause may contain requirement", r) end if r = recommendation_check(extract_text(s)) %w(code-of-practice guide).include?(@doctype) and style_warning(s, "#{@type} clause may contain recommendation", r) end end end |
#iso_id(node, xml) ⇒ Object
47 48 49 50 51 52 53 54 |
# File 'lib/asciidoctor/bsi/front.rb', line 47 def iso_id(node, xml) return unless node.attr("docnumber") part = node&.attr("partnumber") dn = add_id_parts(node.attr("docnumber"), part, nil) dn = id_stage_prefix(dn, node, false) xml.docidentifier dn, **attr_code(type: "BS") end |
#list_full_sentence(elem) ⇒ Object
60 61 62 63 64 65 66 67 68 69 |
# File 'lib/asciidoctor/bsi/validate_list.rb', line 60 def list_full_sentence(elem) text = elem.text.strip text.match?(/^[^A-Za-z]*[A-Z]/) or style_warning(elem, "List entry after full stop must start with "\ "uppercase letter", text) punct = text.sub(/^.*?(\S)\s*$/, "\\1") punct == "." or style_warning(elem, "List entry after full stop must "\ "end with full stop", text) end |
#list_punctuation(doc) ⇒ Object
Rules for Structure 23.5
19 20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/asciidoctor/bsi/validate_list.rb', line 19 def list_punctuation(doc) return if @novalid ((doc.xpath("//ol") - doc.xpath("//ul//ol | //ol//ol")) + (doc.xpath("//ul") - doc.xpath("//ul//ul | //ol//ul"))).each do |list| prec = list.previous_element prec&.name == "p" or style_warning(list, "All lists must be preceded by "\ "introductory phrase", nil) list_punctuation1(list, prec.text) end end |
#list_punctuation1(list, prectext) ⇒ Object
32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/asciidoctor/bsi/validate_list.rb', line 32 def list_punctuation1(list, prectext) entries = list.xpath(".//li") case prectext.sub(/^.*?(\S)\s*$/, "\\1") when ":" list.xpath(".//li").each_with_index do |li, i| list_semicolon_phrase(li, i == entries.size - 1) end when "." then entries.each { |li| list_full_sentence(li) } else style_warning(list, "All lists must be preceded by "\ "colon or full stop", prectext) end end |
#list_semicolon_phrase(elem, last) ⇒ Object
45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/asciidoctor/bsi/validate_list.rb', line 45 def list_semicolon_phrase(elem, last) text = elem.text.strip text.match?(/^[^A-Za-z]*[a-z]/) or style_warning(elem, "List entry after colon must start with "\ "lowercase letter", text) punct = text.sub(/^.*?(\S)\s*$/, "\\1") if last punct == "." or style_warning(elem, "Final list entry after colon "\ "must end with full stop", text) else punct == ";" or style_warning(elem, "List entry after colon must "\ "end with semicolon", text) end end |
#listcount_validate(doc) ⇒ Object
Rules for Structure 23.3
5 6 7 8 9 10 11 12 13 14 15 16 |
# File 'lib/asciidoctor/bsi/validate_list.rb', line 5 def listcount_validate(doc) return if @novalid doc.xpath("//clause[not(.//clause)] | //annex").each do |c| next if c.xpath(".//ol").empty? ols = c.xpath(".//ol") - c.xpath(".//ul//ol | .//ol//ol") ols.size > 3 and style_warning(c, "More than 3 ordered lists in a numbered clause", nil) end end |
#metadata_author(node, xml) ⇒ Object
8 9 10 11 12 13 14 15 16 17 18 |
# File 'lib/asciidoctor/bsi/front.rb', line 8 def (node, xml) publishers = node.attr("publisher") || "BSI" csv_split(publishers)&.each do |p| xml.contributor do |c| c.role **{ type: "author" } c.organization do |a| organization(a, p, node, !node.attr("publisher")) end end end end |
#metadata_copyright(node, xml) ⇒ Object
32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/asciidoctor/bsi/front.rb', line 32 def (node, xml) pub = node.attr("copyright-holder") || node.attr("publisher") || "BSI" csv_split(pub)&.each do |p| xml.copyright do |c| c.from (node.attr("copyright-year") || Date.today.year) c.owner do |owner| owner.organization do |o| organization(o, p, node, !node.attr("copyright-holder") || node.attr("publisher")) end end end end end |
#metadata_doctype(node, xml) ⇒ Object
56 57 58 |
# File 'lib/asciidoctor/bsi/front.rb', line 56 def (node, xml) xml.doctype doctype(node) end |
#metadata_publisher(node, xml) ⇒ Object
20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/asciidoctor/bsi/front.rb', line 20 def (node, xml) publishers = node.attr("publisher") || "BSI" csv_split(publishers)&.each do |p| xml.contributor do |c| c.role **{ type: "publisher" } c.organization do |a| organization(a, p, node, !node.attr("publisher")) end end end end |
#new_ref(title, norm) ⇒ Object
156 157 158 159 |
# File 'lib/asciidoctor/bsi/cleanup_ref.rb', line 156 def new_ref(title, norm) "<references normative='#{norm}' unnumbered='true'>"\ "<title>#{title}</title></references>" end |
#norm_bibitem_style(root) ⇒ Object
Rules for Structure 10.2
129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/asciidoctor/bsi/validate.rb', line 129 def norm_bibitem_style(root) root.xpath(NORM_BIBITEMS).each do |b| b.at(BSI_PUBLISHER_XPATH).nil? and @log.add("Style", b, "#{NORM_BSI_WARN}: #{b.text}") status = b&.at("./status/stage")&.text /^9.$/.match?(status) and @log.add("Style", b, "Do not cite withdrawn standards as normative: #{b.text}") /^[0-5].$/.match?(status) and @log.add( "Style", b, "Do not cite unpublished standards as normative: #{b.text}" ) end end |
#norm_ref_validate(doc) ⇒ Object
25 |
# File 'lib/asciidoctor/bsi/validate.rb', line 25 def norm_ref_validate(doc); end |
#normative_text_style(root) ⇒ Object
Rules for Structure 7.2
82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/asciidoctor/bsi/validate_requirement.rb', line 82 def normative_text_style(root) root.xpath("//sections/* | //annex[@obligation = 'normative']") .each do |s1| s = s1.dup s.xpath(".//note | .//admonition | .//example").each(&:remove) %w(code-of-practice guide).include?(@doctype) and r = requirement_check(extract_text(s)) and style_warning(s, "#{@type} clause may contain requirement", r) %w(specification method-of-specifying test-method) .include?(@doctype) and spec_normative_text_style(s) end end |
#normref_cleanup(xmldoc) ⇒ Object
Rules for Structure 15.4
142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/asciidoctor/bsi/cleanup_ref.rb', line 142 def normref_cleanup(xmldoc) (xmldoc) super xmldoc.xpath("//bibliography//references | //clause//references | "\ "//annex//references").each do |r| next if r["normative"] == "false" if r.at("./bibitem/docidentifier[@type = 'metanorma']") && r.at("./bibitem[not(docidentifier[@type = 'metanorma'])]") split_ref(r, true) end end end |
#note(node) ⇒ Object
TODO: we will not implement sections for now (Rules for Structure 6.4)
TODO: we will not implement access date for now (Rules for Structure 10.3)
23 24 25 26 |
# File 'lib/asciidoctor/bsi/converter.rb', line 23 def note(node) return commentary(node) if node.attr("type") == "commentary" super end |
#note_style(node) ⇒ Object
requirement language taken care of in informative_text_style
49 50 51 |
# File 'lib/asciidoctor/bsi/validate_requirement.rb', line 49 def note_style(node) style(node, extract_text(node)) end |
#ol_cleanup(doc) ⇒ Object
13 14 15 16 17 18 19 20 21 |
# File 'lib/asciidoctor/bsi/cleanup.rb', line 13 def ol_cleanup(doc) doc.xpath("//clause[not(.//clause)] | //annex | //preface/* | //note") .each do |c| (c.xpath(".//ol") - c.xpath(".//ul//ol | .//ol//ol")) .each_with_index do |l, i| ol_cleanup1(l, i) end end end |
#ol_cleanup1(list, idx) ⇒ Object
23 24 25 26 27 28 29 |
# File 'lib/asciidoctor/bsi/cleanup.rb', line 23 def ol_cleanup1(list, idx) styles = %w(alphabet arabic roman) list["type"] = styles[idx % styles.size] (list.xpath(".//ol") - list.xpath(".//ol//ol")).each do |l| ol_cleanup1(l, idx + 1) end end |
#ordinal_check(node) ⇒ Object
Rules for Structure 9.1
73 74 75 76 77 78 79 |
# File 'lib/asciidoctor/bsi/validate.rb', line 73 def ordinal_check(node) node.xpath(".//sup").each do |s| next unless %w(st nd rd th).include? s.text style_warning(s, "text contains ordinal superscript", s.text) end end |
#org_abbrev ⇒ Object
4 5 6 |
# File 'lib/asciidoctor/bsi/front.rb', line 4 def org_abbrev super.merge("British Standards Institute" => "BSI") end |
#pdf_converter(node) ⇒ Object
54 55 56 57 58 59 60 61 62 |
# File 'lib/asciidoctor/bsi/converter.rb', line 54 def pdf_converter(node) return if node.attr("no-pdf") if node.nil? IsoDoc::BSI::PdfConvert.new({}) else IsoDoc::BSI::PdfConvert.new(doc_extract_attributes(node)) end end |
#presentation_xml_converter(node) ⇒ Object
64 65 66 67 68 69 70 |
# File 'lib/asciidoctor/bsi/converter.rb', line 64 def presentation_xml_converter(node) if node.nil? IsoDoc::BSI::PresentationXMLConvert.new({}) else IsoDoc::BSI::PresentationXMLConvert.new(doc_extract_attributes(node)) end end |
#relaton_relations ⇒ Object
60 61 62 |
# File 'lib/asciidoctor/bsi/front.rb', line 60 def relaton_relations super + %w(obsoletes adopted-from) end |
#section_style(root) ⇒ Object
81 82 83 84 85 86 87 88 89 |
# File 'lib/asciidoctor/bsi/validate.rb', line 81 def section_style(root) super @doctype = root.at("//bibdata/ext/doctype")&.text @type = @doctype.gsub(/-/, " ").split.map(&:capitalize).join(" ") informative_text_style(root) normative_text_style(root) avoid_must(root) annex_validate(root) end |
#see_xrefs_validate(root) ⇒ Object
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/asciidoctor/bsi/validate_requirement.rb', line 106 def see_xrefs_validate(root) root.xpath("//xref").each do |t| (target = root.at("//*[@id = '#{t['target']}']")) || next if target.at("./ancestor-or-self::annex") xrefs_annex_validate(t, target) else preceding = t.at("./preceding-sibling::text()[last()]") next unless !preceding.nil? && /\b(see| refer to)\s*$/mi.match(preceding) if target&.at("./ancestor-or-self::*[@obligation = 'normative']") @log.add("Style", t, "'see #{t['target']}' is pointing "\ "to a normative section") end end end end |
#sort_biblio(bib) ⇒ Object
60 61 62 63 |
# File 'lib/asciidoctor/bsi/cleanup_ref.rb', line 60 def sort_biblio(bib) @sort_bib_by_appearance and sort_biblio_appearance(bib) or sort_norm_appearance(bib) end |
#sort_biblio_appearance(bib) ⇒ Object
83 84 85 86 87 88 |
# File 'lib/asciidoctor/bsi/cleanup_ref.rb', line 83 def sort_biblio_appearance(bib) ids = citation_order(bib) bib.sort do |a, b| id_to_num(a, ids) <=> id_to_num(b, ids) end end |
#sort_biblio_key(bib) ⇒ Object
Rules for Structure 15.4 Normative references ordering sort by: alphanumeric prefix, then docnumber if present, numeric sort
else alphanumeric metanorma id (abbreviation)
then doc part number if present, numeric sort then doc id (not DOI &c) then title
109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/asciidoctor/bsi/cleanup_ref.rb', line 109 def sort_biblio_key(bib) num = bib&.at("./docnumber")&.text id = bib&.at("./docidentifier[not(#{OTHERIDS})]") = bib&.at("./docidentifier[@type = 'metanorma']")&.text abbrid = unless /^\[\d+\]$/.match?() /\d-(?<partid>\d+)/ =~ id&.text type = id["type"] if id title = bib&.at("./title[@type = 'main']")&.text || bib&.at("./title")&.text || bib&.at("./formattedref")&.text "#{type} :: "\ "#{num.nil? ? abbrid : sprintf('%09d', num.to_i)} :: "\ "#{partid} :: #{id&.text} :: #{title}" end |
#sort_norm_appearance(bib) ⇒ Object
90 91 92 93 94 95 96 97 98 99 |
# File 'lib/asciidoctor/bsi/cleanup_ref.rb', line 90 def sort_norm_appearance(bib) ids = citation_order(bib) bib.each do |b| ids[b["id"]] = 0 unless b.at("./docidentifier[@type = 'metanorma']") end bib.sort do |a, b| "#{id_to_num(a, ids)} :: #{sort_biblio_key(a)}" <=> "#{id_to_num(b, ids)} :: #{sort_biblio_key(b)}" end end |
#spec_normative_text_style(node) ⇒ Object
Rules for Structure 7.3, 7.4, 7.5
96 97 98 99 100 101 102 103 104 |
# File 'lib/asciidoctor/bsi/validate_requirement.rb', line 96 def spec_normative_text_style(node) r = recommendation_check(extract_text(node)) r and style_warning(node, "#{@type} clause may contain recommendation", r) r = (extract_text(node)) r and style_warning(node, "#{@type} clause may contain permission", r) r = possibility_check(extract_text(node)) r and style_warning(node, "#{@type} clause may contain possibility", r) end |
#split_ref(ref, norm) ⇒ Object
161 162 163 164 165 166 167 168 |
# File 'lib/asciidoctor/bsi/cleanup_ref.rb', line 161 def split_ref(ref, norm) std = ref.add_child(new_ref("Standards publications", norm)).first other = ref.add_child(new_ref("Other publications", norm)).first ref.xpath("./bibitem").each do |b| b.parent = b.at("./docidentifier[@type = 'metanorma']") ? other : std end end |
#sts_converter(node) ⇒ Object
72 73 74 75 76 77 78 79 80 |
# File 'lib/asciidoctor/bsi/converter.rb', line 72 def sts_converter(node) return if node.attr("no-pdf") if node.nil? IsoDoc::BSI::StsConvert.new({}) else IsoDoc::BSI::StsConvert.new(html_extract_attributes(node)) end end |
#style(node, text) ⇒ Object
27 28 29 30 31 |
# File 'lib/asciidoctor/bsi/validate.rb', line 27 def style(node, text) super style_plusminus(node, text) style_subscript(node) end |
#style_number(node, text) ⇒ Object
protest decimal comma not decimal point TODO we will not yet override decimal comma warning if this is a National Annex to Eurocode (Rules for Structure Annex B)
59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/asciidoctor/bsi/validate.rb', line 59 def style_number(node, text) style_two_regex_not_prev( node, text, /^(?<num>-?[0-9]{4,}[,0-9]*)$/, %r{\b(ISO|IEC|IEEE/|(in|January|February|March|April|May|June|August|September|October|November|December)\b)$}, "number not broken up in threes" ) style_regex(/\b(?<num>[0-9]+,[0-9]+)/i, "possible decimal comma", node, text) style_regex(/\b(?<num>billions?)\b/i, "ambiguous number", node, text) ordinal_check(node) end |
#style_plusminus(node, text) ⇒ Object
Rules for Structure 27.5
34 35 36 37 38 39 |
# File 'lib/asciidoctor/bsi/validate.rb', line 34 def style_plusminus(node, text) style_regex(/\s*(?<num>\S+\u00b1\s*\S+)/, "no space before plus-minus sign", node, text) style_regex(/\s*(?<num>\S+\s*\u00b1\s+\S+)/, "space after plus-minus sign", node, text) end |
#style_subscript(node) ⇒ Object
Rules for Structure 27.6
42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/asciidoctor/bsi/validate.rb', line 42 def style_subscript(node) node.xpath(".//sub[.//sub]").each do |r| style_warning(node, "Nested subscript", r) end node.xpath(".//m:msub[.//m:msub]", "m" => MATHML_NS).each do |r| style_warning(node, "Nested subscript", r) end node.xpath(".//sup[.//sup]").each do |r| style_warning(node, "Nested superscript", r) end node.xpath(".//m:msup[.//m:msup]", "m" => MATHML_NS).each do |r| style_warning(node, "Nested superscript", r) end end |
#subclause_validate(root) ⇒ Object
Rules for Structure 22.3.2
196 197 198 199 200 201 202 203 |
# File 'lib/asciidoctor/bsi/validate.rb', line 196 def subclause_validate(root) return if @novalid root.xpath("//clause/clause/clause/clause/clause/clause") .each do |c| style_warning(c, "Exceeds the maximum clause depth of 5", nil) end end |
#symbol_style(xmldoc) ⇒ Object
Rules for Structure 17.5
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
# File 'lib/asciidoctor/bsi/validate.rb', line 179 def symbol_style(xmldoc) return if @novalid xmldoc.xpath("//definitions//dd").each do |para| term = para&.at("./preceding::dt[1]")&.text&.strip || "[symbol]" termdef_warn(para.text, /^(the|a)\b/i, para, term, "symbol definition starts with article") termdef_warn(para.text, /\.$/i, para, term, "symbol definition ends with period") termdef_warn(para.text, /^[A-Z]/, para, term, "symbol definition starts with upper case character") termdef_warn(para.text, /\b#{term.downcase}\b/i, para, term, "symbol definition may be circular") end end |
#table_footnote_renumber1(fn, i, seen) ⇒ Object
58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/asciidoctor/bsi/cleanup.rb', line 58 def table_footnote_renumber1(fn, i, seen) content = footnote_content(fn) if seen[content] then outnum = seen[content] else i += 1 outnum = i seen[content] = outnum end fn["reference"] = (outnum - 1 + "A".ord).chr fn["table"] = true [i, seen] end |
#table_validate(xmldoc) ⇒ Object
Rules for Structure 29.6
206 207 208 209 210 211 |
# File 'lib/asciidoctor/bsi/validate.rb', line 206 def table_validate(xmldoc) xmldoc.xpath("//td[not(./*) and normalize-space(.)=''] | "\ "//th[not(./*) and normalize-space(.)='']").each do |td| style_warning(td, "Empty table cell", nil) end end |
#tech_report_style(root) ⇒ Object
Rules for Structure 7.2
32 |
# File 'lib/asciidoctor/bsi/validate_requirement.rb', line 32 def tech_report_style(root); end |
#termdef_style(xmldoc) ⇒ Object
Rules for Structure 16.5.5
158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/asciidoctor/bsi/validate.rb', line 158 def termdef_style(xmldoc) super xmldoc.xpath("//term").each do |t| para = t.at("./definition") || return term = t.at("./preferred").text.strip termdef_warn(para.text, /^[A-Z]/, t, term, "term definition starts with upper case character") termdef_warn(para.text, /\b#{term.downcase}\b/i, t, term, "term definition may be circular") end end |
#title_names_type_validate(root) ⇒ Object
Rules for Structure 11.5.2
145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/asciidoctor/bsi/validate.rb', line 145 def title_names_type_validate(root) super doctypes = /British\sStandard/xi title_main_en = title_lang_part(root, "main", "en") !title_main_en.nil? && doctypes.match(title_main_en.text) and @log.add("Style", title_main_en, "Main Title may name document type") title_intro_en = title_lang_part(root, "intro", "en") !title_intro_en.nil? && doctypes.match(title_intro_en.text) and @log.add("Style", title_intro_en, "Title Intro may name document type") end |
#validate(doc) ⇒ Object
17 18 19 20 21 |
# File 'lib/asciidoctor/bsi/validate.rb', line 17 def validate(doc) content_validate(doc) schema_validate(formattedstr_strip(doc.dup), File.join(File.dirname(__FILE__), "bsi.rng")) end |
#xrefs_annex_validate(xref, target) ⇒ Object
Rules for Structure 20.5
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/asciidoctor/bsi/validate_requirement.rb', line 129 def xrefs_annex_validate(xref, target) normative = !target&.at("./ancestor-or-self::*"\ "[@obligation='normative']").nil? clause = xref.at(PARENT_PARA) or return prec = (clause&.children & xref&.xpath("./preceding::text()")) &.text&.split(/\.\s*(?=[A-Z])/m)[-1]&.strip foll = (clause.children & xref.xpath("./following::text()")) &.text&.split(/\.\s*(?=[A-Z])/m)[0]&.strip text = "#{prec} XREF #{foll}".strip if %w(specification method-of-specifying).include?(@doctype) && normative requirement_re.match?(text) or style_warning(xref, "#{@type} must cite normative "\ "annex as requirement", text) elsif @doctype == "code-of-practice" && normative recommendation_re.match?(text) or style_warning(xref, "#{@type} must cite normative "\ "annex as recommendation", text) elsif %w(specification method-of-specifying).include?(@doctype) && !normative (recommendation_re.match?(text) || (!requirement_re.match?(text) && !.match?(text) && !possibility_re.match?(text))) or style_warning(xref, "#{@type} must cite informative annex as "\ "recommendation or statement", text) elsif %w(code-of-practice guide).include?(@doctype) && !normative (!recommendation_re.match?(text) && !requirement_re.match?(text) && !.match?(text) && !possibility_re.match?(text)) or style_warning(xref, "#{@type} must cite informative annex as "\ "statement", text) end end |