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 |"\ "//references[title = 'Normative References']//bibitem/note".freeze
- POST_NORMREF_FOOTNOTES =
"//clause[not(title = 'Scope')]//fn | "\ "//references[title = 'Bibliography']//fn | "\ "//references[title = 'Bibliography']//bibitem/note".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
- #appendix_parse(attrs, xml, node) ⇒ Object
- #asset_style(root) ⇒ Object
- #asset_title_style(root) ⇒ Object
- #content_validate(doc) ⇒ Object
- #definition_style(node) ⇒ Object
- #doc_converter(node) ⇒ 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
- #html_converter(node) ⇒ Object
- #html_converter_alt(node) ⇒ Object
- #introduction_style(node) ⇒ Object
- #isosubgroup_validate(root) ⇒ Object
- #locality_erefs_validate(root) ⇒ Object
- #makexml1(node) ⇒ Object
- #metadata(node, xml) ⇒ Object
- #metadata_author(node, xml) ⇒ Object
- #metadata_committee(node, xml) ⇒ Object
- #metadata_copyright(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(text) ⇒ Object
- #possibility(text) ⇒ Object
- #recommendation(text) ⇒ Object
- #requirement(text) ⇒ Object
- #scope_parse(attrs, xml, node) ⇒ Object
- #scope_style(node) ⇒ 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
- #sourcecode_style(root) ⇒ 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
- #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_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
#appendix_parse(attrs, xml, node) ⇒ Object
47 48 49 50 51 52 53 54 |
# File 'lib/asciidoctor/iso/section.rb', line 47 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
197 198 199 200 201 202 203 204 205 |
# File 'lib/asciidoctor/iso/validate_section.rb', line 197 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 |
#asset_title_style(root) ⇒ Object
180 181 182 183 184 185 186 187 |
# File 'lib/asciidoctor/iso/validate_section.rb', line 180 def asset_title_style(root) root.xpath("//figure[image][not(title)]").each do |node| style_warning(node, "Figure should have title", nil) end root.xpath("//table[not(title)]").each do |node| style_warning(node, "Table should have title", nil) end end |
#content_validate(doc) ⇒ Object
171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/asciidoctor/iso/validate.rb', line 171 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) 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(extract_text(node)) style_warning(node, "Definition may contain requirement", r) if r end |
#doc_converter(node) ⇒ Object
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/asciidoctor/iso/base.rb', line 43 def doc_converter(node) IsoDoc::Iso::WordConvert.new( script: node.attr("script"), bodyfont: node.attr("body-font"), headerfont: node.attr("header-font"), monospacefont: node.attr("monospace-font"), i18nyaml: node.attr("i18nyaml"), scope: node.attr("scope"), wordstylesheet: node.attr("wordstylesheet"), standardstylesheet: node.attr("standardstylesheet"), header: node.attr("header"), wordcoverpage: node.attr("wordcoverpage"), wordintropage: node.attr("wordintropage"), ulstyle: node.attr("ulstyle"), olstyle: node.attr("olstyle"), ) end |
#document(node) ⇒ Object
61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/asciidoctor/iso/base.rb', line 61 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") system "mv #{@filename}.html #{@filename}_alt.html" html_converter(node).convert(@filename + ".xml") doc_converter(node).convert(@filename + ".xml") end @files_to_delete.each { |f| system "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 |
#html_converter(node) ⇒ Object
12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
# File 'lib/asciidoctor/iso/base.rb', line 12 def html_converter(node) IsoDoc::Iso::HtmlConvert.new( script: node.attr("script"), bodyfont: node.attr("body-font"), headerfont: node.attr("header-font"), monospacefont: node.attr("monospace-font"), i18nyaml: node.attr("i18nyaml"), scope: node.attr("scope"), htmlstylesheet: node.attr("htmlstylesheet"), htmlcoverpage: node.attr("htmlcoverpage"), htmlintropage: node.attr("htmlintropage"), scripts: node.attr("scripts"), ) end |
#html_converter_alt(node) ⇒ Object
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/asciidoctor/iso/base.rb', line 27 def html_converter_alt(node) IsoDoc::Iso::HtmlConvert.new( script: node.attr("script"), bodyfont: node.attr("body-font"), headerfont: node.attr("header-font"), monospacefont: node.attr("monospace-font"), i18nyaml: node.attr("i18nyaml"), alt: true, scope: node.attr("scope"), htmlstylesheet: node.attr("htmlstylesheet"), htmlcoverpage: node.attr("htmlcoverpage"), htmlintropage: node.attr("htmlintropage"), scripts: node.attr("scripts"), ) 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(extract_text(node)) style_warning(node, "Introduction may contain requirement", r) if r end |
#isosubgroup_validate(root) ⇒ Object
110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/asciidoctor/iso/validate.rb', line 110 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 |
#locality_erefs_validate(root) ⇒ Object
147 148 149 150 151 152 153 154 |
# File 'lib/asciidoctor/iso/validate.rb', line 147 def locality_erefs_validate(root) root.xpath("//eref[locality]").each do |t| unless /:[ ]?\d+{4}$/.match t["citeas"] warn "ISO: undated reference #{t['citeas']} should not contain "\ "specific elements" end end end |
#makexml1(node) ⇒ Object
75 76 77 78 79 80 81 |
# File 'lib/asciidoctor/iso/base.rb', line 75 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.flatten * "\n") end |
#metadata(node, xml) ⇒ Object
86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/asciidoctor/iso/front.rb', line 86 def (node, xml) title node, xml (node, xml) (node, xml) (node, xml) xml.language (node.attr("language") || "en") xml.script (node.attr("script") || "Latn") (node, xml) (node, xml) (node, xml) (node, xml) end |
#metadata_author(node, xml) ⇒ Object
37 38 39 40 41 42 43 44 45 |
# File 'lib/asciidoctor/iso/front.rb', line 37 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
77 78 79 80 81 82 83 84 |
# File 'lib/asciidoctor/iso/front.rb', line 77 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
57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/asciidoctor/iso/front.rb', line 57 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_id(node, xml) ⇒ Object
12 13 14 15 16 17 18 19 20 21 |
# File 'lib/asciidoctor/iso/front.rb', line 12 def (node, xml) part, subpart = node&.attr("partnumber")&.split(/-/) xml.docidentifier do |i| i.project_number node.attr("docnumber"), **attr_code(part: part, subpart: subpart) if node.attr("tc-docnumber") i.tc_document_number node.attr("tc-docnumber") end end end |
#metadata_publisher(node, xml) ⇒ Object
47 48 49 50 51 52 53 54 55 |
# File 'lib/asciidoctor/iso/front.rb', line 47 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
69 70 71 72 73 74 75 |
# File 'lib/asciidoctor/iso/front.rb', line 69 def (node, xml) xml.status do |s| s.stage (node.attr("docstage") || "60") s.substage (node.attr("docsubstage") || "60") node.attr("iteration") && (s.iteration node.attr("iteration")) end end |
#norm_bibitem_style(root) ⇒ Object
189 190 191 192 193 194 195 |
# File 'lib/asciidoctor/iso/validate_section.rb', line 189 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
100 101 102 103 104 105 106 107 108 |
# File 'lib/asciidoctor/iso/validate.rb', line 100 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
23 24 25 26 27 28 29 30 31 32 33 34 35 |
# File 'lib/asciidoctor/iso/front.rb', line 23 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
24 25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/asciidoctor/iso/cleanup.rb', line 24 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
56 57 58 59 60 61 |
# File 'lib/asciidoctor/iso/section.rb', line 56 def patent_notice_parse(xml, node) # xml.patent_notice do |xml_section| # xml_section << node.content # end xml << node.content end |
#permission(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(text) ⇒ Object
44 45 46 47 48 49 |
# File 'lib/asciidoctor/iso/validate_requirements.rb', line 44 def recommendation(text) text.split(/\.\s+/).each do |t| return t if RECOMMENDATION_RE.match t end nil end |
#requirement(text) ⇒ Object
26 27 28 29 30 31 |
# File 'lib/asciidoctor/iso/validate_requirements.rb', line 26 def requirement(text) text.split(/\.\s+/).each do |t| return t if REQUIREMENT_RE.match t end nil end |
#scope_parse(attrs, xml, node) ⇒ Object
63 64 65 66 67 68 69 |
# File 'lib/asciidoctor/iso/section.rb', line 63 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 |
#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 43 44 45 |
# File 'lib/asciidoctor/iso/section.rb', line 7 def section(node) a = { id: Standoc::Utils::anchor_or_uuid(node) } noko do |xml| case sectiontype(node) when "introduction" then if node.level == 1 then introduction_parse(a, xml, node) else clause_parse(a, xml, node) end 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" 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" && node.level == 1 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
135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/asciidoctor/iso/validate.rb', line 135 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) target = root.at("//*[@id = '#{t['bibitemid']}']") 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
123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/asciidoctor/iso/validate.rb', line 123 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 |
#sourcecode_style(root) ⇒ Object
163 164 165 166 167 168 169 170 171 |
# File 'lib/asciidoctor/iso/validate_section.rb', line 163 def sourcecode_style(root) root.xpath("//sourcecode").each do |x| callouts = x.elements.select { |e| e.name == "callout" } annotations = x.elements.select { |e| e.name == "annotation" } if callouts.size != annotations.size warn "#{x['id']}: mismatch of callouts and annotations" end 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(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(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
207 208 209 210 211 |
# File 'lib/asciidoctor/iso/validate_section.rb', line 207 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 |
#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
160 161 162 163 164 165 166 167 168 169 |
# File 'lib/asciidoctor/iso/validate.rb', line 160 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 end |
#termdef_warn(text, re, term, msg) ⇒ Object
156 157 158 |
# File 'lib/asciidoctor/iso/validate.rb', line 156 def termdef_warn(text, re, term, msg) re.match(text) && warn("ISO style: #{term}: #{msg}") end |
#title(node, xml) ⇒ Object
119 120 121 122 123 124 125 126 127 128 |
# File 'lib/asciidoctor/iso/front.rb', line 119 def title(node, xml) ["en", "fr"].each do |lang| xml.title do |t| at = { language: lang, format: "text/plain" } title_intro(node, t, lang, at) title_main(node, t, lang, at) title_part(node, t, lang, at) end end end |
#title_all_siblings(xpath, label) ⇒ Object
76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/asciidoctor/iso/validate.rb', line 76 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
65 66 67 68 69 70 71 72 73 74 |
# File 'lib/asciidoctor/iso/validate.rb', line 65 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_intro(node, t, lang, at) ⇒ Object
99 100 101 102 103 104 |
# File 'lib/asciidoctor/iso/front.rb', line 99 def title_intro(node, t, lang, at) return unless node.attr("title-intro-#{lang}") t.title_intro(**attr_code(at)) 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-intro[@language='en']") title_intro_fr = root.at("//title-intro[@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
106 107 108 109 110 |
# File 'lib/asciidoctor/iso/front.rb', line 106 def title_main(node, t, lang, at) t.title_main **attr_code(at) 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-main[@language='en']") title_main_fr = root.at("//title-main[@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
52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/asciidoctor/iso/validate.rb', line 52 def title_names_type_validate(root) doctypes = /International\sStandard | Technical\sSpecification | Publicly\sAvailable\sSpecification | Technical\sReport | Guide /xi title_main_en = root.at("//title-main[@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-intro[@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
112 113 114 115 116 117 |
# File 'lib/asciidoctor/iso/front.rb', line 112 def title_part(node, t, lang, at) return unless node.attr("title-part-#{lang}") t.title_part(**attr_code(at)) 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-part[@language='en']") title_part_fr = root.at("//title-part[@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 |
# File 'lib/asciidoctor/iso/validate.rb', line 44 def title_subpart_validate(root) subpart = root.at("//bibdata/docidentifier/project-number[@subpart]") 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
90 91 92 93 94 95 96 97 98 |
# File 'lib/asciidoctor/iso/validate.rb', line 90 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
183 184 185 186 187 |
# File 'lib/asciidoctor/iso/validate.rb', line 183 def validate(doc) content_validate(doc) schema_validate(formattedstr_strip(doc.dup), File.join(File.dirname(__FILE__), "isostandard.rng")) end |