asciidoctor-iso 0.6.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
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