slaw 5.0.0 → 6.0.0

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