Class: Asciidoctor::ISO::Converter
- Inherits:
-
Standoc::Converter
- Object
- Standoc::Converter
- Asciidoctor::ISO::Converter
- Defined in:
- lib/asciidoctor/iso/converter.rb,
lib/asciidoctor/iso/base.rb,
lib/asciidoctor/iso/front.rb,
lib/asciidoctor/iso/cleanup.rb,
lib/asciidoctor/iso/section.rb,
lib/asciidoctor/iso/validate.rb,
lib/asciidoctor/iso/validate_style.rb,
lib/asciidoctor/iso/validate_section.rb,
lib/asciidoctor/iso/validate_requirements.rb
Overview
A Converter implementation that generates ISO output, and a document schema encapsulation of the document for validation
Constant Summary collapse
- PRE_NORMREF_FOOTNOTES =
"//foreword//fn | //introduction//fn |"\ "//clause[title = 'Scope']//fn" .freeze
- NORMREF_FOOTNOTES =
"//references[title = 'Normative References']//fn".freeze
- POST_NORMREF_FOOTNOTES =
"//clause[not(title = 'Scope')]//fn | "\ "//references[title = 'Bibliography']//fn".freeze
- SI_UNIT =
leaving out as problematic: N J K C S T H h d B o E
"(m|cm|mm|km|μm|nm|g|kg|mgmol|cd|rad|sr|Hz|Hz|MHz|Pa|hPa|kJ|"\ "V|kV|W|MW|kW|F|μF|Ω|Wb|°C|lm|lx|Bq|Gy|Sv|kat|l|t|eV|u|Np|Bd|"\ "bit|kB|MB|Hart|nat|Sh|var)".freeze
- NONSTD_UNITS =
{ "sec": "s", "mins": "min", "hrs": "h", "hr": "h", "cc": "cm^3", "lit": "l", "amp": "A", "amps": "A", "rpm": "r/min" }.freeze
- ONE_SYMBOLS_WARNING =
"ISO style: only one Symbols and Abbreviated "\ "Terms section in the standard".freeze
- NON_DL_SYMBOLS_WARNING =
"ISO style: Symbols and Abbreviated Terms can "\ "only contain a definition list".freeze
- SEQ =
spec of permissible section sequence we skip normative references, it goes to end of list
[ { msg: "Initial section must be (content) Foreword", val: [{ tag: "foreword", title: "Foreword" }], }, { msg: "Prefatory material must be followed by (clause) Scope", val: [{ tag: "introduction", title: "Introduction" }, { tag: "clause", title: "Scope" }], }, { msg: "Prefatory material must be followed by (clause) Scope", val: [{ tag: "clause", title: "Scope" }], }, { msg: "Normative References must be followed by "\ "Terms and Definitions", val: [ { tag: "terms", title: "Terms and definitions" }, { tag: "clause", title: "Terms and definitions" }, { tag: "terms", title: "Terms, definitions, symbols and abbreviated terms", }, { tag: "clause", title: "Terms, definitions, symbols and abbreviated terms", }, ], }, ].freeze
- SECTIONS_XPATH =
"//foreword | //introduction | //sections/terms | .//annex | "\ "//sections/definitions | //sections/clause | //references[not(parent::clause)] | "\ "//clause[descendant::references][not(parent::clause)]".freeze
- NORM_ISO_WARN =
"non-ISO/IEC reference not expected as normative".freeze
- SCOPE_WARN =
"Scope contains subclauses: should be succint".freeze
- ASSETS_TO_STYLE =
"//termsource | //formula | //termnote | //p | //li[not(p)] | "\ "//dt | //dd[not(p)] | //td[not(p)] | //th[not(p)]".freeze
- NORM_BIBITEMS =
"//references[title = 'Normative References']/bibitem".freeze
- REQUIREMENT_RE_STR =
<<~REGEXP.freeze \\b ( shall | (is|are)_to | (is|are)_required_(not_)?to | (is|are)_required_that | has_to | only\\b[^.,]+\\b(is|are)_permitted | it_is_necessary | (is|are)_not_(allowed | permitted | acceptable | permissible) | (is|are)_not_to_be | do_not ) \\b REGEXP
- REQUIREMENT_RE =
Regexp.new(REQUIREMENT_RE_STR.gsub(/\s/, "").gsub(/_/, "\\s"), Regexp::IGNORECASE)
- RECOMMENDATION_RE_STR =
<<~REGEXP.freeze \\b should | ought_(not_)?to | it_is_(not_)?recommended_that \\b REGEXP
- RECOMMENDATION_RE =
Regexp.new(RECOMMENDATION_RE_STR.gsub(/\s/, "").gsub(/_/, "\\s"), Regexp::IGNORECASE)
- PERMISSION_RE_STR =
<<~REGEXP.freeze \\b may | (is|are)_(permitted | allowed | permissible ) | it_is_not_required_that | no\\b[^.,]+\\b(is|are)_required \\b REGEXP
- PERMISSION_RE =
Regexp.new(PERMISSION_RE_STR.gsub(/\s/, "").gsub(/_/, "\\s"), Regexp::IGNORECASE)
- POSSIBILITY_RE_STR =
<<~REGEXP.freeze \\b can | cannot | be_able_to | there_is_a_possibility_of | it_is_possible_to | be_unable_to | there_is_no_possibility_of | it_is_not_possible_to \\b REGEXP
- POSSIBILITY_RE =
Regexp.new(POSSIBILITY_RE_STR.gsub(/\s/, "").gsub(/_/, "\\s"), Regexp::IGNORECASE)
Instance Method Summary collapse
- #add_id_parts(dn, part, subpart) ⇒ Object
- #appendix_parse(attrs, xml, node) ⇒ Object
- #asset_style(root) ⇒ Object
- #bibdata_validate(doc) ⇒ Object
- #cited_term_style(xmldoc) ⇒ Object
- #content_validate(doc) ⇒ Object
- #definition_style(node) ⇒ Object
- #doc_converter(node) ⇒ Object
-
#docidentifier_cleanup(xmldoc) ⇒ Object
ISO as a prefix goes first.
- #doctype_validate(xmldoc) ⇒ Object
- #document(node) ⇒ Object
- #example_style(node) ⇒ Object
- #external_constraint(text) ⇒ Object
- #extract_text(node) ⇒ Object
- #footnote_style(node) ⇒ Object
- #foreword_style(node) ⇒ Object
- #foreword_validate(root) ⇒ Object
- #get_id_prefix(xmldoc) ⇒ Object
- #get_stage(node) ⇒ Object
- #get_substage(node) ⇒ Object
- #html_converter(node) ⇒ Object
- #html_converter_alt(node) ⇒ Object
- #id_prefix(prefix, id) ⇒ Object
- #id_stage_prefix(dn, node) ⇒ Object
- #introduction_style(node) ⇒ Object
- #iso_id(node, xml) ⇒ Object
- #isosubgroup_validate(root) ⇒ Object
- #iteration_validate(xmldoc) ⇒ Object
- #locality_erefs_validate(root) ⇒ Object
- #makexml1(node) ⇒ Object
- #metadata_author(node, xml) ⇒ Object
- #metadata_committee(node, xml) ⇒ Object
- #metadata_copyright(node, xml) ⇒ Object
- #metadata_ext(node, xml) ⇒ Object
- #metadata_id(node, xml) ⇒ Object
- #metadata_publisher(node, xml) ⇒ Object
- #metadata_status(node, xml) ⇒ Object
- #norm_bibitem_style(root) ⇒ Object
- #normref_validate(root) ⇒ Object
- #note_style(node) ⇒ Object
- #onlychild_clause_validate(root) ⇒ Object
- #organization(org, orgname) ⇒ Object
- #other_footnote_renumber(xmldoc) ⇒ Object
- #patent_notice_parse(xml, node) ⇒ Object
- #permission_check(text) ⇒ Object
- #possibility(text) ⇒ Object
- #recommendation_check(text) ⇒ Object
- #requirement_check(text) ⇒ Object
- #scope_parse(attrs, xml, node) ⇒ Object
- #scope_style(node) ⇒ Object
- #script_validate(xmldoc) ⇒ Object
- #section(node) ⇒ Object
- #section_style(root) ⇒ Object
- #section_validate(doc) ⇒ Object
- #sections_sequence_validate(root) ⇒ Object
- #see_erefs_validate(root) ⇒ Object
- #see_xrefs_validate(root) ⇒ Object
- #seqcheck(names, msg, accepted) ⇒ Object
- #stage_validate(xmldoc) ⇒ Object
- #structured_id(node, xml) ⇒ Object
- #style(n, t) ⇒ Object
- #style_abbrev(n, t) ⇒ Object
- #style_no_guidance(node, text, docpart) ⇒ Object
- #style_non_std_units(n, t) ⇒ Object
- #style_number(n, t) ⇒ Object
- #style_percent(n, t) ⇒ Object
- #style_regex(re, warning, n, text) ⇒ Object
-
#style_two_regex_not_prev(n, text, re, re_prev, warning) ⇒ Object
style check with a regex on a token and a negative match on its preceding token.
- #style_units(n, t) ⇒ Object
- #style_warning(node, msg, text) ⇒ Object
- #subclause_validate(root) ⇒ Object
- #substage_validate(xmldoc) ⇒ Object
- #symbols_validate(root) ⇒ Object
- #termdef_style(xmldoc) ⇒ Object
- #termdef_warn(text, re, term, msg) ⇒ Object
- #title(node, xml) ⇒ Object
- #title_all_siblings(xpath, label) ⇒ Object
- #title_first_level_validate(root) ⇒ Object
- #title_full(node, t, lang, at) ⇒ Object
- #title_intro(node, t, lang, at) ⇒ Object
- #title_intro_validate(root) ⇒ Object
- #title_main(node, t, lang, at) ⇒ Object
- #title_main_validate(root) ⇒ Object
- #title_names_type_validate(root) ⇒ Object
- #title_part(node, t, lang, at) ⇒ Object
- #title_part_validate(root) ⇒ Object
- #title_subpart_validate(root) ⇒ Object
- #title_validate(root) ⇒ Object
- #validate(doc) ⇒ Object
Instance Method Details
#add_id_parts(dn, part, subpart) ⇒ Object
42 43 44 45 46 |
# File 'lib/asciidoctor/iso/front.rb', line 42 def add_id_parts(dn, part, subpart) dn += "-#{part}" if part dn += "-#{subpart}" if subpart dn end |
#appendix_parse(attrs, xml, node) ⇒ Object
44 45 46 47 48 49 50 51 |
# File 'lib/asciidoctor/iso/section.rb', line 44 def appendix_parse(attrs, xml, node) attrs["inline-header".to_sym] = node.option? "inline-header" set_obligation(attrs, node) xml.appendix **attr_code(attrs) do |xml_section| xml_section.title { |name| name << node.title } xml_section << node.content end end |
#asset_style(root) ⇒ Object
178 179 180 181 182 183 184 185 186 |
# File 'lib/asciidoctor/iso/validate_section.rb', line 178 def asset_style(root) root.xpath("//example | //termexample").each { |e| example_style(e) } root.xpath("//definition").each { |e| definition_style(e) } root.xpath("//note").each { |e| note_style(e) } root.xpath("//fn").each { |e| footnote_style(e) } root.xpath(ASSETS_TO_STYLE).each { |e| style(e, extract_text(e)) } norm_bibitem_style(root) super end |
#bibdata_validate(doc) ⇒ Object
219 220 221 222 223 224 225 |
# File 'lib/asciidoctor/iso/validate.rb', line 219 def bibdata_validate(doc) doctype_validate(doc) script_validate(doc) stage_validate(doc) substage_validate(doc) iteration_validate(doc) end |
#cited_term_style(xmldoc) ⇒ Object
178 179 180 181 182 183 184 185 |
# File 'lib/asciidoctor/iso/validate.rb', line 178 def cited_term_style(xmldoc) xmldoc.xpath("//term//xref").each do |x| next unless xmldoc.at("//term[@id = '#{x['target']}']") x&.previous&.text == " (" and x&.previous&.previous&.name == "em" or style_warning(x, "term citation not preceded with italicised term", x.parent.text) end end |
#content_validate(doc) ⇒ Object
227 228 229 230 231 232 233 234 235 236 237 238 |
# File 'lib/asciidoctor/iso/validate.rb', line 227 def content_validate(doc) super title_validate(doc.root) isosubgroup_validate(doc.root) onlychild_clause_validate(doc.root) termdef_style(doc.root) iev_validate(doc.root) see_xrefs_validate(doc.root) see_erefs_validate(doc.root) locality_erefs_validate(doc.root) bibdata_validate(doc.root) end |
#definition_style(node) ⇒ Object
33 34 35 36 37 |
# File 'lib/asciidoctor/iso/validate_style.rb', line 33 def definition_style(node) return if @novalid r = requirement_check(extract_text(node)) style_warning(node, "Definition may contain requirement", r) if r end |
#doc_converter(node) ⇒ Object
22 23 24 |
# File 'lib/asciidoctor/iso/base.rb', line 22 def doc_converter(node) IsoDoc::Iso::WordConvert.new(doc_extract_attributes(node)) end |
#docidentifier_cleanup(xmldoc) ⇒ Object
ISO as a prefix goes first
51 52 53 54 55 56 57 |
# File 'lib/asciidoctor/iso/cleanup.rb', line 51 def docidentifier_cleanup(xmldoc) prefix = get_id_prefix(xmldoc) id = xmldoc.at("//bibdata/docidentifier[@type = 'iso']") or return id.content = id_prefix(prefix, id) id = xmldoc.at("//bibdata/ext/structuredidentifier/project-number") or return id.content = id_prefix(prefix, id) end |
#doctype_validate(xmldoc) ⇒ Object
187 188 189 190 191 192 193 |
# File 'lib/asciidoctor/iso/validate.rb', line 187 def doctype_validate(xmldoc) doctype = xmldoc&.at("//bibdata/ext/doctype")&.text %w(international-standard technical-specification technical-report publicly-available-specification international-workshop-agreement guide).include? doctype or warn "ISO Document Attributes: #{doctype} is not a recognised document type" end |
#document(node) ⇒ Object
26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/asciidoctor/iso/base.rb', line 26 def document(node) init(node) ret = makexml(node).to_xml(indent: 2) unless node.attr("nodoc") || !node.attr("docfile") File.open(@filename + ".xml", "w:UTF-8") { |f| f.write(ret) } html_converter_alt(node).convert(@filename + ".xml") FileUtils.mv "#{@filename}.html", "#{@filename}_alt.html" html_converter(node).convert(@filename + ".xml") doc_converter(node).convert(@filename + ".xml") end @files_to_delete.each { |f| FileUtils.rm f } ret end |
#example_style(node) ⇒ Object
39 40 41 42 43 |
# File 'lib/asciidoctor/iso/validate_style.rb', line 39 def example_style(node) return if @novalid style_no_guidance(node, extract_text(node), "Term Example") style(node, extract_text(node)) end |
#external_constraint(text) ⇒ Object
88 89 90 91 92 93 |
# File 'lib/asciidoctor/iso/validate_requirements.rb', line 88 def external_constraint(text) text.split(/\.\s+/).each do |t| return t if /\b(must)\b/xi.match t end nil end |
#extract_text(node) ⇒ Object
8 9 10 11 12 13 14 15 |
# File 'lib/asciidoctor/iso/validate_style.rb', line 8 def extract_text(node) return "" if node.nil? node1 = Nokogiri::XML.fragment(node.to_s) node1.xpath("//link | //locality").each(&:remove) ret = "" node1.traverse { |x| ret += x.text if x.text? } ret end |
#footnote_style(node) ⇒ Object
51 52 53 54 55 |
# File 'lib/asciidoctor/iso/validate_style.rb', line 51 def footnote_style(node) return if @novalid style_no_guidance(node, extract_text(node), "Footnote") style(node, extract_text(node)) end |
#foreword_style(node) ⇒ Object
17 18 19 20 |
# File 'lib/asciidoctor/iso/validate_style.rb', line 17 def foreword_style(node) return if @novalid style_no_guidance(node, extract_text(node), "Foreword") end |
#foreword_validate(root) ⇒ Object
16 17 18 19 20 |
# File 'lib/asciidoctor/iso/validate_section.rb', line 16 def foreword_validate(root) f = root.at("//foreword") || return s = f.at("./clause") warn "ISO style: foreword contains subclauses" unless s.nil? end |
#get_id_prefix(xmldoc) ⇒ Object
40 41 42 43 44 45 46 47 48 |
# File 'lib/asciidoctor/iso/cleanup.rb', line 40 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 == "ISO" and prefix.unshift("ISO") or prefix << x1 end prefix end |
#get_stage(node) ⇒ Object
108 109 110 |
# File 'lib/asciidoctor/iso/front.rb', line 108 def get_stage(node) stage = node.attr("status") || node.attr("docstage") || "60" end |
#get_substage(node) ⇒ Object
112 113 114 115 |
# File 'lib/asciidoctor/iso/front.rb', line 112 def get_substage(node) stage = get_stage(node) node.attr("docsubstage") || ( stage == "60" ? "60" : "00" ) end |
#html_converter(node) ⇒ Object
13 14 15 |
# File 'lib/asciidoctor/iso/base.rb', line 13 def html_converter(node) IsoDoc::Iso::HtmlConvert.new(html_extract_attributes(node)) end |
#html_converter_alt(node) ⇒ Object
17 18 19 20 |
# File 'lib/asciidoctor/iso/base.rb', line 17 def html_converter_alt(node) IsoDoc::Iso::HtmlConvert.new(html_extract_attributes(node). merge(alt: true)) end |
#id_prefix(prefix, id) ⇒ Object
36 37 38 |
# File 'lib/asciidoctor/iso/cleanup.rb', line 36 def id_prefix(prefix, id) prefix.join("/") + ( id.text.match(%{^/}) ? "" : " " ) + id.text end |
#id_stage_prefix(dn, node) ⇒ Object
48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/asciidoctor/iso/front.rb', line 48 def id_stage_prefix(dn, node) stage = get_stage(node) substage = get_substage(node) if stage && (stage.to_i < 60 || stage.to_i == 60 && substage.to_i < 60) abbr = IsoDoc::Iso::Metadata.new("en", "Latn", {}). stage_abbrev(stage, substage, node.attr("iteration"), node.attr("draft")) dn = "/#{abbr} #{dn}" # prefixes added in cleanup else dn += ":#{node.attr("copyright-year")}" if node.attr("copyright-year") end dn end |
#introduction_style(node) ⇒ Object
27 28 29 30 31 |
# File 'lib/asciidoctor/iso/validate_style.rb', line 27 def introduction_style(node) return if @novalid r = requirement_check(extract_text(node)) style_warning(node, "Introduction may contain requirement", r) if r end |
#iso_id(node, xml) ⇒ Object
20 21 22 23 24 25 26 |
# File 'lib/asciidoctor/iso/front.rb', line 20 def iso_id(node, xml) return unless node.attr("docnumber") part, subpart = node&.attr("partnumber")&.split(/-/) dn = add_id_parts(node.attr("docnumber"), part, subpart) dn = id_stage_prefix(dn, node) xml.docidentifier dn, **attr_code(type: "iso") end |
#isosubgroup_validate(root) ⇒ Object
111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/asciidoctor/iso/validate.rb', line 111 def isosubgroup_validate(root) root.xpath("//technical-committee/@type").each do |t| unless %w{TC PC JTC JPC}.include? t.text warn "ISO: invalid technical committee type #{t}" end end root.xpath("//subcommittee/@type").each do |t| unless %w{SC JSC}.include? t.text warn "ISO: invalid subcommittee type #{t}" end end end |
#iteration_validate(xmldoc) ⇒ Object
213 214 215 216 217 |
# File 'lib/asciidoctor/iso/validate.rb', line 213 def iteration_validate(xmldoc) iteration = xmldoc&.at("//bibdata/status/iteration")&.text or return /^\d+/.match(iteration) or warn "ISO Document Attributes: #{iteration} is not a recognised iteration" end |
#locality_erefs_validate(root) ⇒ Object
151 152 153 154 155 156 157 158 159 160 |
# File 'lib/asciidoctor/iso/validate.rb', line 151 def locality_erefs_validate(root) root.xpath("//eref[locality]").each do |t| if /^(ISO|IEC)/.match t["citeas"] unless /:[ ]?(\d+{4}|--)$/.match t["citeas"] warn "ISO: undated reference #{t['citeas']} should not contain "\ "specific elements" end end end end |
#makexml1(node) ⇒ Object
40 41 42 43 44 45 46 |
# File 'lib/asciidoctor/iso/base.rb', line 40 def makexml1(node) result = ["<?xml version='1.0' encoding='UTF-8'?>\n<iso-standard>"] result << noko { |ixml| front node, ixml } result << noko { |ixml| middle node, ixml } result << "</iso-standard>" textcleanup(result) end |
#metadata_author(node, xml) ⇒ Object
76 77 78 79 80 81 82 83 84 |
# File 'lib/asciidoctor/iso/front.rb', line 76 def (node, xml) publishers = node.attr("publisher") || "ISO" publishers.split(/,[ ]?/).each do |p| xml.contributor do |c| c.role **{ type: "author" } c.organization { |a| organization(a, p) } end end end |
#metadata_committee(node, xml) ⇒ Object
125 126 127 128 129 130 131 132 |
# File 'lib/asciidoctor/iso/front.rb', line 125 def (node, xml) xml.editorialgroup do |a| committee_component("technical-committee", node, a) committee_component("subcommittee", node, a) committee_component("workgroup", node, a) node.attr("secretariat") && a.secretariat(node.attr("secretariat")) end end |
#metadata_copyright(node, xml) ⇒ Object
96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/asciidoctor/iso/front.rb', line 96 def (node, xml) publishers = node.attr("publisher") || "ISO" publishers.split(/,[ ]?/).each do |p| xml.copyright do |c| c.from (node.attr("copyright-year") || Date.today.year) c.owner do |owner| owner.organization { |o| organization(o, p) } end end end end |
#metadata_ext(node, xml) ⇒ Object
28 29 30 31 |
# File 'lib/asciidoctor/iso/front.rb', line 28 def (node, xml) super structured_id(node, xml) end |
#metadata_id(node, xml) ⇒ Object
12 13 14 15 16 17 18 |
# File 'lib/asciidoctor/iso/front.rb', line 12 def (node, xml) iso_id(node, xml) node.attr("tc-docnumber") and xml.docidentifier(node.attr("tc-docnumber"), **attr_code(type: "iso-tc")) xml.docnumber node&.attr("docnumber") end |
#metadata_publisher(node, xml) ⇒ Object
86 87 88 89 90 91 92 93 94 |
# File 'lib/asciidoctor/iso/front.rb', line 86 def (node, xml) publishers = node.attr("publisher") || "ISO" publishers.split(/,[ ]?/).each do |p| xml.contributor do |c| c.role **{ type: "publisher" } c.organization { |a| organization(a, p) } end end end |
#metadata_status(node, xml) ⇒ Object
117 118 119 120 121 122 123 |
# File 'lib/asciidoctor/iso/front.rb', line 117 def (node, xml) xml.status do |s| s.stage get_stage(node) s.substage get_substage(node) node.attr("iteration") && (s.iteration node.attr("iteration")) end end |
#norm_bibitem_style(root) ⇒ Object
170 171 172 173 174 175 176 |
# File 'lib/asciidoctor/iso/validate_section.rb', line 170 def norm_bibitem_style(root) root.xpath(NORM_BIBITEMS).each do |b| if b.at(Standoc::Converter::ISO_PUBLISHER_XPATH).nil? Standoc::Utils::warning(b, NORM_ISO_WARN, b.text) end end end |
#normref_validate(root) ⇒ Object
22 23 24 25 26 |
# File 'lib/asciidoctor/iso/validate_section.rb', line 22 def normref_validate(root) f = root.at("//references[title = 'Normative References']") || return f.at("./references | ./clause") && warn("ISO style: normative references contains subclauses") end |
#note_style(node) ⇒ Object
45 46 47 48 49 |
# File 'lib/asciidoctor/iso/validate_style.rb', line 45 def note_style(node) return if @novalid style_no_guidance(node, extract_text(node), "Note") style(node, extract_text(node)) end |
#onlychild_clause_validate(root) ⇒ Object
101 102 103 104 105 106 107 108 109 |
# File 'lib/asciidoctor/iso/validate.rb', line 101 def onlychild_clause_validate(root) root.xpath(Standoc::Utils::SUBCLAUSE_XPATH).each do |c| next unless c.xpath("../clause").size == 1 title = c.at("./title") location = c["id"] || c.text[0..60] + "..." location += ":#{title.text}" if c["id"] && !title.nil? warn "ISO style: #{location}: subclause is only child" end end |
#organization(org, orgname) ⇒ Object
62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/asciidoctor/iso/front.rb', line 62 def organization(org, orgname) if ["ISO", "International Organization for Standardization"].include? orgname org.name "International Organization for Standardization" org.abbreviation "ISO" elsif ["IEC", "International Electrotechnical Commission"].include? orgname org.name "International Electrotechnical Commission" org.abbreviation "IEC" else org.name orgname end end |
#other_footnote_renumber(xmldoc) ⇒ Object
22 23 24 25 26 27 28 29 30 31 32 33 34 |
# File 'lib/asciidoctor/iso/cleanup.rb', line 22 def other_footnote_renumber(xmldoc) seen = {} i = 0 xmldoc.xpath(PRE_NORMREF_FOOTNOTES).each do |fn| i, seen = other_footnote_renumber1(fn, i, seen) end xmldoc.xpath(NORMREF_FOOTNOTES).each do |fn| i, seen = other_footnote_renumber1(fn, i, seen) end xmldoc.xpath(POST_NORMREF_FOOTNOTES).each do |fn| i, seen = other_footnote_renumber1(fn, i, seen) end end |
#patent_notice_parse(xml, node) ⇒ Object
53 54 55 56 57 58 |
# File 'lib/asciidoctor/iso/section.rb', line 53 def patent_notice_parse(xml, node) # xml.patent_notice do |xml_section| # xml_section << node.content # end xml << node.content end |
#permission_check(text) ⇒ Object
63 64 65 66 67 68 |
# File 'lib/asciidoctor/iso/validate_requirements.rb', line 63 def (text) text.split(/\.\s+/).each do |t| return t if PERMISSION_RE.match t end nil end |
#possibility(text) ⇒ Object
83 84 85 86 |
# File 'lib/asciidoctor/iso/validate_requirements.rb', line 83 def possibility(text) text.split(/\.\s+/).each { |t| return t if POSSIBILITY_RE.match t } nil end |
#recommendation_check(text) ⇒ Object
44 45 46 47 48 49 |
# File 'lib/asciidoctor/iso/validate_requirements.rb', line 44 def recommendation_check(text) text.split(/\.\s+/).each do |t| return t if RECOMMENDATION_RE.match t end nil end |
#requirement_check(text) ⇒ Object
26 27 28 29 30 31 |
# File 'lib/asciidoctor/iso/validate_requirements.rb', line 26 def requirement_check(text) text.split(/\.\s+/).each do |t| return t if REQUIREMENT_RE.match t end nil end |
#scope_parse(attrs, xml, node) ⇒ Object
60 61 62 63 64 65 66 |
# File 'lib/asciidoctor/iso/section.rb', line 60 def scope_parse(attrs, xml, node) xml.clause **attr_code(attrs) do |xml_section| xml_section.title { |t| t << "Scope" } content = node.content xml_section << content end end |
#scope_style(node) ⇒ Object
22 23 24 25 |
# File 'lib/asciidoctor/iso/validate_style.rb', line 22 def scope_style(node) return if @novalid style_no_guidance(node, extract_text(node), "Scope") end |
#script_validate(xmldoc) ⇒ Object
195 196 197 198 199 |
# File 'lib/asciidoctor/iso/validate.rb', line 195 def script_validate(xmldoc) script = xmldoc&.at("//bibdata/script")&.text script == "Latn" or warn "ISO Document Attributes: #{script} is not a recognised script" end |
#section(node) ⇒ Object
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/asciidoctor/iso/section.rb', line 7 def section(node) a = section_attributes(node) noko do |xml| case sectiontype(node) when "introduction" then introduction_parse(a, xml, node) when "patent notice" then patent_notice_parse(xml, node) when "scope" then scope_parse(a, xml, node) when "normative references" then norm_ref_parse(a, xml, node) when "terms and definitions", "terms, definitions, symbols and abbreviated terms", "terms, definitions, symbols and abbreviations", "terms, definitions and symbols", "terms, definitions and abbreviations", "terms, definitions and abbreviated terms" @term_def = true term_def_parse(a, xml, node, true) @term_def = false when "symbols and abbreviated terms", "abbreviations", "abbreviated terms", "symbols" symbols_parse(a, xml, node) when "bibliography" then bibliography_parse(a, xml, node) else if @term_def then term_def_subclause_parse(a, xml, node) elsif @biblio then bibliography_parse(a, xml, node) elsif node.attr("style") == "bibliography" bibliography_parse(a, xml, node) elsif node.attr("style") == "appendix" && node.level == 1 annex_parse(a, xml, node) elsif node.option? "appendix" appendix_parse(a, xml, node) else clause_parse(a, xml, node) end end end.join("\n") end |
#section_style(root) ⇒ Object
155 156 157 158 159 160 161 |
# File 'lib/asciidoctor/iso/validate_section.rb', line 155 def section_style(root) foreword_style(root.at("//foreword")) introduction_style(root.at("//introduction")) scope_style(root.at("//clause[title = 'Scope']")) scope = root.at("//clause[title = 'Scope']/clause") scope.nil? || style_warning(scope, SCOPE_WARN, nil) end |
#section_validate(doc) ⇒ Object
6 7 8 9 10 11 12 13 14 |
# File 'lib/asciidoctor/iso/validate_section.rb', line 6 def section_validate(doc) foreword_validate(doc.root) normref_validate(doc.root) symbols_validate(doc.root) sections_sequence_validate(doc.root) section_style(doc.root) subclause_validate(doc.root) super end |
#sections_sequence_validate(root) ⇒ Object
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/asciidoctor/iso/validate_section.rb', line 95 def sections_sequence_validate(root) f = root.xpath(SECTIONS_XPATH) names = f.map { |s| { tag: s.name, title: s&.at("./title")&.text } } names = seqcheck(names, SEQ[0][:msg], SEQ[0][:val]) || return n = names[0] names = seqcheck(names, SEQ[1][:msg], SEQ[1][:val]) || return if n == { tag: "introduction", title: "Introduction" } names = seqcheck(names, SEQ[2][:msg], SEQ[2][:val]) || return end names = seqcheck(names, SEQ[3][:msg], SEQ[3][:val]) || return n = names.shift if n == { tag: "definitions", title: nil } n = names.shift || return end unless n warn "ISO style: Document must contain at least one clause" return end n[:tag] == "clause" || warn("ISO style: Document must contain clause after "\ "Terms and Definitions") n == { tag: "clause", title: "Scope" } && warn("ISO style: Scope must occur before Terms and Definitions") n = names.shift || return while n[:tag] == "clause" n[:title] == "Scope" && warn("ISO style: Scope must occur before Terms and Definitions") n = names.shift || return end unless n[:tag] == "annex" || n[:tag] == "references" warn "ISO style: Only annexes and references can follow clauses" end while n[:tag] == "annex" n = names.shift if n.nil? warn("ISO style: Document must include (references) "\ "Normative References") return end end n == { tag: "references", title: "Normative References" } || warn("ISO style: Document must include (references) "\ "Normative References") n = names.shift n == { tag: "references", title: "Bibliography" } || warn("ISO style: Final section must be (references) Bibliography") names.empty? || warn("ISO style: There are sections after the final Bibliography") end |
#see_erefs_validate(root) ⇒ Object
136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
# File 'lib/asciidoctor/iso/validate.rb', line 136 def see_erefs_validate(root) root.xpath("//eref").each do |t| preceding = t.at("./preceding-sibling::text()[last()]") next unless !preceding.nil? && /\bsee\s*$/mi.match(preceding) unless target = root.at("//*[@id = '#{t['bibitemid']}']") warn "ISO: '#{t} is not pointing to a real reference" next end if target.at("./ancestor::references"\ "[title = 'Normative References']") warn "ISO: 'see #{t}' is pointing to a normative reference" end end end |
#see_xrefs_validate(root) ⇒ Object
124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/asciidoctor/iso/validate.rb', line 124 def see_xrefs_validate(root) root.xpath("//xref").each do |t| # does not deal with preceding text marked up preceding = t.at("./preceding-sibling::text()[last()]") next unless !preceding.nil? && /\bsee\s*$/mi.match(preceding) (target = root.at("//*[@id = '#{t['target']}']")) || next if target&.at("./ancestor-or-self::*[@obligation = 'normative']") warn "ISO: 'see #{t['target']}' is pointing to a normative section" end end end |
#seqcheck(names, msg, accepted) ⇒ Object
46 47 48 49 50 51 52 53 |
# File 'lib/asciidoctor/iso/validate_section.rb', line 46 def seqcheck(names, msg, accepted) n = names.shift unless accepted.include? n warn "ISO style: #{msg}" names = [] end names end |
#stage_validate(xmldoc) ⇒ Object
201 202 203 204 205 |
# File 'lib/asciidoctor/iso/validate.rb', line 201 def stage_validate(xmldoc) stage = xmldoc&.at("//bibdata/status/stage")&.text %w(00 10 20 30 40 50 60 90 95).include? stage or warn "ISO Document Attributes: #{stage} is not a recognised stage" end |
#structured_id(node, xml) ⇒ Object
33 34 35 36 37 38 39 40 |
# File 'lib/asciidoctor/iso/front.rb', line 33 def structured_id(node, xml) return unless node.attr("docnumber") part, subpart = node&.attr("partnumber")&.split(/-/) xml.structuredidentifier do |i| i.project_number node.attr("docnumber"), **attr_code(part: part, subpart: subpart) end end |
#style(n, t) ⇒ Object
75 76 77 78 79 80 81 |
# File 'lib/asciidoctor/iso/validate_style.rb', line 75 def style(n, t) return if @novalid style_number(n, t) style_percent(n, t) style_abbrev(n, t) style_units(n, t) end |
#style_abbrev(n, t) ⇒ Object
100 101 102 103 104 105 106 |
# File 'lib/asciidoctor/iso/validate_style.rb', line 100 def style_abbrev(n, t) style_regex(/(^|\s)(?!e\.g\.|i\.e\.) (?<num>[a-z]{1,2}\.([a-z]{1,2}|\.))\b/ix, "no dots in abbreviations", n, t) style_regex(/\b(?<num>ppm)\b/i, "language-specific abbreviation", n, t) end |
#style_no_guidance(node, text, docpart) ⇒ Object
95 96 97 98 99 100 101 102 |
# File 'lib/asciidoctor/iso/validate_requirements.rb', line 95 def style_no_guidance(node, text, docpart) r = requirement_check(text) style_warning(node, "#{docpart} may contain requirement", r) if r r = (text) style_warning(node, "#{docpart} may contain permission", r) if r r = recommendation_check(text) style_warning(node, "#{docpart} may contain recommendation", r) if r end |
#style_non_std_units(n, t) ⇒ Object
126 127 128 129 130 131 |
# File 'lib/asciidoctor/iso/validate_style.rb', line 126 def style_non_std_units(n, t) NONSTD_UNITS.each do |k, v| style_regex(/\b(?<num>[0-9][0-9,]*\s+#{k})\b/, "non-standard unit (should be #{v})", n, t) end end |
#style_number(n, t) ⇒ Object
83 84 85 86 87 88 89 90 91 |
# File 'lib/asciidoctor/iso/validate_style.rb', line 83 def style_number(n, t) style_two_regex_not_prev(n, t, /^(?<num>-?[0-9]{4,}[,0-9]*)$/, %r{(\bISO|\bIEC|\bIEEE/)$}, "number not broken up in threes") style_regex(/\b(?<num>[0-9]+\.[0-9]+)/i, "possible decimal point", n, t) style_regex(/\b(?<num>billion[s]?)\b/i, "ambiguous number", n, t) end |
#style_percent(n, t) ⇒ Object
93 94 95 96 97 98 |
# File 'lib/asciidoctor/iso/validate_style.rb', line 93 def style_percent(n, t) style_regex(/\b(?<num>[0-9.,]+%)/, "no space before percent sign", n, t) style_regex(/\b(?<num>[0-9.,]+ \u00b1 [0-9,.]+ %)/, "unbracketed tolerance before percent sign", n, t) end |
#style_regex(re, warning, n, text) ⇒ Object
57 58 59 |
# File 'lib/asciidoctor/iso/validate_style.rb', line 57 def style_regex(re, warning, n, text) (m = re.match(text)) && style_warning(n, warning, m[:num]) end |
#style_two_regex_not_prev(n, text, re, re_prev, warning) ⇒ Object
style check with a regex on a token and a negative match on its preceding token
63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/asciidoctor/iso/validate_style.rb', line 63 def style_two_regex_not_prev(n, text, re, re_prev, warning) return if text.nil? arr = text.split(/\W+/) arr.each_index do |i| m = re.match arr[i] m_prev = i.zero? ? nil : re_prev.match(arr[i - 1]) if !m.nil? && m_prev.nil? style_warning(n, warning, m[:num]) end end end |
#style_units(n, t) ⇒ Object
113 114 115 116 117 118 119 |
# File 'lib/asciidoctor/iso/validate_style.rb', line 113 def style_units(n, t) style_regex(/\b(?<num>[0-9][0-9,]*\s+[\u00b0\u2032\u2033])/, "space between number and degrees/minutes/seconds", n, t) style_regex(/\b(?<num>[0-9][0-9,]*#{SI_UNIT})\b/, "no space between number and SI unit", n, t) style_non_std_units(n, t) end |
#style_warning(node, msg, text) ⇒ Object
145 146 147 148 149 150 |
# File 'lib/asciidoctor/iso/validate_section.rb', line 145 def style_warning(node, msg, text) return if @novalid w = "ISO style: WARNING (#{Standoc::Utils::current_location(node)}): #{msg}" w += ": #{text}" if text warn w end |
#subclause_validate(root) ⇒ Object
188 189 190 191 192 |
# File 'lib/asciidoctor/iso/validate_section.rb', line 188 def subclause_validate(root) root.xpath("//clause/clause/clause/clause/clause/clause/clause/clause").each do |c| style_warning(c, "Exceeds the maximum clause depth of 7", nil) end end |
#substage_validate(xmldoc) ⇒ Object
207 208 209 210 211 |
# File 'lib/asciidoctor/iso/validate.rb', line 207 def substage_validate(xmldoc) substage = xmldoc&.at("//bibdata/status/substage")&.text or return %w(00 20 60 90 92 93 98 99).include? substage or warn "ISO Document Attributes: #{substage} is not a recognised substage" end |
#symbols_validate(root) ⇒ Object
34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/asciidoctor/iso/validate_section.rb', line 34 def symbols_validate(root) f = root.xpath("//definitions") f.empty? && return (f.size == 1) || warn(ONE_SYMBOLS_WARNING) f.first.elements.each do |e| unless e.name == "dl" warn(NON_DL_SYMBOLS_WARNING) return end end end |
#termdef_style(xmldoc) ⇒ Object
166 167 168 169 170 171 172 173 174 175 176 |
# File 'lib/asciidoctor/iso/validate.rb', line 166 def termdef_style(xmldoc) xmldoc.xpath("//term").each do |t| para = t.at("./definition") || return term = t.at("./preferred").text termdef_warn(para.text, /^(the|a)\b/i, term, "term definition starts with article") termdef_warn(para.text, /\.$/i, term, "term definition ends with period") end cited_term_style(xmldoc) end |
#termdef_warn(text, re, term, msg) ⇒ Object
162 163 164 |
# File 'lib/asciidoctor/iso/validate.rb', line 162 def termdef_warn(text, re, term, msg) re.match(text) && warn("ISO style: #{term}: #{msg}") end |
#title(node, xml) ⇒ Object
165 166 167 168 169 170 171 172 173 |
# File 'lib/asciidoctor/iso/front.rb', line 165 def title(node, xml) ["en", "fr"].each do |lang| at = { language: lang, format: "text/plain" } title_full(node, xml, lang, at) title_intro(node, xml, lang, at) title_main(node, xml, lang, at) title_part(node, xml, lang, at) end end |
#title_all_siblings(xpath, label) ⇒ Object
77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/asciidoctor/iso/validate.rb', line 77 def title_all_siblings(xpath, label) notitle = false withtitle = false xpath.each do |s| title_all_siblings(s.xpath("./clause | ./terms | ./references"), s&.at("./title")&.text || s["id"]) subtitle = s.at("./title") notitle = notitle || (!subtitle || subtitle.text.empty?) withtitle = withtitle || (subtitle && !subtitle.text.empty?) end notitle && withtitle && warn("#{label}: all subclauses must have a title, or none") end |
#title_first_level_validate(root) ⇒ Object
66 67 68 69 70 71 72 73 74 75 |
# File 'lib/asciidoctor/iso/validate.rb', line 66 def title_first_level_validate(root) root.xpath(SECTIONS_XPATH).each do |s| title = s&.at("./title")&.text || s.name s.xpath("./clause | ./terms | ./references").each do |ss| subtitle = ss.at("./title") !subtitle.nil? && !subtitle&.text&.empty? || warn("#{title}: each first-level subclause must have a title") end end end |
#title_full(node, t, lang, at) ⇒ Object
154 155 156 157 158 159 160 161 162 163 |
# File 'lib/asciidoctor/iso/front.rb', line 154 def title_full(node, t, lang, at) title = node.attr("title-main-#{lang}") intro = node.attr("title-intro-#{lang}") part = node.attr("title-part-#{lang}") title = "#{intro} -- #{title}" if intro title = "#{title} -- #{part}" if part t.title **attr_code(at.merge(type: "main")) do |t1| t1 << asciidoc_sub(title) end end |
#title_intro(node, t, lang, at) ⇒ Object
134 135 136 137 138 139 |
# File 'lib/asciidoctor/iso/front.rb', line 134 def title_intro(node, t, lang, at) return unless node.attr("title-intro-#{lang}") t.title(**attr_code(at.merge(type: "title-intro"))) do |t1| t1 << asciidoc_sub(node.attr("title-intro-#{lang}")) end end |
#title_intro_validate(root) ⇒ Object
13 14 15 16 17 18 19 20 21 22 |
# File 'lib/asciidoctor/iso/validate.rb', line 13 def title_intro_validate(root) title_intro_en = root.at("//title[@type='title-intro' and @language='en']") title_intro_fr = root.at("//title[@type='title-intro' and @language='fr']") if title_intro_en.nil? && !title_intro_fr.nil? warn "No English Title Intro!" end if !title_intro_en.nil? && title_intro_fr.nil? warn "No French Title Intro!" end end |
#title_main(node, t, lang, at) ⇒ Object
141 142 143 144 145 |
# File 'lib/asciidoctor/iso/front.rb', line 141 def title_main(node, t, lang, at) t.title **attr_code(at.merge(type: "title-main")) do |t1| t1 << asciidoc_sub(node.attr("title-main-#{lang}")) end end |
#title_main_validate(root) ⇒ Object
24 25 26 27 28 29 30 31 32 33 |
# File 'lib/asciidoctor/iso/validate.rb', line 24 def title_main_validate(root) title_main_en = root.at("//title[@type='title-main' and @language='en']") title_main_fr = root.at("//title[@type='title-main' and @language='fr']") if title_main_en.nil? && !title_main_fr.nil? warn "No English Title!" end if !title_main_en.nil? && title_main_fr.nil? warn "No French Title!" end end |
#title_names_type_validate(root) ⇒ Object
53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/asciidoctor/iso/validate.rb', line 53 def title_names_type_validate(root) doctypes = /International\sStandard | Technical\sSpecification | Publicly\sAvailable\sSpecification | Technical\sReport | Guide /xi title_main_en = root.at("//title[@type='title-main' and @language='en']") if !title_main_en.nil? && doctypes.match(title_main_en.text) warn "Main Title may name document type" end title_intro_en = root.at("//title[@type='title-intro' and @language='en']") if !title_intro_en.nil? && doctypes.match(title_intro_en.text) warn "Title Intro may name document type" end end |
#title_part(node, t, lang, at) ⇒ Object
147 148 149 150 151 152 |
# File 'lib/asciidoctor/iso/front.rb', line 147 def title_part(node, t, lang, at) return unless node.attr("title-part-#{lang}") t.title(**attr_code(at.merge(type: "title-part"))) do |t1| t1 << asciidoc_sub(node.attr("title-part-#{lang}")) end end |
#title_part_validate(root) ⇒ Object
35 36 37 38 39 40 41 42 |
# File 'lib/asciidoctor/iso/validate.rb', line 35 def title_part_validate(root) title_part_en = root.at("//title[@type='title-part' and @language='en']") title_part_fr = root.at("//title[@type='title-part' and @language='fr']") (title_part_en.nil? && !title_part_fr.nil?) && warn("No English Title Part!") (!title_part_en.nil? && title_part_fr.nil?) && warn("No French Title Part!") end |
#title_subpart_validate(root) ⇒ Object
44 45 46 47 48 49 50 51 |
# File 'lib/asciidoctor/iso/validate.rb', line 44 def title_subpart_validate(root) docid = root.at("//bibdata/docidentifier[@type = 'iso']") subpart = /-\d+-\d+/.match docid iec = root.at("//bibdata/contributor[role/@type = 'publisher']/"\ "organization[abbreviation = 'IEC' or "\ "name = 'International Electrotechnical Commission']") warn("Subpart defined on non-IEC document!") if subpart && !iec end |
#title_validate(root) ⇒ Object
91 92 93 94 95 96 97 98 99 |
# File 'lib/asciidoctor/iso/validate.rb', line 91 def title_validate(root) title_intro_validate(root) title_main_validate(root) title_part_validate(root) title_subpart_validate(root) title_names_type_validate(root) title_first_level_validate(root) title_all_siblings(root.xpath(SECTIONS_XPATH), "(top level)") end |
#validate(doc) ⇒ Object
240 241 242 243 244 |
# File 'lib/asciidoctor/iso/validate.rb', line 240 def validate(doc) content_validate(doc) schema_validate(formattedstr_strip(doc.dup), File.join(File.dirname(__FILE__), "isostandard.rng")) end |