Module: Asciidoctor::ISO::Validate
- Included in:
- Converter
- Defined in:
- lib/asciidoctor/iso/validate.rb,
lib/asciidoctor/iso/validate_style.rb,
lib/asciidoctor/iso/validate_section.rb,
lib/asciidoctor/iso/validate_requirements.rb
Constant Summary collapse
- SOURCELOCALITY =
".//locality[@type = 'clause']/referenceFrom".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
- #asset_style(root) ⇒ Object
- #asset_title_style(root) ⇒ Object
- #content_validate(doc) ⇒ Object
- #definition_style(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
-
#formattedstr_strip(doc) ⇒ Object
RelaxNG cannot cope well with wildcard attributes.
- #iev_validate(xmldoc) ⇒ Object
- #introduction_style(node) ⇒ Object
- #isosubgroup_validate(root) ⇒ Object
- #locality_erefs_validate(root) ⇒ Object
- #norm_bibitem_style(root) ⇒ Object
- #normref_validate(root) ⇒ Object
- #note_style(node) ⇒ Object
- #onlychild_clause_validate(root) ⇒ Object
- #permission(text) ⇒ Object
- #possibility(text) ⇒ Object
- #recommendation(text) ⇒ Object
- #requirement(text) ⇒ Object
- #schema_validate(doc, filename) ⇒ Object
- #scope_style(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_all_siblings(xpath, label) ⇒ Object
- #title_first_level_validate(root) ⇒ Object
- #title_intro_validate(root) ⇒ Object
- #title_main_validate(root) ⇒ Object
- #title_names_type_validate(root) ⇒ Object
- #title_part_validate(root) ⇒ Object
- #title_subpart_validate(root) ⇒ Object
- #title_validate(root) ⇒ Object
- #validate(doc) ⇒ Object
Instance Method Details
#asset_style(root) ⇒ Object
191 192 193 194 195 196 197 198 199 |
# File 'lib/asciidoctor/iso/validate_section.rb', line 191 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)) } asset_title_style(root) norm_bibitem_style(root) end |
#asset_title_style(root) ⇒ Object
174 175 176 177 178 179 180 181 |
# File 'lib/asciidoctor/iso/validate_section.rb', line 174 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
184 185 186 187 188 189 190 191 192 193 194 |
# File 'lib/asciidoctor/iso/validate.rb', line 184 def content_validate(doc) title_validate(doc.root) isosubgroup_validate(doc.root) section_validate(doc) 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 |
#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
17 18 19 20 21 |
# File 'lib/asciidoctor/iso/validate_section.rb', line 17 def foreword_validate(root) f = root.at("//foreword") || return s = f.at("./clause") warn "ISO style: foreword contains subclauses" unless s.nil? end |
#formattedstr_strip(doc) ⇒ Object
RelaxNG cannot cope well with wildcard attributes. So we strip any attributes from FormattedString instances (which can contain xs:any markup, and are signalled with @format) before validation.
212 213 214 215 216 217 218 219 220 221 222 |
# File 'lib/asciidoctor/iso/validate.rb', line 212 def formattedstr_strip(doc) doc.xpath("//*[@format]").each do |n| n.elements.each do |e| e.traverse do |e1| next unless e1.element? e1.each { |k, _v| e.delete(k) } end end end doc end |
#iev_validate(xmldoc) ⇒ Object
173 174 175 176 177 178 179 180 181 182 |
# File 'lib/asciidoctor/iso/validate.rb', line 173 def iev_validate(xmldoc) xmldoc.xpath("//term").each do |t| /^IEV($|\s|:)/.match(t&.at(".//origin/@citeas")&.text) or next pref = t.xpath("./preferred").inject([]) { |m, x| m << x&.text&.downcase } locality = t.xpath(SOURCELOCALITY)&.text or next iev = @iev.fetch(locality, xmldoc&.at("//language")&.text || "en") or next pref.include?(iev.downcase) or warn %(Term "#{pref[0]}" does not match IEV #{locality} "#{iev}") end 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 |
#norm_bibitem_style(root) ⇒ Object
183 184 185 186 187 188 189 |
# File 'lib/asciidoctor/iso/validate_section.rb', line 183 def norm_bibitem_style(root) root.xpath(NORM_BIBITEMS).each do |b| if b.at(Cleanup::ISO_PUBLISHER_XPATH).nil? Utils::warning(b, NORM_ISO_WARN, b.text) end end end |
#normref_validate(root) ⇒ Object
23 24 25 26 27 |
# File 'lib/asciidoctor/iso/validate_section.rb', line 23 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(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 |
#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 |
#schema_validate(doc, filename) ⇒ Object
196 197 198 199 200 201 202 203 204 205 206 207 |
# File 'lib/asciidoctor/iso/validate.rb', line 196 def schema_validate(doc, filename) File.open(".tmp.xml", "w:UTF-8") { |f| f.write(doc.to_xml) } begin errors = Jing.new(filename).validate(".tmp.xml") rescue Jing::Error => e abort "what what what #{e}" end warn "Valid!" if errors.none? errors.each do |error| warn "#{error[:message]} @ #{error[:line]}:#{error[:column]}" 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_style(root) ⇒ Object
149 150 151 152 153 154 155 |
# File 'lib/asciidoctor/iso/validate_section.rb', line 149 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 15 |
# 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) sourcecode_style(doc.root) asset_style(doc.root) end |
#sections_sequence_validate(root) ⇒ Object
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 144 |
# File 'lib/asciidoctor/iso/validate_section.rb', line 96 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
47 48 49 50 51 52 53 54 |
# File 'lib/asciidoctor/iso/validate_section.rb', line 47 def seqcheck(names, msg, accepted) n = names.shift unless accepted.include? n warn "ISO style: #{msg}" names = [] end names end |
#sourcecode_style(root) ⇒ Object
157 158 159 160 161 162 163 164 165 |
# File 'lib/asciidoctor/iso/validate_section.rb', line 157 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
82 83 84 85 86 87 88 |
# File 'lib/asciidoctor/iso/validate_style.rb', line 82 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
107 108 109 110 111 112 113 |
# File 'lib/asciidoctor/iso/validate_style.rb', line 107 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
133 134 135 136 137 138 |
# File 'lib/asciidoctor/iso/validate_style.rb', line 133 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
90 91 92 93 94 95 96 97 98 |
# File 'lib/asciidoctor/iso/validate_style.rb', line 90 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
100 101 102 103 104 105 |
# File 'lib/asciidoctor/iso/validate_style.rb', line 100 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
64 65 66 |
# File 'lib/asciidoctor/iso/validate_style.rb', line 64 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
70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/asciidoctor/iso/validate_style.rb', line 70 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
120 121 122 123 124 125 126 |
# File 'lib/asciidoctor/iso/validate_style.rb', line 120 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
57 58 59 60 61 62 |
# File 'lib/asciidoctor/iso/validate_style.rb', line 57 def style_warning(node, msg, text) return if @novalid w = "ISO style: WARNING (#{Utils::current_location(node)}): #{msg}" w += ": #{text}" if text warn w end |
#subclause_validate(root) ⇒ Object
201 202 203 204 205 |
# File 'lib/asciidoctor/iso/validate_section.rb', line 201 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
35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/asciidoctor/iso/validate_section.rb', line 35 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_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_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_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_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
224 225 226 227 228 |
# File 'lib/asciidoctor/iso/validate.rb', line 224 def validate(doc) content_validate(doc) schema_validate(formattedstr_strip(doc.dup), File.join(File.dirname(__FILE__), "isostandard.rng")) end |