metanorma-bsi 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +6 -0
- data/.hound.yml +3 -0
- data/.rubocop.yml +14 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +7 -0
- data/LICENSE +25 -0
- data/README.adoc +199 -0
- data/Rakefile +8 -0
- data/bin/rspec +18 -0
- data/lib/asciidoctor/bsi/basicdoc.rng +1131 -0
- data/lib/asciidoctor/bsi/biblio.rng +1235 -0
- data/lib/asciidoctor/bsi/bsi.rng +120 -0
- data/lib/asciidoctor/bsi/bsi_intro_en.xml +105 -0
- data/lib/asciidoctor/bsi/cleanup.rb +78 -0
- data/lib/asciidoctor/bsi/cleanup_ref.rb +183 -0
- data/lib/asciidoctor/bsi/converter.rb +83 -0
- data/lib/asciidoctor/bsi/front.rb +67 -0
- data/lib/asciidoctor/bsi/isodoc.rng +1870 -0
- data/lib/asciidoctor/bsi/isostandard.rng +477 -0
- data/lib/asciidoctor/bsi/reqt.rng +194 -0
- data/lib/asciidoctor/bsi/validate.rb +224 -0
- data/lib/asciidoctor/bsi/validate_list.rb +72 -0
- data/lib/asciidoctor/bsi/validate_requirement.rb +163 -0
- data/lib/isodoc/bsi/base_convert.rb +91 -0
- data/lib/isodoc/bsi/bsi.international-standard.xsl +6540 -0
- data/lib/isodoc/bsi/html/html_bsi_intro.html +8 -0
- data/lib/isodoc/bsi/html/html_bsi_titlepage.html +50 -0
- data/lib/isodoc/bsi/html/htmlstyle.css +968 -0
- data/lib/isodoc/bsi/html/htmlstyle.scss +699 -0
- data/lib/isodoc/bsi/html_convert.rb +56 -0
- data/lib/isodoc/bsi/i18n-en.yaml +56 -0
- data/lib/isodoc/bsi/i18n.rb +15 -0
- data/lib/isodoc/bsi/init.rb +24 -0
- data/lib/isodoc/bsi/metadata.rb +33 -0
- data/lib/isodoc/bsi/pdf_convert.rb +17 -0
- data/lib/isodoc/bsi/presentation_xml_convert.rb +72 -0
- data/lib/isodoc/bsi/sts_convert.rb +30 -0
- data/lib/isodoc/bsi/xref.rb +134 -0
- data/lib/metanorma-bsi.rb +15 -0
- data/lib/metanorma/bsi.rb +6 -0
- data/lib/metanorma/bsi/processor.rb +51 -0
- data/lib/metanorma/bsi/version.rb +6 -0
- data/metanorma-bsi.gemspec +47 -0
- data/spec/asciidoctor/base_spec.rb +778 -0
- data/spec/asciidoctor/blocks_spec.rb +553 -0
- data/spec/asciidoctor/cleanup_spec.rb +547 -0
- data/spec/asciidoctor/inline_spec.rb +176 -0
- data/spec/asciidoctor/lists_spec.rb +194 -0
- data/spec/asciidoctor/refs_spec.rb +318 -0
- data/spec/asciidoctor/section_spec.rb +382 -0
- data/spec/asciidoctor/validate_spec.rb +858 -0
- data/spec/assets/header.html +7 -0
- data/spec/assets/html.css +2 -0
- data/spec/assets/iso.xml +71 -0
- data/spec/assets/rice_image1.png +0 -0
- data/spec/assets/word.css +2 -0
- data/spec/assets/wordintro.html +4 -0
- data/spec/assets/xref_error.adoc +7 -0
- data/spec/isodoc/blocks_spec.rb +259 -0
- data/spec/isodoc/i18n_spec.rb +442 -0
- data/spec/isodoc/inline_spec.rb +287 -0
- data/spec/isodoc/iso_spec.rb +116 -0
- data/spec/isodoc/metadata_spec.rb +262 -0
- data/spec/isodoc/postproc_spec.rb +137 -0
- data/spec/isodoc/ref_spec.rb +376 -0
- data/spec/isodoc/section_spec.rb +467 -0
- data/spec/isodoc/terms_spec.rb +246 -0
- data/spec/isodoc/xref_spec.rb +1730 -0
- data/spec/metanorma/processor_spec.rb +76 -0
- data/spec/spec_helper.rb +291 -0
- data/spec/vcr_cassettes/iso-639.yml +182 -0
- data/spec/vcr_cassettes/isobib_get_639_1967.yml +136 -0
- data/spec/vcr_cassettes/multistandard.yml +352 -0
- metadata +343 -0
@@ -0,0 +1,194 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
|
3
|
+
<!--
|
4
|
+
Presupposes isodoc.rnc, is included in it
|
5
|
+
include "isodoc.rnc" { }
|
6
|
+
-->
|
7
|
+
<define name="requirement">
|
8
|
+
<element name="requirement">
|
9
|
+
<ref name="RequirementType"/>
|
10
|
+
</element>
|
11
|
+
</define>
|
12
|
+
<define name="recommendation">
|
13
|
+
<element name="recommendation">
|
14
|
+
<ref name="RequirementType"/>
|
15
|
+
</element>
|
16
|
+
</define>
|
17
|
+
<define name="permission">
|
18
|
+
<element name="permission">
|
19
|
+
<ref name="RequirementType"/>
|
20
|
+
</element>
|
21
|
+
</define>
|
22
|
+
<define name="RequirementType">
|
23
|
+
<optional>
|
24
|
+
<attribute name="obligation">
|
25
|
+
<ref name="ObligationType"/>
|
26
|
+
</attribute>
|
27
|
+
</optional>
|
28
|
+
<optional>
|
29
|
+
<attribute name="unnumbered">
|
30
|
+
<data type="boolean"/>
|
31
|
+
</attribute>
|
32
|
+
</optional>
|
33
|
+
<optional>
|
34
|
+
<attribute name="number"/>
|
35
|
+
</optional>
|
36
|
+
<optional>
|
37
|
+
<attribute name="subsequence"/>
|
38
|
+
</optional>
|
39
|
+
<optional>
|
40
|
+
<attribute name="keep-with-next">
|
41
|
+
<data type="boolean"/>
|
42
|
+
</attribute>
|
43
|
+
</optional>
|
44
|
+
<optional>
|
45
|
+
<attribute name="keep-lines-together">
|
46
|
+
<data type="boolean"/>
|
47
|
+
</attribute>
|
48
|
+
</optional>
|
49
|
+
<attribute name="id">
|
50
|
+
<data type="ID"/>
|
51
|
+
</attribute>
|
52
|
+
<optional>
|
53
|
+
<attribute name="filename"/>
|
54
|
+
</optional>
|
55
|
+
<optional>
|
56
|
+
<attribute name="model"/>
|
57
|
+
</optional>
|
58
|
+
<optional>
|
59
|
+
<attribute name="type"/>
|
60
|
+
</optional>
|
61
|
+
<optional>
|
62
|
+
<ref name="reqtitle"/>
|
63
|
+
</optional>
|
64
|
+
<optional>
|
65
|
+
<ref name="label"/>
|
66
|
+
</optional>
|
67
|
+
<optional>
|
68
|
+
<ref name="subject"/>
|
69
|
+
</optional>
|
70
|
+
<zeroOrMore>
|
71
|
+
<ref name="reqinherit"/>
|
72
|
+
</zeroOrMore>
|
73
|
+
<zeroOrMore>
|
74
|
+
<ref name="classification"/>
|
75
|
+
</zeroOrMore>
|
76
|
+
<zeroOrMore>
|
77
|
+
<choice>
|
78
|
+
<ref name="measurementtarget"/>
|
79
|
+
<ref name="specification"/>
|
80
|
+
<ref name="verification"/>
|
81
|
+
<ref name="import"/>
|
82
|
+
<ref name="description"/>
|
83
|
+
</choice>
|
84
|
+
</zeroOrMore>
|
85
|
+
<optional>
|
86
|
+
<ref name="reqt_references"/>
|
87
|
+
</optional>
|
88
|
+
<zeroOrMore>
|
89
|
+
<choice>
|
90
|
+
<ref name="requirement"/>
|
91
|
+
<ref name="recommendation"/>
|
92
|
+
<ref name="permission"/>
|
93
|
+
</choice>
|
94
|
+
</zeroOrMore>
|
95
|
+
</define>
|
96
|
+
<define name="reqtitle">
|
97
|
+
<element name="title">
|
98
|
+
<ref name="FormattedString"/>
|
99
|
+
</element>
|
100
|
+
</define>
|
101
|
+
<define name="label">
|
102
|
+
<element name="label">
|
103
|
+
<text/>
|
104
|
+
</element>
|
105
|
+
</define>
|
106
|
+
<define name="subject">
|
107
|
+
<element name="subject">
|
108
|
+
<text/>
|
109
|
+
</element>
|
110
|
+
</define>
|
111
|
+
<define name="reqinherit">
|
112
|
+
<element name="inherit">
|
113
|
+
<text/>
|
114
|
+
</element>
|
115
|
+
</define>
|
116
|
+
<define name="measurementtarget">
|
117
|
+
<element name="measurement-target">
|
118
|
+
<ref name="RequirementSubpart"/>
|
119
|
+
</element>
|
120
|
+
</define>
|
121
|
+
<define name="specification">
|
122
|
+
<element name="specification">
|
123
|
+
<ref name="RequirementSubpart"/>
|
124
|
+
</element>
|
125
|
+
</define>
|
126
|
+
<define name="verification">
|
127
|
+
<element name="verification">
|
128
|
+
<ref name="RequirementSubpart"/>
|
129
|
+
</element>
|
130
|
+
</define>
|
131
|
+
<define name="import">
|
132
|
+
<element name="import">
|
133
|
+
<ref name="RequirementSubpart"/>
|
134
|
+
</element>
|
135
|
+
</define>
|
136
|
+
<define name="description">
|
137
|
+
<element name="description">
|
138
|
+
<ref name="RequirementSubpart"/>
|
139
|
+
</element>
|
140
|
+
</define>
|
141
|
+
<define name="reqt_references">
|
142
|
+
<element name="references">
|
143
|
+
<oneOrMore>
|
144
|
+
<ref name="bibitem"/>
|
145
|
+
</oneOrMore>
|
146
|
+
</element>
|
147
|
+
</define>
|
148
|
+
<define name="RequirementSubpart">
|
149
|
+
<optional>
|
150
|
+
<attribute name="type"/>
|
151
|
+
</optional>
|
152
|
+
<optional>
|
153
|
+
<attribute name="exclude">
|
154
|
+
<data type="boolean"/>
|
155
|
+
</attribute>
|
156
|
+
</optional>
|
157
|
+
<optional>
|
158
|
+
<attribute name="keep-with-next">
|
159
|
+
<data type="boolean"/>
|
160
|
+
</attribute>
|
161
|
+
</optional>
|
162
|
+
<optional>
|
163
|
+
<attribute name="keep-lines-together">
|
164
|
+
<data type="boolean"/>
|
165
|
+
</attribute>
|
166
|
+
</optional>
|
167
|
+
<oneOrMore>
|
168
|
+
<ref name="BasicBlock"/>
|
169
|
+
</oneOrMore>
|
170
|
+
</define>
|
171
|
+
<define name="ObligationType">
|
172
|
+
<choice>
|
173
|
+
<value>requirement</value>
|
174
|
+
<value>recommendation</value>
|
175
|
+
<value>permission</value>
|
176
|
+
</choice>
|
177
|
+
</define>
|
178
|
+
<define name="classification">
|
179
|
+
<element name="classification">
|
180
|
+
<ref name="classification_tag"/>
|
181
|
+
<ref name="classification_value"/>
|
182
|
+
</element>
|
183
|
+
</define>
|
184
|
+
<define name="classification_tag">
|
185
|
+
<element name="tag">
|
186
|
+
<text/>
|
187
|
+
</element>
|
188
|
+
</define>
|
189
|
+
<define name="classification_value">
|
190
|
+
<element name="value">
|
191
|
+
<text/>
|
192
|
+
</element>
|
193
|
+
</define>
|
194
|
+
</grammar>
|
@@ -0,0 +1,224 @@
|
|
1
|
+
require_relative "./validate_requirement"
|
2
|
+
require_relative "./validate_list"
|
3
|
+
|
4
|
+
module Asciidoctor
|
5
|
+
module BSI
|
6
|
+
class Converter < ISO::Converter
|
7
|
+
# BSI 0:2016 9.4.1
|
8
|
+
def doctype_validate(xmldoc)
|
9
|
+
doctype = xmldoc&.at("//bibdata/ext/doctype")&.text
|
10
|
+
%w(specification management-systems-standard code-of-practice
|
11
|
+
guide method-of-test method-of-specifying vocabulary
|
12
|
+
classification).include? doctype or
|
13
|
+
@log.add("Document Attributes", nil,
|
14
|
+
"#{doctype} is not a recognised document type")
|
15
|
+
end
|
16
|
+
|
17
|
+
def validate(doc)
|
18
|
+
content_validate(doc)
|
19
|
+
schema_validate(formattedstr_strip(doc.dup),
|
20
|
+
File.join(File.dirname(__FILE__), "bsi.rng"))
|
21
|
+
end
|
22
|
+
|
23
|
+
def image_name_validate(xmldoc); end
|
24
|
+
|
25
|
+
def norm_ref_validate(doc); end
|
26
|
+
|
27
|
+
def style(node, text)
|
28
|
+
super
|
29
|
+
style_plusminus(node, text)
|
30
|
+
style_subscript(node)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Rules for Structure 27.5
|
34
|
+
def style_plusminus(node, text)
|
35
|
+
style_regex(/\s*(?<num>\S+\u00b1\s*\S+)/,
|
36
|
+
"no space before plus-minus sign", node, text)
|
37
|
+
style_regex(/\s*(?<num>\S+\s*\u00b1\s+\S+)/,
|
38
|
+
"space after plus-minus sign", node, text)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Rules for Structure 27.6
|
42
|
+
def style_subscript(node)
|
43
|
+
node.xpath(".//sub[.//sub]").each do |r|
|
44
|
+
style_warning(node, "Nested subscript", r)
|
45
|
+
end
|
46
|
+
node.xpath(".//m:msub[.//m:msub]", "m" => MATHML_NS).each do |r|
|
47
|
+
style_warning(node, "Nested subscript", r)
|
48
|
+
end
|
49
|
+
node.xpath(".//sup[.//sup]").each do |r|
|
50
|
+
style_warning(node, "Nested superscript", r)
|
51
|
+
end
|
52
|
+
node.xpath(".//m:msup[.//m:msup]", "m" => MATHML_NS).each do |r|
|
53
|
+
style_warning(node, "Nested superscript", r)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# protest decimal comma not decimal point
|
58
|
+
# TODO we will not yet override decimal comma warning if this is a National Annex to Eurocode (Rules for Structure Annex B)
|
59
|
+
def style_number(node, text)
|
60
|
+
style_two_regex_not_prev(
|
61
|
+
node, text, /^(?<num>-?[0-9]{4,}[,0-9]*)$/,
|
62
|
+
%r{\b(ISO|IEC|IEEE/|(in|January|February|March|April|May|June|August|September|October|November|December)\b)$},
|
63
|
+
"number not broken up in threes"
|
64
|
+
)
|
65
|
+
style_regex(/\b(?<num>[0-9]+,[0-9]+)/i,
|
66
|
+
"possible decimal comma", node, text)
|
67
|
+
style_regex(/\b(?<num>billions?)\b/i,
|
68
|
+
"ambiguous number", node, text)
|
69
|
+
ordinal_check(node)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Rules for Structure 9.1
|
73
|
+
def ordinal_check(node)
|
74
|
+
node.xpath(".//sup").each do |s|
|
75
|
+
next unless %w(st nd rd th).include? s.text
|
76
|
+
|
77
|
+
style_warning(s, "text contains ordinal superscript", s.text)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def section_style(root)
|
82
|
+
super
|
83
|
+
@doctype = root.at("//bibdata/ext/doctype")&.text
|
84
|
+
@type = @doctype.gsub(/-/, " ").split.map(&:capitalize).join(" ")
|
85
|
+
informative_text_style(root)
|
86
|
+
normative_text_style(root)
|
87
|
+
avoid_must(root)
|
88
|
+
annex_validate(root)
|
89
|
+
end
|
90
|
+
|
91
|
+
def annex_validate(root)
|
92
|
+
annex_normative_validate(root)
|
93
|
+
annex_ordering_validate(root)
|
94
|
+
end
|
95
|
+
|
96
|
+
# Rules for Structure 20.2
|
97
|
+
def annex_normative_validate(root)
|
98
|
+
@doctype == "guide" and root.xpath("//annex[@obligation = 'normative']")
|
99
|
+
.each do |s|
|
100
|
+
style_warning(s, "Guide contains normative annex",
|
101
|
+
s&.at("./title")&.text)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# Rules for Structure 20.4
|
106
|
+
def annex_ordering_validate(root)
|
107
|
+
ids = citation_order(root.xpath("//annex"))
|
108
|
+
cite_order = ids.keys.sort { |a, b| ids[a] <=> ids[b] }
|
109
|
+
annex_order = root.xpath("//annex").map { |x| x["id"] }
|
110
|
+
cite_order.each_with_index do |a, i|
|
111
|
+
next if annex_order[i] == a
|
112
|
+
|
113
|
+
annex = root.at("//annex[@id = '#{a}']")
|
114
|
+
title = annex&.at("./title")&.text || "Annex #{a}"
|
115
|
+
style_warning(annex, "#{title} should be annex ##{i + 1}", nil)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
BSI_PUBLISHER_XPATH =
|
120
|
+
"./contributor[role/@type = 'publisher']/"\
|
121
|
+
"organization[abbreviation = 'ISO' or abbreviation = 'IEC' or "\
|
122
|
+
"abbreviation = 'BSI' or abbreviation = 'CEN' or "\
|
123
|
+
"abbreviation = 'CENELEC']".freeze
|
124
|
+
|
125
|
+
NORM_BSI_WARN = "reference other than BSI, CEN, CENELEC, ISO, IEC "\
|
126
|
+
"not expected as normative".freeze
|
127
|
+
|
128
|
+
# Rules for Structure 10.2
|
129
|
+
def norm_bibitem_style(root)
|
130
|
+
root.xpath(NORM_BIBITEMS).each do |b|
|
131
|
+
b.at(BSI_PUBLISHER_XPATH).nil? and
|
132
|
+
@log.add("Style", b, "#{NORM_BSI_WARN}: #{b.text}")
|
133
|
+
status = b&.at("./status/stage")&.text
|
134
|
+
/^9.$/.match?(status) and
|
135
|
+
@log.add("Style", b,
|
136
|
+
"Do not cite withdrawn standards as normative: #{b.text}")
|
137
|
+
/^[0-5].$/.match?(status) and @log.add(
|
138
|
+
"Style", b,
|
139
|
+
"Do not cite unpublished standards as normative: #{b.text}"
|
140
|
+
)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# Rules for Structure 11.5.2
|
145
|
+
def title_names_type_validate(root)
|
146
|
+
super
|
147
|
+
doctypes = /British\sStandard/xi
|
148
|
+
title_main_en = title_lang_part(root, "main", "en")
|
149
|
+
!title_main_en.nil? && doctypes.match(title_main_en.text) and
|
150
|
+
@log.add("Style", title_main_en, "Main Title may name document type")
|
151
|
+
title_intro_en = title_lang_part(root, "intro", "en")
|
152
|
+
!title_intro_en.nil? && doctypes.match(title_intro_en.text) and
|
153
|
+
@log.add("Style", title_intro_en,
|
154
|
+
"Title Intro may name document type")
|
155
|
+
end
|
156
|
+
|
157
|
+
# Rules for Structure 16.5.5
|
158
|
+
def termdef_style(xmldoc)
|
159
|
+
super
|
160
|
+
xmldoc.xpath("//term").each do |t|
|
161
|
+
para = t.at("./definition") || return
|
162
|
+
term = t.at("./preferred").text.strip
|
163
|
+
termdef_warn(para.text, /^[A-Z]/, t, term,
|
164
|
+
"term definition starts with upper case character")
|
165
|
+
termdef_warn(para.text, /\b#{term.downcase}\b/i, t, term,
|
166
|
+
"term definition may be circular")
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def content_validate(doc)
|
171
|
+
super
|
172
|
+
symbol_style(doc)
|
173
|
+
table_validate(doc)
|
174
|
+
listcount_validate(doc)
|
175
|
+
list_punctuation(doc)
|
176
|
+
end
|
177
|
+
|
178
|
+
# Rules for Structure 17.5
|
179
|
+
def symbol_style(xmldoc)
|
180
|
+
return if @novalid
|
181
|
+
|
182
|
+
xmldoc.xpath("//definitions//dd").each do |para|
|
183
|
+
term = para&.at("./preceding::dt[1]")&.text&.strip || "[symbol]"
|
184
|
+
termdef_warn(para.text, /^(the|a)\b/i, para, term,
|
185
|
+
"symbol definition starts with article")
|
186
|
+
termdef_warn(para.text, /\.$/i, para, term,
|
187
|
+
"symbol definition ends with period")
|
188
|
+
termdef_warn(para.text, /^[A-Z]/, para, term,
|
189
|
+
"symbol definition starts with upper case character")
|
190
|
+
termdef_warn(para.text, /\b#{term.downcase}\b/i, para, term,
|
191
|
+
"symbol definition may be circular")
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
# Rules for Structure 22.3.2
|
196
|
+
def subclause_validate(root)
|
197
|
+
return if @novalid
|
198
|
+
|
199
|
+
root.xpath("//clause/clause/clause/clause/clause/clause")
|
200
|
+
.each do |c|
|
201
|
+
style_warning(c, "Exceeds the maximum clause depth of 5", nil)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
# Rules for Structure 29.6
|
206
|
+
def table_validate(xmldoc)
|
207
|
+
xmldoc.xpath("//td[not(./*) and normalize-space(.)=''] | "\
|
208
|
+
"//th[not(./*) and normalize-space(.)='']").each do |td|
|
209
|
+
style_warning(td, "Empty table cell", nil)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
# TODO: we will not block foreword from National Annex to Eurocode (Rules for Structure G.6.1)
|
214
|
+
#
|
215
|
+
# TODO: we will not test location of commentaries (Rules for Structure 24.7)
|
216
|
+
#
|
217
|
+
# TODO: we will not check for space either side of mathematical sign (Rules for Structure 27.5)
|
218
|
+
#
|
219
|
+
# TODO: we will not check for conflict of ln and log_e or log lg log_10 (Rules for Structure 27.8)
|
220
|
+
#
|
221
|
+
# TODO: we will not check order of brackets in stem as {[( (Rules for Structure 27.9)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Asciidoctor
|
2
|
+
module BSI
|
3
|
+
class Converter < ISO::Converter
|
4
|
+
# Rules for Structure 23.3
|
5
|
+
def listcount_validate(doc)
|
6
|
+
return if @novalid
|
7
|
+
|
8
|
+
doc.xpath("//clause[not(.//clause)] | //annex").each do |c|
|
9
|
+
next if c.xpath(".//ol").empty?
|
10
|
+
|
11
|
+
ols = c.xpath(".//ol") - c.xpath(".//ul//ol | .//ol//ol")
|
12
|
+
ols.size > 3 and
|
13
|
+
style_warning(c, "More than 3 ordered lists in a numbered clause",
|
14
|
+
nil)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Rules for Structure 23.5
|
19
|
+
def list_punctuation(doc)
|
20
|
+
return if @novalid
|
21
|
+
|
22
|
+
((doc.xpath("//ol") - doc.xpath("//ul//ol | //ol//ol")) +
|
23
|
+
(doc.xpath("//ul") - doc.xpath("//ul//ul | //ol//ul"))).each do |list|
|
24
|
+
prec = list.previous_element
|
25
|
+
prec&.name == "p" or
|
26
|
+
style_warning(list, "All lists must be preceded by "\
|
27
|
+
"introductory phrase", nil)
|
28
|
+
list_punctuation1(list, prec.text)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def list_punctuation1(list, prectext)
|
33
|
+
entries = list.xpath(".//li")
|
34
|
+
case prectext.sub(/^.*?(\S)\s*$/, "\\1")
|
35
|
+
when ":"
|
36
|
+
list.xpath(".//li").each_with_index do |li, i|
|
37
|
+
list_semicolon_phrase(li, i == entries.size - 1)
|
38
|
+
end
|
39
|
+
when "." then entries.each { |li| list_full_sentence(li) }
|
40
|
+
else style_warning(list, "All lists must be preceded by "\
|
41
|
+
"colon or full stop", prectext)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def list_semicolon_phrase(elem, last)
|
46
|
+
text = elem.text.strip
|
47
|
+
text.match?(/^[^A-Za-z]*[a-z]/) or
|
48
|
+
style_warning(elem, "List entry after colon must start with "\
|
49
|
+
"lowercase letter", text)
|
50
|
+
punct = text.sub(/^.*?(\S)\s*$/, "\\1")
|
51
|
+
if last
|
52
|
+
punct == "." or style_warning(elem, "Final list entry after colon "\
|
53
|
+
"must end with full stop", text)
|
54
|
+
else
|
55
|
+
punct == ";" or style_warning(elem, "List entry after colon must "\
|
56
|
+
"end with semicolon", text)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def list_full_sentence(elem)
|
61
|
+
text = elem.text.strip
|
62
|
+
text.match?(/^[^A-Za-z]*[A-Z]/) or
|
63
|
+
style_warning(elem, "List entry after full stop must start with "\
|
64
|
+
"uppercase letter", text)
|
65
|
+
punct = text.sub(/^.*?(\S)\s*$/, "\\1")
|
66
|
+
punct == "." or
|
67
|
+
style_warning(elem, "List entry after full stop must "\
|
68
|
+
"end with full stop", text)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|