asciidoctor-iso 0.6.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +2 -0
  3. data/.travis.yml +5 -0
  4. data/Gemfile.lock +12 -10
  5. data/README.adoc +113 -16
  6. data/bin/rspec +18 -0
  7. data/lib/asciidoctor/iso/base.rb +30 -28
  8. data/lib/asciidoctor/iso/blocks.rb +33 -33
  9. data/lib/asciidoctor/iso/cleanup.rb +79 -33
  10. data/lib/asciidoctor/iso/cleanup_block.rb +71 -18
  11. data/lib/asciidoctor/iso/cleanup_ref.rb +35 -30
  12. data/lib/asciidoctor/iso/converter.rb +0 -3
  13. data/lib/asciidoctor/iso/front.rb +29 -16
  14. data/lib/asciidoctor/iso/html/isodoc.css +34 -0
  15. data/lib/asciidoctor/iso/html/wordstyle.css +138 -6
  16. data/lib/asciidoctor/iso/inline.rb +10 -22
  17. data/lib/asciidoctor/iso/isodoc.rng +66 -16
  18. data/lib/asciidoctor/iso/isostandard.rng +129 -15
  19. data/lib/asciidoctor/iso/lists.rb +49 -42
  20. data/lib/asciidoctor/iso/macros.rb +12 -8
  21. data/lib/asciidoctor/iso/section.rb +53 -37
  22. data/lib/asciidoctor/iso/table.rb +9 -1
  23. data/lib/asciidoctor/iso/utils.rb +18 -13
  24. data/lib/asciidoctor/iso/validate.rb +100 -24
  25. data/lib/asciidoctor/iso/validate_requirements.rb +106 -0
  26. data/lib/asciidoctor/iso/validate_section.rb +85 -65
  27. data/lib/asciidoctor/iso/validate_style.rb +68 -115
  28. data/lib/asciidoctor/iso/version.rb +1 -1
  29. data/spec/asciidoctor-iso/base_spec.rb +193 -0
  30. data/spec/asciidoctor-iso/blocks_spec.rb +426 -0
  31. data/spec/asciidoctor-iso/cleanup_spec.rb +687 -0
  32. data/spec/asciidoctor-iso/inline_spec.rb +159 -0
  33. data/spec/asciidoctor-iso/lists_spec.rb +189 -0
  34. data/spec/asciidoctor-iso/macros_spec.rb +20 -0
  35. data/spec/asciidoctor-iso/refs_spec.rb +194 -0
  36. data/spec/asciidoctor-iso/section_spec.rb +301 -0
  37. data/spec/asciidoctor-iso/table_spec.rb +307 -0
  38. data/spec/asciidoctor-iso/validate_spec.rb +749 -0
  39. data/spec/examples/english.yaml +69 -0
  40. data/spec/examples/rice.adoc +30 -28
  41. data/spec/examples/rice.doc +3035 -2865
  42. data/spec/examples/rice.html +281 -234
  43. data/spec/examples/rice.preview.html +30 -20
  44. data/spec/examples/rice.xml +250 -282
  45. data/spec/spec_helper.rb +87 -0
  46. metadata +17 -2
@@ -10,10 +10,10 @@ module Asciidoctor
10
10
  @table_fn_number = "a"
11
11
  noko do |xml|
12
12
  xml.table **attr_code(table_attrs(node)) do |xml_table|
13
+ table_name(node, xml_table)
13
14
  %i(head body foot).reject do |tblsec|
14
15
  node.rows[tblsec].empty?
15
16
  end
16
- xml_table.name node.title if node.title?
17
17
  table_head_body_and_foot node, xml_table
18
18
  end
19
19
  end
@@ -21,6 +21,14 @@ module Asciidoctor
21
21
 
22
22
  private
23
23
 
24
+ def table_name(node, xml_table)
25
+ if node.title?
26
+ xml_table.name node.title
27
+ else
28
+ style_warning(node, "Table should have title", nil)
29
+ end
30
+ end
31
+
24
32
  def table_cell1(cell, thd)
25
33
  if cell.style == :asciidoc
26
34
  thd << cell.content
@@ -24,18 +24,33 @@ module Asciidoctor
24
24
  (!n.respond_to?(:level) || n.level.positive?) &&
25
25
  (!n.respond_to?(:context) || n.context != :section)
26
26
  n = n.parent
27
- return "Section: #{n.title}" if !n.nil? && n.context == :section
27
+ return "Section: #{n.title}" if n&.respond_to?(:context) &&
28
+ n&.context == :section
28
29
  end
29
30
  "??"
30
31
  end
31
32
 
32
33
  def warning(node, msg, text)
34
+ return if @novalid
33
35
  warntext = "asciidoctor: WARNING"\
34
36
  "(#{current_location(node)}): #{msg}"
35
37
  warntext += ": #{text}" if text
36
38
  warn warntext
37
39
  end
38
40
 
41
+ def flatten_rawtext_lines(node, result)
42
+ node.lines.each do |x|
43
+ if node.respond_to?(:context) && (node.context == :literal ||
44
+ node.context == :listing)
45
+ result << x.gsub(/</, "&lt;").gsub(/>/, "&gt;")
46
+ else
47
+ # strip not only HTML <tag>, and Asciidoc xrefs <<xref>>
48
+ result << x.gsub(/<[^>]*>+/, "")
49
+ end
50
+ end
51
+ result
52
+ end
53
+
39
54
  # if node contains blocks, flatten them into a single line;
40
55
  # and extract only raw text
41
56
  def flatten_rawtext(node)
@@ -43,16 +58,7 @@ module Asciidoctor
43
58
  if node.respond_to?(:blocks) && node.blocks?
44
59
  node.blocks.each { |b| result << flatten_rawtext(b) }
45
60
  elsif node.respond_to?(:lines)
46
- node.lines.each do |x|
47
- if node.respond_to?(:context) && (node.context == :literal ||
48
- node.context == :listing)
49
- result << x.gsub(/</, "&lt;").gsub(/>/, "&gt;")
50
- else
51
- # strip not only HTML tags <tag>,
52
- # but also Asciidoc crossreferences <<xref>>
53
- result << x.gsub(/<[^>]*>+/, "")
54
- end
55
- end
61
+ result = flatten_rawtext_lines(node, result)
56
62
  elsif node.respond_to?(:text)
57
63
  result << node.text.gsub(/<[^>]*>+/, "")
58
64
  else
@@ -71,7 +77,7 @@ module Asciidoctor
71
77
  nil
72
78
  end
73
79
 
74
- NOKOHEAD = <<~HERE
80
+ NOKOHEAD = <<~HERE.freeze
75
81
  <!DOCTYPE html SYSTEM
76
82
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
77
83
  <html xmlns="http://www.w3.org/1999/xhtml">
@@ -105,7 +111,6 @@ module Asciidoctor
105
111
  out.p { |p| p << node.content }
106
112
  end
107
113
  end
108
-
109
114
  end
110
115
  end
111
116
  end
@@ -1,5 +1,6 @@
1
1
  require "asciidoctor/iso/utils"
2
2
  require_relative "./validate_style.rb"
3
+ require_relative "./validate_requirements.rb"
3
4
  require_relative "./validate_section.rb"
4
5
  require "nokogiri"
5
6
  require "jing"
@@ -19,39 +20,83 @@ module Asciidoctor
19
20
  end
20
21
  end
21
22
 
23
+ def title_main_validate(root)
24
+ title_main_en = root.at("//title-main[@language='en']")
25
+ title_main_fr = root.at("//title-main[@language='fr']")
26
+ if title_main_en.nil? && !title_main_fr.nil?
27
+ warn "No English Title!"
28
+ end
29
+ if !title_main_en.nil? && title_main_fr.nil?
30
+ warn "No French Title!"
31
+ end
32
+ end
33
+
22
34
  def title_part_validate(root)
23
35
  title_part_en = root.at("//title-part[@language='en']")
24
36
  title_part_fr = root.at("//title-part[@language='fr']")
25
- if title_part_en.nil? && !title_part_fr.nil?
26
- warn "No English Title Part!"
27
- end
28
- if !title_part_en.nil? && title_part_fr.nil?
29
- warn "No French Title Part!"
30
- end
37
+ (title_part_en.nil? && !title_part_fr.nil?) &&
38
+ warn("No English Title Part!")
39
+ (!title_part_en.nil? && title_part_fr.nil?) &&
40
+ warn("No French Title Part!")
41
+ end
42
+
43
+ def title_subpart_validate(root)
44
+ subpart = root.at("//bibdata/docidentifier/project-number[@subpart]")
45
+ iec = root.at("//bibdata/contributor[role/@type = 'publisher']/"\
46
+ "organization[name = 'IEC']")
47
+ warn("Subpart defined on non-IEC document!") if subpart && !iec
31
48
  end
32
49
 
33
50
  def title_names_type_validate(root)
34
51
  doctypes = /International\sStandard | Technical\sSpecification |
35
52
  Publicly\sAvailable\sSpecification | Technical\sReport | Guide /xi
36
53
  title_main_en = root.at("//title-main[@language='en']")
37
- if doctypes.match? title_main_en.text
54
+ if !title_main_en.nil? && doctypes.match?(title_main_en.text)
38
55
  warn "Main Title may name document type"
39
56
  end
40
57
  title_intro_en = root.at("//title-intro[@language='en']")
41
58
  if !title_intro_en.nil? && doctypes.match?(title_intro_en.text)
42
- warn "Part Title may name document type"
59
+ warn "Title Intro may name document type"
60
+ end
61
+ end
62
+
63
+ def title_first_level_validate(root)
64
+ root.xpath(SECTIONS_XPATH).each do |s|
65
+ title = s&.at("./title")&.text || s.name
66
+ s.xpath("./subsection | ./terms").each do |ss|
67
+ subtitle = ss.at("./title")
68
+ !subtitle.nil? && !subtitle&.text&.empty? ||
69
+ warn("#{title}: each first-level subclause must have a title")
70
+ end
71
+ end
72
+ end
73
+
74
+ def title_all_siblings(xpath, label)
75
+ notitle = false
76
+ withtitle = false
77
+ xpath.each do |s|
78
+ sublabel = s&.at("./title")&.text || s["id"]
79
+ title_all_siblings(s.xpath("./subsection | ./terms"), sublabel)
80
+ subtitle = s.at("./title")
81
+ notitle = notitle || (!subtitle || subtitle.text.empty?)
82
+ withtitle = withtitle || !subtitle&.text&.empty?
43
83
  end
84
+ notitle && withtitle &&
85
+ warn("#{label}: all subclauses must have a title, or none")
44
86
  end
45
87
 
46
88
  def title_validate(root)
47
89
  title_intro_validate(root)
90
+ title_main_validate(root)
48
91
  title_part_validate(root)
92
+ title_subpart_validate(root)
49
93
  title_names_type_validate(root)
94
+ title_first_level_validate(root)
95
+ title_all_siblings(root.xpath(SECTIONS_XPATH), "(top level)")
50
96
  end
51
97
 
52
98
  def onlychild_clause_validate(root)
53
- q = "//subsection"
54
- root.xpath(q).each do |c|
99
+ root.xpath("//subsection").each do |c|
55
100
  next unless c.xpath("../subsection").size == 1
56
101
  title = c.at("./title")
57
102
  location = c["id"] || c.text[0..60] + "..."
@@ -60,13 +105,6 @@ module Asciidoctor
60
105
  end
61
106
  end
62
107
 
63
- def iso8601_validate(root)
64
- root.xpath("//review/@date | //revision-date").each do |d|
65
- /^\d{8}(T\d{4,6})?$/.match? d.text or
66
- warn "ISO style: #{d.text} is not an ISO 8601 date"
67
- end
68
- end
69
-
70
108
  def isosubgroup_validate(root)
71
109
  root.xpath("//technical-committee/@type").each do |t|
72
110
  unless %w{TC PC JTC JPC}.include? t.text
@@ -80,15 +118,53 @@ module Asciidoctor
80
118
  end
81
119
  end
82
120
 
121
+ def see_xrefs_validate(root)
122
+ root.xpath("//xref").each do |t|
123
+ # does not deal with preceding text marked up
124
+ preceding = t.at("./preceding-sibling::text()[last()]")
125
+ next unless !preceding.nil? && /\bsee\s*$/mi.match?(preceding)
126
+ (target = root.at("//*[@id = '#{t['target']}']")) || next
127
+ if target&.at("./ancestor-or-self::*[@obligation = 'normative']")
128
+ warn "ISO: 'see #{t['target']}' is pointing to a normative section"
129
+ end
130
+ end
131
+ end
132
+
133
+ def see_erefs_validate(root)
134
+ root.xpath("//eref").each do |t|
135
+ preceding = t.at("./preceding-sibling::text()[last()]")
136
+ next unless !preceding.nil? && /\bsee\s*$/mi.match?(preceding)
137
+ target = root.at("//*[@id = '#{t['bibitemid']}']")
138
+ if target.at("./ancestor::references"\
139
+ "[title = 'Normative References']")
140
+ warn "ISO: 'see #{t}' is pointing to a normative reference"
141
+ end
142
+ end
143
+ end
144
+
145
+ def termdef_warn(text, re, term, msg)
146
+ re.match?(text) && warn("ISO style: #{term}: #{msg}")
147
+ end
148
+
149
+ def termdef_style(xmldoc)
150
+ xmldoc.xpath("//term").each do |t|
151
+ para = t.at("./definition") || return
152
+ term = t.at("./preferred").text
153
+ termdef_warn(para.text, /^(the|a)\b/i, term,
154
+ "term definition starts with article")
155
+ termdef_warn(para.text, /\.$/i, term,
156
+ "term definition ends with period")
157
+ end
158
+ end
159
+
83
160
  def content_validate(doc)
84
161
  title_validate(doc.root)
85
162
  isosubgroup_validate(doc.root)
86
- foreword_validate(doc.root)
87
- normref_validate(doc.root)
88
- symbols_validate(doc.root)
89
- iso8601_validate(doc.root)
163
+ section_validate(doc)
90
164
  onlychild_clause_validate(doc.root)
91
- sections_sequence_validate(doc.root)
165
+ termdef_style(doc.root)
166
+ see_xrefs_validate(doc.root)
167
+ see_erefs_validate(doc.root)
92
168
  end
93
169
 
94
170
  def schema_validate(doc, filename)
@@ -112,7 +188,7 @@ module Asciidoctor
112
188
  n.elements.each do |e|
113
189
  e.traverse do |e1|
114
190
  next unless e1.element?
115
- e1.each { |k, v| e.delete(k) }
191
+ e1.each { |k, _v| e.delete(k) }
116
192
  end
117
193
  end
118
194
  end
@@ -121,7 +197,7 @@ module Asciidoctor
121
197
 
122
198
  def validate(doc)
123
199
  content_validate(doc)
124
- schema_validate(formattedstr_strip(doc.dup),
200
+ schema_validate(formattedstr_strip(doc.dup),
125
201
  File.join(File.dirname(__FILE__), "isostandard.rng"))
126
202
  end
127
203
  end
@@ -0,0 +1,106 @@
1
+ require "asciidoctor/iso/utils"
2
+ require "nokogiri"
3
+ require "pp"
4
+
5
+ module Asciidoctor
6
+ module ISO
7
+ module Validate
8
+ REQUIREMENT_RE_STR = <<~REGEXP.freeze
9
+ \\b
10
+ ( shall | (is|are)_to |
11
+ (is|are)_required_(not_)?to |
12
+ has_to |
13
+ only\\b[^.,]+\\b(is|are)_permitted |
14
+ it_is_necessary |
15
+ (needs|need)_to |
16
+ (is|are)_not_(allowed | permitted |
17
+ acceptable | permissible) |
18
+ (is|are)_not_to_be |
19
+ (need|needs)_not |
20
+ do_not )
21
+ \\b
22
+ REGEXP
23
+ REQUIREMENT_RE =
24
+ Regexp.new(REQUIREMENT_RE_STR.gsub(/\s/, "").gsub(/_/, "\\s"),
25
+ Regexp::IGNORECASE)
26
+
27
+ def requirement(text)
28
+ text.split(/\.\s+/).each do |t|
29
+ return t if REQUIREMENT_RE.match? t
30
+ end
31
+ nil
32
+ end
33
+
34
+ RECOMMENDATION_RE_STR = <<~REGEXP.freeze
35
+ \\b
36
+ should |
37
+ ought_(not_)?to |
38
+ it_is_(not_)?recommended_that
39
+ \\b
40
+ REGEXP
41
+ RECOMMENDATION_RE =
42
+ Regexp.new(RECOMMENDATION_RE_STR.gsub(/\s/, "").gsub(/_/, "\\s"),
43
+ Regexp::IGNORECASE)
44
+
45
+ def recommendation(text)
46
+ text.split(/\.\s+/).each do |t|
47
+ return t if RECOMMENDATION_RE.match? t
48
+ end
49
+ nil
50
+ end
51
+
52
+ PERMISSION_RE_STR = <<~REGEXP.freeze
53
+ \\b
54
+ may |
55
+ (is|are)_(permitted | allowed | permissible ) |
56
+ it_is_not_required_that |
57
+ no\\b[^.,]+\\b(is|are)_required
58
+ \\b
59
+ REGEXP
60
+ PERMISSION_RE =
61
+ Regexp.new(PERMISSION_RE_STR.gsub(/\s/, "").gsub(/_/, "\\s"),
62
+ Regexp::IGNORECASE)
63
+
64
+ def permission(text)
65
+ text.split(/\.\s+/).each do |t|
66
+ return t if PERMISSION_RE.match? t
67
+ end
68
+ nil
69
+ end
70
+
71
+ POSSIBILITY_RE_STR = <<~REGEXP.freeze
72
+ \\b
73
+ can | cannot | be_able_to |
74
+ there_is_a_possibility_of |
75
+ it_is_possible_to | be_unable_to |
76
+ there_is_no_possibility_of |
77
+ it_is_not_possible_to
78
+ \\b
79
+ REGEXP
80
+ POSSIBILITY_RE =
81
+ Regexp.new(POSSIBILITY_RE_STR.gsub(/\s/, "").gsub(/_/, "\\s"),
82
+ Regexp::IGNORECASE)
83
+
84
+ def possibility(text)
85
+ text.split(/\.\s+/).each { |t| return t if POSSIBILITY_RE.match? t }
86
+ nil
87
+ end
88
+
89
+ def external_constraint(text)
90
+ text.split(/\.\s+/).each do |t|
91
+ return t if /\b(must)\b/xi.match? t
92
+ end
93
+ nil
94
+ end
95
+
96
+ def style_no_guidance(node, text, docpart)
97
+ r = requirement(text)
98
+ style_warning(node, "#{docpart} may contain requirement", r) if r
99
+ r = permission(text)
100
+ style_warning(node, "#{docpart} may contain permission", r) if r
101
+ r = recommendation(text)
102
+ style_warning(node, "#{docpart} may contain recommendation", r) if r
103
+ end
104
+ end
105
+ end
106
+ end
@@ -1,28 +1,40 @@
1
1
  require "nokogiri"
2
- require "pp"
3
2
 
4
3
  module Asciidoctor
5
4
  module ISO
6
5
  module Validate
6
+ def section_validate(doc)
7
+ foreword_validate(doc.root)
8
+ normref_validate(doc.root)
9
+ symbols_validate(doc.root)
10
+ sections_sequence_validate(doc.root)
11
+ end
12
+
7
13
  def foreword_validate(root)
8
- f = root.at("//foreword")
14
+ f = root.at("//foreword") || return
9
15
  s = f.at("./subsection")
10
16
  warn "ISO style: foreword contains subsections" unless s.nil?
11
17
  end
12
18
 
13
19
  def normref_validate(root)
14
- f = root.at("//references[title = 'Normative References']")
15
- f.at("./references") and
16
- warn "ISO style: normative references contains subsections"
20
+ f = root.at("//references[title = 'Normative References']") || return
21
+ f.at("./references") &&
22
+ warn("ISO style: normative references contains subsections")
17
23
  end
18
24
 
25
+ ONE_SYMBOLS_WARNING = "ISO style: only one Symbols and Abbreviated "\
26
+ "Terms section in the standard".freeze
27
+
28
+ NON_DL_SYMBOLS_WARNING = "ISO style: Symbols and Abbreviated Terms can "\
29
+ "only contain a definition list".freeze
30
+
19
31
  def symbols_validate(root)
20
- f = root.at("//clause[title = 'Symbols and Abbreviations']")
21
- return if f.nil?
22
- f.elements do |e|
32
+ f = root.xpath("//symbols-abbrevs")
33
+ f.empty? && return
34
+ (f.size == 1) || warn(ONE_SYMBOLS_WARNING)
35
+ f.first.elements.each do |e|
23
36
  unless e.name == "dl"
24
- warn "ISO style: Symbols and Abbreviations can only contain "\
25
- "a definition list"
37
+ warn(NON_DL_SYMBOLS_WARNING)
26
38
  return
27
39
  end
28
40
  end
@@ -38,79 +50,87 @@ module Asciidoctor
38
50
  end
39
51
 
40
52
  # spec of permissible section sequence
41
- SEQ = [
42
- {
43
- msg: "Initial section must be (content) Foreword",
44
- val: [{ tag: "foreword", title: "Foreword" }],
45
- },
46
- {
47
- msg: "Prefatory material must be followed by (clause) Scope",
48
- val: [{ tag: "introduction", title: "Introduction" },
49
- { tag: "clause", title: "Scope" }],
50
- },
51
- {
52
- msg: "Prefatory material must be followed by (clause) Scope",
53
- val: [{ tag: "clause", title: "Scope" }],
54
- },
55
- # we skip normative references, it goes to end of list
56
- {
57
- msg: "Normative References must be followed by "\
58
- "Terms and Definitions",
59
- val: [
60
- { tag: "terms", title: "Terms and Definitions" },
61
- { tag: "terms",
62
- title: "Terms, Definitions, Symbols and Abbreviations" }
63
- ]
64
- },
65
- ]
53
+ # we skip normative references, it goes to end of list
54
+ SEQ =
55
+ [
56
+ {
57
+ msg: "Initial section must be (content) Foreword",
58
+ val: [{ tag: "foreword", title: "Foreword" }],
59
+ },
60
+ {
61
+ msg: "Prefatory material must be followed by (clause) Scope",
62
+ val: [{ tag: "introduction", title: "Introduction" },
63
+ { tag: "clause", title: "Scope" }],
64
+ },
65
+ {
66
+ msg: "Prefatory material must be followed by (clause) Scope",
67
+ val: [{ tag: "clause", title: "Scope" }],
68
+ },
69
+ {
70
+ msg: "Normative References must be followed by "\
71
+ "Terms and Definitions",
72
+ val: [
73
+ { tag: "terms", title: "Terms and Definitions" },
74
+ {
75
+ tag: "terms",
76
+ title: "Terms, Definitions, Symbols and Abbreviated Terms"
77
+ },
78
+ ],
79
+ },
80
+ ].freeze
81
+
82
+ SECTIONS_XPATH =
83
+ " //foreword | //introduction | //sections/terms | "\
84
+ "//symbols-abbrevs | "\
85
+ "//sections/clause | ./references | ./annex".freeze
66
86
 
67
87
  def sections_sequence_validate(root)
68
- f = root.xpath(" //foreword | //introduction | //sections/terms | "\
69
- "//sections/clause | ./references | "\
70
- "./annex")
71
- names = f.map { |s| { tag: s.name, title: s.at("./title").text } }
72
- names = seqcheck(names, SEQ[0][:msg], SEQ[0][:val]) or return
88
+ f = root.xpath(SECTIONS_XPATH)
89
+ names = f.map { |s| { tag: s.name, title: s&.at("./title")&.text } }
90
+ names = seqcheck(names, SEQ[0][:msg], SEQ[0][:val]) || return
73
91
  n = names[0]
74
- names = seqcheck(names, SEQ[1][:msg], SEQ[1][:val]) or return
92
+ names = seqcheck(names, SEQ[1][:msg], SEQ[1][:val]) || return
75
93
  if n == { tag: "introduction", title: "Introduction" }
76
- names = seqcheck(names, SEQ[2][:msg], SEQ[2][:val]) or return
94
+ names = seqcheck(names, SEQ[2][:msg], SEQ[2][:val]) || return
77
95
  end
78
- names = seqcheck(names, SEQ[3][:msg], SEQ[3][:val]) or return
96
+ names = seqcheck(names, SEQ[3][:msg], SEQ[3][:val]) || return
79
97
  n = names.shift
80
- if n == { tag: "clause", title: "Symbols and Abbreviations" }
81
- n = names.shift or return
98
+ if n == { tag: "symbols-abbrevs", title: nil }
99
+ n = names.shift || return
82
100
  end
83
101
  unless n
84
102
  warn "ISO style: Document must contain at least one clause"
85
103
  return
86
104
  end
87
- n[:tag] == "clause" or
88
- warn "ISO style: Document must contain at least one clause"
89
- n == { tag: "clause", title: "Scope" } and
90
- warn "ISO style: Scope must occur before Terms and Definitions"
91
- n = names.shift or return
105
+ n[:tag] == "clause" ||
106
+ warn("ISO style: Document must contain clause after Terms and Definitions")
107
+ n == { tag: "clause", title: "Scope" } &&
108
+ warn("ISO style: Scope must occur before Terms and Definitions")
109
+ n = names.shift || return
92
110
  while n[:tag] == "clause"
93
- n[:title] == "Scope" and
94
- warn "ISO style: Scope must occur before Terms and Definitions"
95
- n[:title] == "Symbols and Abbreviations" and
96
- warn "ISO style: Symbols and Abbreviations must occur "\
97
- "right after Terms and Definitions"
98
- n = names.shift or return
111
+ n[:title] == "Scope" &&
112
+ warn("ISO style: Scope must occur before Terms and Definitions")
113
+ n = names.shift || return
99
114
  end
100
- unless n[:tag] == "annex" or n[:tag] == "references"
115
+ unless n[:tag] == "annex" || n[:tag] == "references"
101
116
  warn "ISO style: Only annexes and references can follow clauses"
102
117
  end
103
118
  while n[:tag] == "annex"
104
- n = names.shift or return
119
+ n = names.shift
120
+ if n.nil?
121
+ warn("ISO style: Document must include (references) "\
122
+ "Normative References")
123
+ return
124
+ end
105
125
  end
106
- n == { tag: "references", title: "Normative References" } or
107
- warn "ISO style: Document must include (references) "\
108
- "Normative References"
126
+ n == { tag: "references", title: "Normative References" } ||
127
+ warn("ISO style: Document must include (references) "\
128
+ "Normative References")
109
129
  n = names.shift
110
- n == { tag: "references", title: "Bibliography" } or
111
- warn "ISO style: Final section must be (references) Bibliography"
112
- names.empty? or
113
- warn "ISO style: There are sections after the final Bibliography"
130
+ n == { tag: "references", title: "Bibliography" } ||
131
+ warn("ISO style: Final section must be (references) Bibliography")
132
+ names.empty? ||
133
+ warn("ISO style: There are sections after the final Bibliography")
114
134
  end
115
135
  end
116
136
  end