slaw 0.17.2 → 1.0.0.alpha.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 +4 -4
- data/README.md +9 -2
- data/bin/slaw +2 -19
- data/lib/slaw/generator.rb +21 -6
- data/lib/slaw/grammars/core_nodes.rb +17 -0
- data/lib/slaw/grammars/inlines.treetop +45 -0
- data/lib/slaw/grammars/inlines_nodes.rb +58 -0
- data/lib/slaw/grammars/pl/act.treetop +246 -0
- data/lib/slaw/grammars/pl/act_nodes.rb +469 -0
- data/lib/slaw/grammars/schedules.treetop +33 -0
- data/lib/slaw/grammars/schedules_nodes.rb +107 -0
- data/lib/slaw/grammars/tables.treetop +59 -0
- data/lib/slaw/grammars/tables_nodes.rb +74 -0
- data/lib/slaw/grammars/terminals.treetop +84 -0
- data/lib/slaw/grammars/za/act.treetop +222 -0
- data/lib/slaw/grammars/za/act_nodes.rb +307 -0
- data/lib/slaw/{za → grammars/za}/act_text.xsl +0 -0
- data/lib/slaw/parse/builder.rb +6 -202
- data/lib/slaw/version.rb +1 -1
- data/spec/generator_spec.rb +2 -0
- data/spec/parse/builder_spec.rb +0 -48
- data/spec/pl/act_block_spec.rb +449 -0
- data/spec/za/act_block_spec.rb +5 -3
- data/spec/za/act_inline_spec.rb +2 -0
- data/spec/za/act_schedules_spec.rb +2 -0
- data/spec/za/act_table_spec.rb +2 -0
- metadata +19 -7
- data/lib/slaw/za/act.treetop +0 -393
- data/lib/slaw/za/act_nodes.rb +0 -532
data/lib/slaw/za/act_nodes.rb
DELETED
@@ -1,532 +0,0 @@
|
|
1
|
-
module Slaw
|
2
|
-
module ZA
|
3
|
-
module Act
|
4
|
-
class Act < Treetop::Runtime::SyntaxNode
|
5
|
-
FRBR_URI = '/za/act/1980/01'
|
6
|
-
WORK_URI = FRBR_URI
|
7
|
-
EXPRESSION_URI = "#{FRBR_URI}/eng@"
|
8
|
-
MANIFESTATION_URI = EXPRESSION_URI
|
9
|
-
|
10
|
-
def to_xml(b, idprefix=nil, i=0)
|
11
|
-
b.act(contains: "originalVersion") { |b|
|
12
|
-
write_meta(b)
|
13
|
-
write_preface(b)
|
14
|
-
write_preamble(b)
|
15
|
-
write_body(b)
|
16
|
-
}
|
17
|
-
write_schedules(b)
|
18
|
-
end
|
19
|
-
|
20
|
-
def write_meta(b)
|
21
|
-
b.meta { |b|
|
22
|
-
write_identification(b)
|
23
|
-
|
24
|
-
b.references(source: "#this") {
|
25
|
-
b.TLCOrganization(id: 'slaw', href: 'https://github.com/longhotsummer/slaw', showAs: "Slaw")
|
26
|
-
b.TLCOrganization(id: 'council', href: '/ontology/organization/za/council', showAs: "Council")
|
27
|
-
}
|
28
|
-
}
|
29
|
-
end
|
30
|
-
|
31
|
-
def write_identification(b)
|
32
|
-
b.identification(source: "#slaw") { |b|
|
33
|
-
# use stub values so that we can generate a validating document
|
34
|
-
b.FRBRWork { |b|
|
35
|
-
b.FRBRthis(value: "#{WORK_URI}/main")
|
36
|
-
b.FRBRuri(value: WORK_URI)
|
37
|
-
b.FRBRalias(value: 'Short Title')
|
38
|
-
b.FRBRdate(date: '1980-01-01', name: 'Generation')
|
39
|
-
b.FRBRauthor(href: '#council')
|
40
|
-
b.FRBRcountry(value: 'za')
|
41
|
-
}
|
42
|
-
b.FRBRExpression { |b|
|
43
|
-
b.FRBRthis(value: "#{EXPRESSION_URI}/main")
|
44
|
-
b.FRBRuri(value: EXPRESSION_URI)
|
45
|
-
b.FRBRdate(date: '1980-01-01', name: 'Generation')
|
46
|
-
b.FRBRauthor(href: '#council')
|
47
|
-
b.FRBRlanguage(language: 'eng')
|
48
|
-
}
|
49
|
-
b.FRBRManifestation { |b|
|
50
|
-
b.FRBRthis(value: "#{MANIFESTATION_URI}/main")
|
51
|
-
b.FRBRuri(value: MANIFESTATION_URI)
|
52
|
-
b.FRBRdate(date: Time.now.strftime('%Y-%m-%d'), name: 'Generation')
|
53
|
-
b.FRBRauthor(href: '#slaw')
|
54
|
-
}
|
55
|
-
}
|
56
|
-
end
|
57
|
-
|
58
|
-
def write_preface(b)
|
59
|
-
preface.to_xml(b) if preface.respond_to? :to_xml
|
60
|
-
end
|
61
|
-
|
62
|
-
def write_preamble(b)
|
63
|
-
preamble.to_xml(b) if preamble.respond_to? :to_xml
|
64
|
-
end
|
65
|
-
|
66
|
-
def write_body(b)
|
67
|
-
body.to_xml(b)
|
68
|
-
end
|
69
|
-
|
70
|
-
def write_schedules(b)
|
71
|
-
if schedules.text_value != ""
|
72
|
-
schedules.to_xml(b)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
class Body < Treetop::Runtime::SyntaxNode
|
78
|
-
def to_xml(b)
|
79
|
-
b.body { |b|
|
80
|
-
children.elements.each_with_index { |e, i| e.to_xml(b, '', i) }
|
81
|
-
}
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
class GroupNode < Treetop::Runtime::SyntaxNode
|
86
|
-
def to_xml(b, *args)
|
87
|
-
children.elements.each { |e| e.to_xml(b, *args) }
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
class Preface < Treetop::Runtime::SyntaxNode
|
92
|
-
def to_xml(b, *args)
|
93
|
-
if text_value != ""
|
94
|
-
b.preface { |b|
|
95
|
-
statements.elements.each { |element|
|
96
|
-
for e in element.elements
|
97
|
-
e.to_xml(b, "") if e.is_a? NakedStatement
|
98
|
-
end
|
99
|
-
}
|
100
|
-
}
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
class Preamble < Treetop::Runtime::SyntaxNode
|
106
|
-
def to_xml(b, *args)
|
107
|
-
if text_value != ""
|
108
|
-
b.preamble { |b|
|
109
|
-
statements.elements.each { |e|
|
110
|
-
e.to_xml(b, "")
|
111
|
-
}
|
112
|
-
}
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
class Part < Treetop::Runtime::SyntaxNode
|
118
|
-
def num
|
119
|
-
heading.num
|
120
|
-
end
|
121
|
-
|
122
|
-
def to_xml(b, *args)
|
123
|
-
id = "part-#{num}"
|
124
|
-
|
125
|
-
# include a chapter number in the id if our parent has one
|
126
|
-
if parent and parent.parent.is_a?(Chapter) and parent.parent.num
|
127
|
-
id = "chapter-#{parent.parent.num}.#{id}"
|
128
|
-
end
|
129
|
-
|
130
|
-
b.part(id: id) { |b|
|
131
|
-
heading.to_xml(b)
|
132
|
-
children.elements.each_with_index { |e, i| e.to_xml(b, id + '.', i) }
|
133
|
-
}
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
class PartHeading < Treetop::Runtime::SyntaxNode
|
138
|
-
def num
|
139
|
-
part_heading_prefix.alphanums.text_value
|
140
|
-
end
|
141
|
-
|
142
|
-
def title
|
143
|
-
if heading.text_value and heading.respond_to? :content
|
144
|
-
heading.content.text_value.strip
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
def to_xml(b)
|
149
|
-
b.num(num)
|
150
|
-
b.heading(title) if title
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
class Chapter < Treetop::Runtime::SyntaxNode
|
155
|
-
def num
|
156
|
-
heading.num
|
157
|
-
end
|
158
|
-
|
159
|
-
def to_xml(b, *args)
|
160
|
-
id = "chapter-#{num}"
|
161
|
-
|
162
|
-
# include a part number in the id if our parent has one
|
163
|
-
if parent and parent.parent.is_a?(Part) and parent.parent.num
|
164
|
-
id = "part-#{parent.parent.num}.#{id}"
|
165
|
-
end
|
166
|
-
|
167
|
-
b.chapter(id: id) { |b|
|
168
|
-
heading.to_xml(b)
|
169
|
-
children.elements.each_with_index { |e, i| e.to_xml(b, id + '.', i) }
|
170
|
-
}
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
class ChapterHeading < Treetop::Runtime::SyntaxNode
|
175
|
-
def num
|
176
|
-
chapter_heading_prefix.alphanums.text_value
|
177
|
-
end
|
178
|
-
|
179
|
-
def title
|
180
|
-
if heading.text_value and heading.respond_to? :content
|
181
|
-
heading.content.text_value.strip
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
|
-
def to_xml(b)
|
186
|
-
b.num(num)
|
187
|
-
b.heading(title) if title
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
class Section < Treetop::Runtime::SyntaxNode
|
192
|
-
def num
|
193
|
-
section_title.num
|
194
|
-
end
|
195
|
-
|
196
|
-
def title
|
197
|
-
section_title.title
|
198
|
-
end
|
199
|
-
|
200
|
-
def to_xml(b, *args)
|
201
|
-
id = "section-#{num}"
|
202
|
-
b.section(id: id) { |b|
|
203
|
-
b.num("#{num}.")
|
204
|
-
b.heading(title)
|
205
|
-
|
206
|
-
idprefix = "#{id}."
|
207
|
-
|
208
|
-
children.elements.each_with_index { |e, i| e.to_xml(b, idprefix, i) }
|
209
|
-
}
|
210
|
-
end
|
211
|
-
end
|
212
|
-
|
213
|
-
class SectionTitleType1 < Treetop::Runtime::SyntaxNode
|
214
|
-
# a section title of the form:
|
215
|
-
#
|
216
|
-
# Definitions
|
217
|
-
# 1. In this act...
|
218
|
-
|
219
|
-
def num
|
220
|
-
section_title_prefix.number_letter.text_value
|
221
|
-
end
|
222
|
-
|
223
|
-
def title
|
224
|
-
content.text_value
|
225
|
-
end
|
226
|
-
end
|
227
|
-
|
228
|
-
class SectionTitleType2 < Treetop::Runtime::SyntaxNode
|
229
|
-
# a section title of the form:
|
230
|
-
#
|
231
|
-
# 1. Definitions
|
232
|
-
# In this act...
|
233
|
-
#
|
234
|
-
# In this format, the title is optional and the section content may
|
235
|
-
# start where we think the title is.
|
236
|
-
|
237
|
-
def num
|
238
|
-
section_title_prefix.number_letter.text_value
|
239
|
-
end
|
240
|
-
|
241
|
-
def title
|
242
|
-
section_title.empty? ? "" : section_title.content.text_value
|
243
|
-
end
|
244
|
-
end
|
245
|
-
|
246
|
-
class BlockParagraph < Treetop::Runtime::SyntaxNode
|
247
|
-
def to_xml(b, idprefix='', i=0)
|
248
|
-
id = "#{idprefix}paragraph-0"
|
249
|
-
idprefix = "#{id}."
|
250
|
-
|
251
|
-
b.paragraph(id: id) { |b|
|
252
|
-
b.content { |b|
|
253
|
-
elements.each_with_index { |e, i| e.to_xml(b, idprefix, i) }
|
254
|
-
}
|
255
|
-
}
|
256
|
-
end
|
257
|
-
end
|
258
|
-
|
259
|
-
class Subsection < Treetop::Runtime::SyntaxNode
|
260
|
-
def num
|
261
|
-
subsection_prefix.num.text_value
|
262
|
-
end
|
263
|
-
|
264
|
-
def to_xml(b, idprefix, i)
|
265
|
-
id = idprefix + num.gsub(/[()]/, '')
|
266
|
-
idprefix = id + "."
|
267
|
-
|
268
|
-
kids = children.elements
|
269
|
-
kids = [first_child] + kids if first_child and !first_child.empty?
|
270
|
-
|
271
|
-
b.subsection(id: id) { |b|
|
272
|
-
b.num(num)
|
273
|
-
b.content { |b|
|
274
|
-
if kids.empty?
|
275
|
-
# schema requires a non-empty content element
|
276
|
-
b.p
|
277
|
-
else
|
278
|
-
kids.each_with_index { |e, i| e.to_xml(b, idprefix, i) }
|
279
|
-
end
|
280
|
-
}
|
281
|
-
}
|
282
|
-
end
|
283
|
-
end
|
284
|
-
|
285
|
-
class NakedStatement < Treetop::Runtime::SyntaxNode
|
286
|
-
def to_xml(b, idprefix, i=0)
|
287
|
-
b.p { |b| clauses.to_xml(b, idprefix) } if clauses
|
288
|
-
end
|
289
|
-
|
290
|
-
def content
|
291
|
-
clauses
|
292
|
-
end
|
293
|
-
end
|
294
|
-
|
295
|
-
class Clauses < Treetop::Runtime::SyntaxNode
|
296
|
-
def to_xml(b, idprefix=nil)
|
297
|
-
for e in elements
|
298
|
-
if e.respond_to? :to_xml
|
299
|
-
e.to_xml(b, idprefix)
|
300
|
-
else
|
301
|
-
b << e.text_value
|
302
|
-
end
|
303
|
-
end
|
304
|
-
end
|
305
|
-
end
|
306
|
-
|
307
|
-
class Remark < Treetop::Runtime::SyntaxNode
|
308
|
-
def to_xml(b, idprefix)
|
309
|
-
b.remark(status: 'editorial') do |b|
|
310
|
-
b << '['
|
311
|
-
for e in content.elements
|
312
|
-
if e.respond_to? :to_xml
|
313
|
-
e.to_xml(b, idprefix)
|
314
|
-
else
|
315
|
-
b << e.text_value
|
316
|
-
end
|
317
|
-
end
|
318
|
-
b << ']'
|
319
|
-
end
|
320
|
-
end
|
321
|
-
end
|
322
|
-
|
323
|
-
class Image < Treetop::Runtime::SyntaxNode
|
324
|
-
def to_xml(b, idprefix)
|
325
|
-
attrs = {src: href.text_value}
|
326
|
-
attrs[:alt] = content.text_value unless content.text_value.empty?
|
327
|
-
b.img(attrs)
|
328
|
-
end
|
329
|
-
end
|
330
|
-
|
331
|
-
class Ref < Treetop::Runtime::SyntaxNode
|
332
|
-
def to_xml(b, idprefix)
|
333
|
-
b.ref(content.text_value, href: href.text_value)
|
334
|
-
end
|
335
|
-
end
|
336
|
-
|
337
|
-
class Blocklist < Treetop::Runtime::SyntaxNode
|
338
|
-
# Render a block list to xml. If a block is given,
|
339
|
-
# yield to it a builder to insert a listIntroduction node
|
340
|
-
def to_xml(b, idprefix, i=0, &block)
|
341
|
-
id = idprefix + "list#{i}"
|
342
|
-
idprefix = id + '.'
|
343
|
-
|
344
|
-
b.blockList(id: id) { |b|
|
345
|
-
b.listIntroduction { |b| yield b } if block_given?
|
346
|
-
|
347
|
-
elements.each { |e| e.to_xml(b, idprefix) }
|
348
|
-
}
|
349
|
-
end
|
350
|
-
end
|
351
|
-
|
352
|
-
class BlocklistItem < Treetop::Runtime::SyntaxNode
|
353
|
-
def num
|
354
|
-
blocklist_item_prefix.text_value
|
355
|
-
end
|
356
|
-
|
357
|
-
def to_xml(b, idprefix)
|
358
|
-
b.item(id: idprefix + num.gsub(/[()]/, '')) { |b|
|
359
|
-
b.num(num)
|
360
|
-
b.p { |b|
|
361
|
-
item_content.clauses.to_xml(b, idprefix) if respond_to? :item_content and item_content.respond_to? :clauses
|
362
|
-
}
|
363
|
-
}
|
364
|
-
end
|
365
|
-
end
|
366
|
-
|
367
|
-
class Table < Treetop::Runtime::SyntaxNode
|
368
|
-
def to_xml(b, idprefix, i=0)
|
369
|
-
b.table(id: "#{idprefix}table#{i}") { |b|
|
370
|
-
# we'll gather cells into this row list
|
371
|
-
rows = []
|
372
|
-
cells = []
|
373
|
-
|
374
|
-
for child in table_body.elements
|
375
|
-
if child.is_a? TableCell
|
376
|
-
# cell
|
377
|
-
cells << child
|
378
|
-
else
|
379
|
-
# new row marker
|
380
|
-
rows << cells unless cells.empty?
|
381
|
-
cells = []
|
382
|
-
end
|
383
|
-
end
|
384
|
-
rows << cells unless cells.empty?
|
385
|
-
|
386
|
-
for row in rows
|
387
|
-
b.tr { |tr|
|
388
|
-
for cell in row
|
389
|
-
cell.to_xml(tr, "")
|
390
|
-
end
|
391
|
-
}
|
392
|
-
end
|
393
|
-
}
|
394
|
-
end
|
395
|
-
end
|
396
|
-
|
397
|
-
class TableCell < Treetop::Runtime::SyntaxNode
|
398
|
-
def to_xml(b, idprefix)
|
399
|
-
tag = text_value[0] == '!' ? 'th' : 'td'
|
400
|
-
|
401
|
-
attrs = {}
|
402
|
-
if not attribs.empty?
|
403
|
-
for item in attribs.attribs.elements
|
404
|
-
# key=value (strip quotes around value)
|
405
|
-
attrs[item.name.text_value.strip] = item.value.text_value[1..-2]
|
406
|
-
end
|
407
|
-
end
|
408
|
-
|
409
|
-
b.send(tag.to_sym, attrs) { |b|
|
410
|
-
b.p { |b|
|
411
|
-
# first line, and the rest
|
412
|
-
lines = [content.line] + content.elements.last.elements.map(&:line)
|
413
|
-
|
414
|
-
lines.each_with_index do |line, i|
|
415
|
-
line.to_xml(b, i, i == lines.length-1)
|
416
|
-
end
|
417
|
-
}
|
418
|
-
}
|
419
|
-
end
|
420
|
-
end
|
421
|
-
|
422
|
-
class TableLine < Treetop::Runtime::SyntaxNode
|
423
|
-
# line of table content
|
424
|
-
def to_xml(b, i, tail)
|
425
|
-
clauses.to_xml(b) unless clauses.empty?
|
426
|
-
|
427
|
-
# add trailing newlines.
|
428
|
-
# for the first line, eat whitespace at the start
|
429
|
-
# for the last line, eat whitespace at the end
|
430
|
-
if not tail and (i > 0 or not clauses.empty?)
|
431
|
-
eol.text_value.count("\n").times { b.eol }
|
432
|
-
end
|
433
|
-
end
|
434
|
-
end
|
435
|
-
|
436
|
-
class ScheduleContainer < Treetop::Runtime::SyntaxNode
|
437
|
-
def to_xml(b)
|
438
|
-
b.components { |b|
|
439
|
-
schedules.children.elements.each_with_index { |e, i|
|
440
|
-
e.to_xml(b, "", i+1)
|
441
|
-
}
|
442
|
-
}
|
443
|
-
end
|
444
|
-
end
|
445
|
-
|
446
|
-
class Schedule < Treetop::Runtime::SyntaxNode
|
447
|
-
def num
|
448
|
-
n = schedule_title.num.text_value
|
449
|
-
return (n && !n.empty?) ? n : nil
|
450
|
-
end
|
451
|
-
|
452
|
-
def alias
|
453
|
-
if not schedule_title.title.text_value.blank?
|
454
|
-
schedule_title.title.text_value
|
455
|
-
elsif num
|
456
|
-
"Schedule #{num}"
|
457
|
-
else
|
458
|
-
"Schedule"
|
459
|
-
end
|
460
|
-
end
|
461
|
-
|
462
|
-
def heading
|
463
|
-
if schedule_title.heading.respond_to? :content
|
464
|
-
schedule_title.heading.content.text_value
|
465
|
-
else
|
466
|
-
nil
|
467
|
-
end
|
468
|
-
end
|
469
|
-
|
470
|
-
def to_xml(b, idprefix=nil, i=1)
|
471
|
-
if num
|
472
|
-
n = num
|
473
|
-
component = "schedule#{n}"
|
474
|
-
else
|
475
|
-
n = i
|
476
|
-
# make a component name from the schedule title
|
477
|
-
component = self.alias.downcase().strip().gsub(/[^a-z0-9]/i, '').gsub(/ +/, '')
|
478
|
-
end
|
479
|
-
|
480
|
-
id = "#{idprefix}#{component}"
|
481
|
-
|
482
|
-
b.component(id: "component-#{id}") { |b|
|
483
|
-
b.doc_(name: component) { |b|
|
484
|
-
b.meta { |b|
|
485
|
-
b.identification(source: "#slaw") { |b|
|
486
|
-
b.FRBRWork { |b|
|
487
|
-
b.FRBRthis(value: "#{Act::WORK_URI}/#{component}")
|
488
|
-
b.FRBRuri(value: Act::WORK_URI)
|
489
|
-
b.FRBRalias(value: self.alias)
|
490
|
-
b.FRBRdate(date: '1980-01-01', name: 'Generation')
|
491
|
-
b.FRBRauthor(href: '#council')
|
492
|
-
b.FRBRcountry(value: 'za')
|
493
|
-
}
|
494
|
-
b.FRBRExpression { |b|
|
495
|
-
b.FRBRthis(value: "#{Act::EXPRESSION_URI}/#{component}")
|
496
|
-
b.FRBRuri(value: Act::EXPRESSION_URI)
|
497
|
-
b.FRBRdate(date: '1980-01-01', name: 'Generation')
|
498
|
-
b.FRBRauthor(href: '#council')
|
499
|
-
b.FRBRlanguage(language: 'eng')
|
500
|
-
}
|
501
|
-
b.FRBRManifestation { |b|
|
502
|
-
b.FRBRthis(value: "#{Act::MANIFESTATION_URI}/#{component}")
|
503
|
-
b.FRBRuri(value: Act::MANIFESTATION_URI)
|
504
|
-
b.FRBRdate(date: Time.now.strftime('%Y-%m-%d'), name: 'Generation')
|
505
|
-
b.FRBRauthor(href: '#slaw')
|
506
|
-
}
|
507
|
-
}
|
508
|
-
}
|
509
|
-
|
510
|
-
b.mainBody { |b|
|
511
|
-
idprefix = "#{id}."
|
512
|
-
|
513
|
-
# there is no good AKN hierarchy container for schedules, so we
|
514
|
-
# just use article because we don't use it anywhere else.
|
515
|
-
b.article(id: id) { |b|
|
516
|
-
b.heading(heading) if heading
|
517
|
-
body.children.elements.each_with_index { |e| e.to_xml(b, idprefix, i) } if body.is_a? Body
|
518
|
-
}
|
519
|
-
}
|
520
|
-
}
|
521
|
-
}
|
522
|
-
end
|
523
|
-
end
|
524
|
-
|
525
|
-
class ScheduleStatement < Treetop::Runtime::SyntaxNode
|
526
|
-
def to_xml(b, idprefix)
|
527
|
-
b.p { |b| clauses.to_xml(b, idprefix) } if clauses
|
528
|
-
end
|
529
|
-
end
|
530
|
-
end
|
531
|
-
end
|
532
|
-
end
|