slaw 5.0.0 → 6.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5ed924bc3ba2524cc7c23bf29d69aac408195ae35348e45ca6e7f6d14a018620
4
- data.tar.gz: 0ac2bc7e3a1089c56234cabaca35f8961a04db7960655f539412a21293c7ea09
3
+ metadata.gz: cdb72dfa4cdb03a7ff80f8d22e6f6dc5801b95902fb483b50df587a7618ce45b
4
+ data.tar.gz: 50df42fb88aa1a011598d6a021c19b4ecc49d8d32de51652ac3f9900da412160
5
5
  SHA512:
6
- metadata.gz: c43f632d52c957e236a117e33d228093f9c41387fca0743b62efa7195f327492a68fb23c215b985ace37f7c89582ad77ad4aecede444da0ace2fd0335437389c
7
- data.tar.gz: cc262fe65f346c9bf4b2d959121ec76c091e3aafd1f5f4d8e55e074082c8436f2fe50db5b777b33c7a8c12690fb3fc42f9aa60839fb5ff6733907254e82b0349
6
+ metadata.gz: dded061c797a8d698c81a649816f6201bf1f7214e93531a5a41a3156c75c3ff06ef76aacf6d65bdd7aa5abbab05dfe8c61d37a5daa3d261106b8c1729c750d7a
7
+ data.tar.gz: 1e071331cac41c9a65455c0053c9ba36f6c52d34d733ac59de547612075b322b4f3fd5393bba2d471049c6e8aaf2715eeb06c1a6d7f09b742cfd447f0260b5a5
data/README.md CHANGED
@@ -81,6 +81,12 @@ You can create your own grammar by creating a gem that provides these files and
81
81
 
82
82
  ## Changelog
83
83
 
84
+ ### 6.0.0 (7 Nov 2019)
85
+
86
+ * Give grammars the opportunity to post-process generated XML
87
+ * Move blocklist handling into postprocessing for ZA grammar
88
+ * ZA grammar rewrites schedule aliases to include full text content of headings
89
+
84
90
  ### 5.0.0 (25 Oct 2019)
85
91
 
86
92
  * Schedules have a new grammar to make it easier for users to understand headings and subheadings.
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'slaw/parse/grammar_helpers'
4
4
  require 'slaw/grammars/za/act_nodes'
5
+ require 'slaw/grammars/za/postprocess'
5
6
 
6
7
  require 'slaw/grammars/terminals'
7
8
  require 'slaw/grammars/tables'
@@ -13,6 +14,7 @@ module Slaw
13
14
  module ZA
14
15
  grammar Act
15
16
  include Slaw::Parse::GrammarHelpers
17
+ include Slaw::Grammars::ZA::Postprocess
16
18
 
17
19
  ########
18
20
  # major containers
@@ -0,0 +1,28 @@
1
+ require 'slaw/parse/blocklists'
2
+
3
+ module Slaw
4
+ module Grammars
5
+ module ZA
6
+ module Postprocess
7
+ def postprocess(doc)
8
+ Slaw::Parse::Blocklists.adjust_blocklists(doc)
9
+ schedule_aliases(doc)
10
+ doc
11
+ end
12
+
13
+ # Correct aliases for schedules to use the full textual content of the heading element
14
+ def schedule_aliases(doc)
15
+ for hcontainer in doc.xpath('//xmlns:doc/xmlns:mainBody/xmlns:hcontainer[@name="schedule"]')
16
+ heading = hcontainer.at_xpath('./xmlns:heading')
17
+ frbr_alias = hcontainer.at_xpath('../../xmlns:meta/xmlns:identification/xmlns:FRBRWork/xmlns:FRBRalias')
18
+
19
+ if heading and frbr_alias
20
+ text = heading.xpath('.//text()').map(&:text).join('') || frbr_alias['value']
21
+ frbr_alias['value'] = text unless text.empty?
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -3,6 +3,11 @@ module Slaw
3
3
  module Blocklists
4
4
  include Slaw::Namespace
5
5
 
6
+ def self.adjust_blocklists(doc)
7
+ nest_blocklists(doc)
8
+ fix_intros(doc)
9
+ end
10
+
6
11
  # Correctly re-nest nested block lists that are tagged with the "renest" attribute.
7
12
  #
8
13
  # We do this by identifying the numbering format of each item in the list
@@ -185,22 +185,7 @@ module Slaw
185
185
  #
186
186
  # @return [Nokogiri::XML::Document] the updated document
187
187
  def postprocess(doc)
188
- adjust_blocklists(doc)
189
-
190
- doc
191
- end
192
-
193
- # Adjust blocklists:
194
- #
195
- # - nest them correctly
196
- # - change preceding p tags into listIntroductions
197
- #
198
- # @param doc [Nokogiri::XML::Document]
199
- def adjust_blocklists(doc)
200
- logger.info("Adjusting blocklists")
201
-
202
- Slaw::Parse::Blocklists.nest_blocklists(doc)
203
- Slaw::Parse::Blocklists.fix_intros(doc)
188
+ @parser.postprocess(doc)
204
189
  end
205
190
 
206
191
  protected
@@ -10,6 +10,14 @@ module Slaw
10
10
  def options
11
11
  @options ||= {}
12
12
  end
13
+
14
+ # Grammars can override this method to run post-processing on the resulting
15
+ # XML document.
16
+ #
17
+ # @param doc [Nokogiri::XML::Document]
18
+ # @return [Nokogiri::XML::Document]
19
+ def postprocess(doc)
20
+ end
13
21
  end
14
22
  end
15
23
  end
@@ -1,3 +1,3 @@
1
1
  module Slaw
2
- VERSION = "5.0.0"
2
+ VERSION = "6.0.0"
3
3
  end
@@ -0,0 +1,714 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'spec_helper'
4
+ require 'slaw'
5
+
6
+ describe Slaw::Parse::Blocklists do
7
+ describe '#adjust_blocklists' do
8
+ it 'should nest simple blocks' do
9
+ doc = xml2doc(subsection(<<XML
10
+ <blockList id="section-10.1.lst0" renest="true">
11
+ <item id="section-10.1.lst0.a">
12
+ <num>(a)</num>
13
+ <p>foo</p>
14
+ </item>
15
+ <item id="section-10.1.lst0.i">
16
+ <num>(i)</num>
17
+ <p>item-i</p>
18
+ </item>
19
+ <item id="section-10.1.lst0.ii">
20
+ <num>(ii)</num>
21
+ <p>item-ii</p>
22
+ </item>
23
+ <item id="section-10.1.lst0.iii">
24
+ <num>(iii)</num>
25
+ <p>item-iii</p>
26
+ </item>
27
+ <item id="section-10.1.lst0.aa">
28
+ <num>(aa)</num>
29
+ <p>item-aa</p>
30
+ </item>
31
+ <item id="section-10.1.lst0.bb">
32
+ <num>(bb)</num>
33
+ <p>item-bb</p>
34
+ </item>
35
+ </blockList>
36
+ XML
37
+ ))
38
+
39
+ subject.adjust_blocklists(doc)
40
+ doc.to_s.should == subsection(<<XML
41
+ <blockList id="section-10.1.lst0">
42
+ <item id="section-10.1.lst0.a">
43
+ <num>(a)</num>
44
+ <blockList id="section-10.1.lst0.a.list0">
45
+ <listIntroduction>foo</listIntroduction>
46
+ <item id="section-10.1.lst0.a.list0.i">
47
+ <num>(i)</num>
48
+ <p>item-i</p>
49
+ </item>
50
+ <item id="section-10.1.lst0.a.list0.ii">
51
+ <num>(ii)</num>
52
+ <p>item-ii</p>
53
+ </item>
54
+ <item id="section-10.1.lst0.a.list0.iii">
55
+ <num>(iii)</num>
56
+ <blockList id="section-10.1.lst0.a.list0.iii.list0">
57
+ <listIntroduction>item-iii</listIntroduction>
58
+ <item id="section-10.1.lst0.a.list0.iii.list0.aa">
59
+ <num>(aa)</num>
60
+ <p>item-aa</p>
61
+ </item>
62
+ <item id="section-10.1.lst0.a.list0.iii.list0.bb">
63
+ <num>(bb)</num>
64
+ <p>item-bb</p>
65
+ </item>
66
+ </blockList>
67
+ </item>
68
+ </blockList>
69
+ </item>
70
+ </blockList>
71
+ XML
72
+ )
73
+ end
74
+
75
+ # -------------------------------------------------------------------------
76
+
77
+ it 'should jump back up a level' do
78
+ doc = xml2doc(subsection(<<XML
79
+ <blockList id="section-10.1.lst0" renest="true">
80
+ <item id="section-10.1.lst0.a">
81
+ <num>(a)</num>
82
+ <p>foo</p>
83
+ </item>
84
+ <item id="section-10.1.lst0.i">
85
+ <num>(i)</num>
86
+ <p>item-i</p>
87
+ </item>
88
+ <item id="section-10.1.lst0.ii">
89
+ <num>(ii)</num>
90
+ <p>item-ii</p>
91
+ </item>
92
+ <item id="section-10.1.lst0.c">
93
+ <num>(c)</num>
94
+ <p>item-c</p>
95
+ </item>
96
+ </blockList>
97
+ XML
98
+ ))
99
+
100
+ subject.adjust_blocklists(doc)
101
+ doc.to_s.should == subsection(<<XML
102
+ <blockList id="section-10.1.lst0">
103
+ <item id="section-10.1.lst0.a">
104
+ <num>(a)</num>
105
+ <blockList id="section-10.1.lst0.a.list0">
106
+ <listIntroduction>foo</listIntroduction>
107
+ <item id="section-10.1.lst0.a.list0.i">
108
+ <num>(i)</num>
109
+ <p>item-i</p>
110
+ </item>
111
+ <item id="section-10.1.lst0.a.list0.ii">
112
+ <num>(ii)</num>
113
+ <p>item-ii</p>
114
+ </item>
115
+ </blockList>
116
+ </item>
117
+ <item id="section-10.1.lst0.c">
118
+ <num>(c)</num>
119
+ <p>item-c</p>
120
+ </item>
121
+ </blockList>
122
+ XML
123
+ )
124
+ end
125
+
126
+ # -------------------------------------------------------------------------
127
+
128
+ it 'should handle (i) correctly' do
129
+ doc = xml2doc(subsection(<<XML
130
+ <blockList id="section-10.1.lst0" renest="true">
131
+ <item id="section-10.1.lst0.h">
132
+ <num>(h)</num>
133
+ <p>foo</p>
134
+ </item>
135
+ <item id="section-10.1.lst0.i">
136
+ <num>(i)</num>
137
+ <p>item-i</p>
138
+ </item>
139
+ <item id="section-10.1.lst0.j">
140
+ <num>(j)</num>
141
+ <p>item-ii</p>
142
+ </item>
143
+ </blockList>
144
+ XML
145
+ ))
146
+
147
+ subject.adjust_blocklists(doc)
148
+ doc.to_s.should == subsection(<<XML
149
+ <blockList id="section-10.1.lst0">
150
+ <item id="section-10.1.lst0.h">
151
+ <num>(h)</num>
152
+ <p>foo</p>
153
+ </item>
154
+ <item id="section-10.1.lst0.i">
155
+ <num>(i)</num>
156
+ <p>item-i</p>
157
+ </item>
158
+ <item id="section-10.1.lst0.j">
159
+ <num>(j)</num>
160
+ <p>item-ii</p>
161
+ </item>
162
+ </blockList>
163
+ XML
164
+ )
165
+ end
166
+
167
+ # -------------------------------------------------------------------------
168
+
169
+ it 'should handle (u) (v) and (x) correctly' do
170
+ doc = xml2doc(subsection(<<XML
171
+ <blockList id="section-10.1.lst0" renest="true">
172
+ <item id="section-10.1.lst0.t">
173
+ <num>(t)</num>
174
+ <p>foo</p>
175
+ </item>
176
+ <item id="section-10.1.lst0.u">
177
+ <num>(u)</num>
178
+ <p>item-i</p>
179
+ </item>
180
+ <item id="section-10.1.lst0.v">
181
+ <num>(v)</num>
182
+ <p>item-ii</p>
183
+ </item>
184
+ <item id="section-10.1.lst0.w">
185
+ <num>(w)</num>
186
+ <p>item-ii</p>
187
+ </item>
188
+ <item id="section-10.1.lst0.x">
189
+ <num>(x)</num>
190
+ <p>item-ii</p>
191
+ </item>
192
+ </blockList>
193
+ XML
194
+ ))
195
+
196
+ subject.adjust_blocklists(doc)
197
+ doc.to_s.should == subsection(<<XML
198
+ <blockList id="section-10.1.lst0">
199
+ <item id="section-10.1.lst0.t">
200
+ <num>(t)</num>
201
+ <p>foo</p>
202
+ </item>
203
+ <item id="section-10.1.lst0.u">
204
+ <num>(u)</num>
205
+ <p>item-i</p>
206
+ </item>
207
+ <item id="section-10.1.lst0.v">
208
+ <num>(v)</num>
209
+ <p>item-ii</p>
210
+ </item>
211
+ <item id="section-10.1.lst0.w">
212
+ <num>(w)</num>
213
+ <p>item-ii</p>
214
+ </item>
215
+ <item id="section-10.1.lst0.x">
216
+ <num>(x)</num>
217
+ <p>item-ii</p>
218
+ </item>
219
+ </blockList>
220
+ XML
221
+ )
222
+ end
223
+
224
+
225
+ # -------------------------------------------------------------------------
226
+
227
+ it 'should handle (j) correctly' do
228
+ doc = xml2doc(subsection(<<XML
229
+ <blockList id="section-28.3.list2" renest="true">
230
+ <item id="section-28.3.list2.g">
231
+ <num>(g)</num>
232
+ <p>all <term refersTo="#term-memorial_work" id="trm381">memorial work</term> up to 150 mm in thickness must be securely attached to the base;</p>
233
+ </item>
234
+ <item id="section-28.3.list2.h">
235
+ <num>(h)</num>
236
+ <p>all the components of <term refersTo="#term-memorial_work" id="trm382">memorial work</term> must be completed before being brought into a <term refersTo="#term-cemetery" id="trm383">cemetery</term>;</p>
237
+ </item>
238
+ <item id="section-28.3.list2.i">
239
+ <num>(i)</num>
240
+ <p>footstones must consist of one solid piece;</p>
241
+ </item>
242
+ <item id="section-28.3.list2.j">
243
+ <num>(j)</num>
244
+ <p>in all cases where <term refersTo="#term-memorial_work" id="trm384">memorial work</term> rests on a base -</p>
245
+ </item>
246
+ <item id="section-28.3.list2.i">
247
+ <num>(i)</num>
248
+ <p>such <term refersTo="#term-memorial_work" id="trm385">memorial work</term> must have a foundation;</p>
249
+ </item>
250
+ <item id="section-28.3.list2.ii">
251
+ <num>(ii)</num>
252
+ <p>such <term refersTo="#term-memorial_work" id="trm386">memorial work</term> must be set with cement mortar;</p>
253
+ </item>
254
+ <item id="section-28.3.list2.iii">
255
+ <num>(iii)</num>
256
+ <p>the bottom base of a single <term refersTo="#term-memorial_work" id="trm387">memorial work</term> must not be less than 900mm long 220 mm wide x 250 mm thick and that of a double <term refersTo="#term-memorial_work" id="trm388">memorial work</term> not less than 2 286 mm long x 200 mm wide x 250 mm thick; and</p>
257
+ </item>
258
+ </blockList>
259
+ XML
260
+ ))
261
+
262
+ subject.adjust_blocklists(doc)
263
+ doc.to_s.should == subsection(<<XML
264
+ <blockList id="section-28.3.list2">
265
+ <item id="section-28.3.list2.g">
266
+ <num>(g)</num>
267
+ <p>all <term refersTo="#term-memorial_work" id="trm381">memorial work</term> up to 150 mm in thickness must be securely attached to the base;</p>
268
+ </item>
269
+ <item id="section-28.3.list2.h">
270
+ <num>(h)</num>
271
+ <p>all the components of <term refersTo="#term-memorial_work" id="trm382">memorial work</term> must be completed before being brought into a <term refersTo="#term-cemetery" id="trm383">cemetery</term>;</p>
272
+ </item>
273
+ <item id="section-28.3.list2.i">
274
+ <num>(i)</num>
275
+ <p>footstones must consist of one solid piece;</p>
276
+ </item>
277
+ <item id="section-28.3.list2.j">
278
+ <num>(j)</num>
279
+ <blockList id="section-28.3.list2.j.list0">
280
+ <listIntroduction>in all cases where <term refersTo="#term-memorial_work" id="trm384">memorial work</term> rests on a base -</listIntroduction>
281
+ <item id="section-28.3.list2.j.list0.i">
282
+ <num>(i)</num>
283
+ <p>such <term refersTo="#term-memorial_work" id="trm385">memorial work</term> must have a foundation;</p>
284
+ </item>
285
+ <item id="section-28.3.list2.j.list0.ii">
286
+ <num>(ii)</num>
287
+ <p>such <term refersTo="#term-memorial_work" id="trm386">memorial work</term> must be set with cement mortar;</p>
288
+ </item>
289
+ <item id="section-28.3.list2.j.list0.iii">
290
+ <num>(iii)</num>
291
+ <p>the bottom base of a single <term refersTo="#term-memorial_work" id="trm387">memorial work</term> must not be less than 900mm long 220 mm wide x 250 mm thick and that of a double <term refersTo="#term-memorial_work" id="trm388">memorial work</term> not less than 2 286 mm long x 200 mm wide x 250 mm thick; and</p>
292
+ </item>
293
+ </blockList>
294
+ </item>
295
+ </blockList>
296
+ XML
297
+ )
298
+ end
299
+
300
+ # -------------------------------------------------------------------------
301
+ it 'should handle (I) correctly' do
302
+ doc = xml2doc(subsection(<<XML
303
+ <blockList id="section-28.3.list2" renest="true">
304
+ <item id="section-28.3.list2.g">
305
+ <num>(g)</num>
306
+ <p>all memorial work up to 150 mm in thickness must be securely attached to the base;</p>
307
+ </item>
308
+ <item id="section-28.3.list2.h">
309
+ <num>(h)</num>
310
+ <p>all the components of memorial work must be completed before being brought into a cemetery;</p>
311
+ </item>
312
+ <item id="section-28.3.list2.i">
313
+ <num>(i)</num>
314
+ <p>item i</p>
315
+ </item>
316
+ <item id="section-28.3.list2.I">
317
+ <num>(I)</num>
318
+ <p>a subitem</p>
319
+ </item>
320
+ <item id="section-28.3.list2.II">
321
+ <num>(II)</num>
322
+ <p>another subitem</p>
323
+ </item>
324
+ <item id="section-28.3.list2.j">
325
+ <num>(j)</num>
326
+ <p>in all cases where memorial work rests on a base -</p>
327
+ </item>
328
+ <item id="section-28.3.list2.i">
329
+ <num>(i)</num>
330
+ <p>such memorial work must have a foundation;</p>
331
+ </item>
332
+ <item id="section-28.3.list2.ii">
333
+ <num>(ii)</num>
334
+ <p>such memorial work must be set with cement mortar;</p>
335
+ </item>
336
+ <item id="section-28.3.list2.iii">
337
+ <num>(iii)</num>
338
+ <p>the bottom base of a single memorial work must not be less than 900mm long 220 mm wide x 250 mm thick and that of a double memorial work not less than 2 286 mm long x 200 mm wide x 250 mm thick; and</p>
339
+ </item>
340
+ </blockList>
341
+ XML
342
+ ))
343
+
344
+ subject.adjust_blocklists(doc)
345
+ doc.to_s.should == subsection(<<XML
346
+ <blockList id="section-28.3.list2">
347
+ <item id="section-28.3.list2.g">
348
+ <num>(g)</num>
349
+ <p>all memorial work up to 150 mm in thickness must be securely attached to the base;</p>
350
+ </item>
351
+ <item id="section-28.3.list2.h">
352
+ <num>(h)</num>
353
+ <p>all the components of memorial work must be completed before being brought into a cemetery;</p>
354
+ </item>
355
+ <item id="section-28.3.list2.i">
356
+ <num>(i)</num>
357
+ <blockList id="section-28.3.list2.i.list0">
358
+ <listIntroduction>item i</listIntroduction>
359
+ <item id="section-28.3.list2.i.list0.I">
360
+ <num>(I)</num>
361
+ <p>a subitem</p>
362
+ </item>
363
+ <item id="section-28.3.list2.i.list0.II">
364
+ <num>(II)</num>
365
+ <p>another subitem</p>
366
+ </item>
367
+ </blockList>
368
+ </item>
369
+ <item id="section-28.3.list2.j">
370
+ <num>(j)</num>
371
+ <blockList id="section-28.3.list2.j.list1">
372
+ <listIntroduction>in all cases where memorial work rests on a base -</listIntroduction>
373
+ <item id="section-28.3.list2.j.list1.i">
374
+ <num>(i)</num>
375
+ <p>such memorial work must have a foundation;</p>
376
+ </item>
377
+ <item id="section-28.3.list2.j.list1.ii">
378
+ <num>(ii)</num>
379
+ <p>such memorial work must be set with cement mortar;</p>
380
+ </item>
381
+ <item id="section-28.3.list2.j.list1.iii">
382
+ <num>(iii)</num>
383
+ <p>the bottom base of a single memorial work must not be less than 900mm long 220 mm wide x 250 mm thick and that of a double memorial work not less than 2 286 mm long x 200 mm wide x 250 mm thick; and</p>
384
+ </item>
385
+ </blockList>
386
+ </item>
387
+ </blockList>
388
+ XML
389
+ )
390
+ end
391
+
392
+ # -------------------------------------------------------------------------
393
+
394
+ it 'should treat (aa) after (z) as siblings' do
395
+ doc = xml2doc(subsection(<<XML
396
+ <blockList id="list0">
397
+ <item id="list0.y">
398
+ <num>(y)</num>
399
+ <p>foo</p>
400
+ </item>
401
+ <item id="list0.z">
402
+ <num>(z)</num>
403
+ <p>item-z</p>
404
+ </item>
405
+ <item id="list0.aa">
406
+ <num>(aa)</num>
407
+ <p>item-aa</p>
408
+ </item>
409
+ <item id="list0.bb">
410
+ <num>(bb)</num>
411
+ <p>item-bb</p>
412
+ </item>
413
+ </blockList>
414
+ XML
415
+ ))
416
+
417
+ subject.adjust_blocklists(doc)
418
+ doc.to_s.should == subsection(<<XML
419
+ <blockList id="list0">
420
+ <item id="list0.y">
421
+ <num>(y)</num>
422
+ <p>foo</p>
423
+ </item>
424
+ <item id="list0.z">
425
+ <num>(z)</num>
426
+ <p>item-z</p>
427
+ </item>
428
+ <item id="list0.aa">
429
+ <num>(aa)</num>
430
+ <p>item-aa</p>
431
+ </item>
432
+ <item id="list0.bb">
433
+ <num>(bb)</num>
434
+ <p>item-bb</p>
435
+ </item>
436
+ </blockList>
437
+ XML
438
+ )
439
+ end
440
+
441
+ # -------------------------------------------------------------------------
442
+
443
+ it 'should treat (AA) after (z) a sublist' do
444
+ doc = xml2doc(subsection(<<XML
445
+ <blockList id="list0" renest="true">
446
+ <item id="list0.y">
447
+ <num>(y)</num>
448
+ <p>foo</p>
449
+ </item>
450
+ <item id="list0.z">
451
+ <num>(z)</num>
452
+ <p>item-z</p>
453
+ </item>
454
+ <item id="list0.AA">
455
+ <num>(AA)</num>
456
+ <p>item-AA</p>
457
+ </item>
458
+ <item id="list0.BB">
459
+ <num>(BB)</num>
460
+ <p>item-BB</p>
461
+ </item>
462
+ </blockList>
463
+ XML
464
+ ))
465
+
466
+ subject.adjust_blocklists(doc)
467
+ doc.to_s.should == subsection(<<XML
468
+ <blockList id="list0">
469
+ <item id="list0.y">
470
+ <num>(y)</num>
471
+ <p>foo</p>
472
+ </item>
473
+ <item id="list0.z">
474
+ <num>(z)</num>
475
+ <blockList id="list0.z.list0">
476
+ <listIntroduction>item-z</listIntroduction>
477
+ <item id="list0.z.list0.AA">
478
+ <num>(AA)</num>
479
+ <p>item-AA</p>
480
+ </item>
481
+ <item id="list0.z.list0.BB">
482
+ <num>(BB)</num>
483
+ <p>item-BB</p>
484
+ </item>
485
+ </blockList>
486
+ </item>
487
+ </blockList>
488
+ XML
489
+ )
490
+ end
491
+
492
+ # -------------------------------------------------------------------------
493
+
494
+ it 'should handle deeply nested lists' do
495
+ doc = xml2doc(subsection(<<XML
496
+ <blockList id="list0" renest="true">
497
+ <item id="list0.a">
498
+ <num>(a)</num>
499
+ <p>foo</p>
500
+ </item>
501
+ <item id="list0.b">
502
+ <num>(b)</num>
503
+ <p>item-b</p>
504
+ </item>
505
+ <item id="list0.i">
506
+ <num>(i)</num>
507
+ <p>item-b-i</p>
508
+ </item>
509
+ <item id="list0.aa">
510
+ <num>(aa)</num>
511
+ <p>item-i-aa</p>
512
+ </item>
513
+ <item id="list0.bb">
514
+ <num>(bb)</num>
515
+ <p>item-i-bb</p>
516
+ </item>
517
+ <item id="list0.ii">
518
+ <num>(ii)</num>
519
+ <p>item-b-ii</p>
520
+ </item>
521
+ <item id="list0.c">
522
+ <num>(c)</num>
523
+ <p>item-c</p>
524
+ </item>
525
+ <item id="list0.i">
526
+ <num>(i)</num>
527
+ <p>item-c-i</p>
528
+ </item>
529
+ <item id="list0.ii">
530
+ <num>(ii)</num>
531
+ <p>item-c-ii</p>
532
+ </item>
533
+ <item id="list0.iii">
534
+ <num>(iii)</num>
535
+ <p>item-c-iii</p>
536
+ </item>
537
+ </blockList>
538
+ XML
539
+ ))
540
+
541
+ subject.adjust_blocklists(doc)
542
+ doc.to_s.should == subsection(<<XML
543
+ <blockList id="list0">
544
+ <item id="list0.a">
545
+ <num>(a)</num>
546
+ <p>foo</p>
547
+ </item>
548
+ <item id="list0.b">
549
+ <num>(b)</num>
550
+ <blockList id="list0.b.list0">
551
+ <listIntroduction>item-b</listIntroduction>
552
+ <item id="list0.b.list0.i">
553
+ <num>(i)</num>
554
+ <blockList id="list0.b.list0.i.list0">
555
+ <listIntroduction>item-b-i</listIntroduction>
556
+ <item id="list0.b.list0.i.list0.aa">
557
+ <num>(aa)</num>
558
+ <p>item-i-aa</p>
559
+ </item>
560
+ <item id="list0.b.list0.i.list0.bb">
561
+ <num>(bb)</num>
562
+ <p>item-i-bb</p>
563
+ </item>
564
+ </blockList>
565
+ </item>
566
+ <item id="list0.b.list0.ii">
567
+ <num>(ii)</num>
568
+ <p>item-b-ii</p>
569
+ </item>
570
+ </blockList>
571
+ </item>
572
+ <item id="list0.c">
573
+ <num>(c)</num>
574
+ <blockList id="list0.c.list1">
575
+ <listIntroduction>item-c</listIntroduction>
576
+ <item id="list0.c.list1.i">
577
+ <num>(i)</num>
578
+ <p>item-c-i</p>
579
+ </item>
580
+ <item id="list0.c.list1.ii">
581
+ <num>(ii)</num>
582
+ <p>item-c-ii</p>
583
+ </item>
584
+ <item id="list0.c.list1.iii">
585
+ <num>(iii)</num>
586
+ <p>item-c-iii</p>
587
+ </item>
588
+ </blockList>
589
+ </item>
590
+ </blockList>
591
+ XML
592
+ )
593
+ end
594
+
595
+ # -------------------------------------------------------------------------
596
+
597
+ it 'should jump back up a level when finding (i) near (h)' do
598
+ doc = xml2doc(subsection(<<XML
599
+ <blockList id="section-10.1.lst0" renest="true">
600
+ <item id="section-10.1.lst0.h">
601
+ <num>(h)</num>
602
+ <p>foo</p>
603
+ </item>
604
+ <item id="section-10.1.lst0.i">
605
+ <num>(i)</num>
606
+ <p>item-i</p>
607
+ </item>
608
+ <item id="section-10.1.lst0.ii">
609
+ <num>(ii)</num>
610
+ <p>item-ii</p>
611
+ </item>
612
+ <item id="section-10.1.lst0.i">
613
+ <num>(i)</num>
614
+ <p>item-i</p>
615
+ </item>
616
+ </blockList>
617
+ XML
618
+ ))
619
+
620
+ subject.adjust_blocklists(doc)
621
+ doc.to_s.should == subsection(<<XML
622
+ <blockList id="section-10.1.lst0">
623
+ <item id="section-10.1.lst0.h">
624
+ <num>(h)</num>
625
+ <blockList id="section-10.1.lst0.h.list0">
626
+ <listIntroduction>foo</listIntroduction>
627
+ <item id="section-10.1.lst0.h.list0.i">
628
+ <num>(i)</num>
629
+ <p>item-i</p>
630
+ </item>
631
+ <item id="section-10.1.lst0.h.list0.ii">
632
+ <num>(ii)</num>
633
+ <p>item-ii</p>
634
+ </item>
635
+ </blockList>
636
+ </item>
637
+ <item id="section-10.1.lst0.i">
638
+ <num>(i)</num>
639
+ <p>item-i</p>
640
+ </item>
641
+ </blockList>
642
+ XML
643
+ )
644
+ end
645
+
646
+ # -------------------------------------------------------------------------
647
+
648
+ it 'should handle dotted numbers correctly' do
649
+ doc = xml2doc(subsection(<<XML
650
+ <blockList id="section-9.subsection-2.list2" renest="true">
651
+ <item id="section-9.subsection-2.list2.9.2.1">
652
+ <num>9.2.1</num>
653
+ <p>is incapable of trading because of an illness, provided that:</p>
654
+ </item>
655
+ <item id="section-9.subsection-2.list2.9.2.1.1">
656
+ <num>9.2.1.1</num>
657
+ <p>proof from a medical practitioner is provided to the City which certifies that the permit-holder is unable to trade; and</p>
658
+ </item>
659
+ <item id="section-9.subsection-2.list2.9.2.1.2">
660
+ <num>9.2.1.2</num>
661
+ <p>the dependent or assistant is only permitted to replace the permit-</p>
662
+ </item>
663
+ </blockList>
664
+ XML
665
+ ))
666
+
667
+ subject.adjust_blocklists(doc)
668
+ doc.to_s.should == subsection(<<XML
669
+ <blockList id="section-9.subsection-2.list2">
670
+ <item id="section-9.subsection-2.list2.9.2.1">
671
+ <num>9.2.1</num>
672
+ <blockList id="section-9.subsection-2.list2.9.2.1.list0">
673
+ <listIntroduction>is incapable of trading because of an illness, provided that:</listIntroduction>
674
+ <item id="section-9.subsection-2.list2.9.2.1.list0.9.2.1.1">
675
+ <num>9.2.1.1</num>
676
+ <p>proof from a medical practitioner is provided to the City which certifies that the permit-holder is unable to trade; and</p>
677
+ </item>
678
+ <item id="section-9.subsection-2.list2.9.2.1.list0.9.2.1.2">
679
+ <num>9.2.1.2</num>
680
+ <p>the dependent or assistant is only permitted to replace the permit-</p>
681
+ </item>
682
+ </blockList>
683
+ </item>
684
+ </blockList>
685
+ XML
686
+ )
687
+ end
688
+
689
+ it 'should handle p tags just before' do
690
+ doc = xml2doc(subsection(<<XML
691
+ <p>intro</p>
692
+ <blockList id="section-10.1.lst0">
693
+ <item id="section-10.1.lst0.a">
694
+ <num>(a)</num>
695
+ <p>foo</p>
696
+ </item>
697
+ </blockList>
698
+ XML
699
+ ))
700
+
701
+ subject.adjust_blocklists(doc)
702
+ doc.to_s.should == subsection(<<XML
703
+ <blockList id="section-10.1.lst0">
704
+ <listIntroduction>intro</listIntroduction>
705
+ <item id="section-10.1.lst0.a">
706
+ <num>(a)</num>
707
+ <p>foo</p>
708
+ </item>
709
+ </blockList>
710
+ XML
711
+ )
712
+ end
713
+ end
714
+ end