slaw 2.2.0 → 3.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
  SHA1:
3
- metadata.gz: aa23761ec680b927115914fd421ee7492984b78f
4
- data.tar.gz: 80da01e30b41401f66b5784302f92002432535f2
3
+ metadata.gz: 655dd4179f692952514dc6341d332b92bb5ed09f
4
+ data.tar.gz: f94a6f5d09da791132c901343cdc7c0f228822ec
5
5
  SHA512:
6
- metadata.gz: 28c4c706a2dd46256ea6a669d242576dc970195060b42e45e1c940c34c53b72520781a7d8e9f6171f4df7c6265040462626072ebc3bbd44c6c824e6e50c24de5
7
- data.tar.gz: 9df4834b9134ad84f78f43bebc1a46956987876d6f6ffcf54b643d6f1b7addc7bff25273e859fb78fff428e1150211525b985ed37b368753bb578514f064d5ba
6
+ metadata.gz: dae4cc911be85f416e81252489f7914d8da142aa0eacf6e92a15c4f314f7569394eb718cad620ccabe098c352c87f02c4a5ae0bdb8cc7430523a4db1f65add54
7
+ data.tar.gz: ea1bc757d9a29b0f998366f36bd5c5baec6b2b0196705369a06a9ded88aafb1740ac27e364a9ccd1b5320a14a00cb57179911294cd858fd94f5106a2ff5f2d18
data/README.md CHANGED
@@ -84,6 +84,16 @@ You can create your own grammar by creating a gem that provides these files and
84
84
 
85
85
  ## Changelog
86
86
 
87
+ ### 3.0.0 (28 March 2019)
88
+
89
+ * Inline bold and italics
90
+ * Support for CROSSHEADING elements using an empty hcontainer until we support AKN 3.0
91
+ * Support for LONGTITLE in PREFACE
92
+ * Remarks and references support nested inline elements
93
+ * BREAKING: `clauses` rule renamed to `inline_elements` so as not to clash with real AKN clauses
94
+ * BREAKING: `block_paragraphs` rule renamed to `generic_container` and adjusted to be singular to be simpler to understand
95
+ * BREAKING: un-numbered paragraph elements have new ids, that should not clash with numbered paragraphs from other grammars
96
+
87
97
  ### 2.2.0 (18 March 2019)
88
98
 
89
99
  * Schedules use hcontainer, not article
data/bin/slaw CHANGED
@@ -100,3 +100,8 @@ class SlawCLI < Thor
100
100
  end
101
101
 
102
102
  SlawCLI.start(ARGV)
103
+ # Nokogiri can take 5-10 seconds to clean up and we don't care, just
104
+ # exit now
105
+ STDOUT.flush
106
+ STDERR.flush
107
+ exit! 0
@@ -10,18 +10,23 @@ module Slaw
10
10
  # inline content
11
11
 
12
12
  rule inline_statement
13
- space? '\\'? clauses eol
13
+ space? '\\'? inline_items eol
14
14
  <NakedStatement>
15
15
  end
16
16
 
17
17
  # one or more words, allowing inline elements
18
- rule clauses
19
- (remark / image / ref / [^\n])+
20
- <Clauses>
18
+ # TODO: this is badly named, a better name would be inline_items
19
+ rule inline_items
20
+ inline_item+ <InlineItems>
21
+ end
22
+
23
+ rule inline_item
24
+ remark / image / ref / bold / italics / [^\n]
25
+ <InlineItem>
21
26
  end
22
27
 
23
28
  rule remark
24
- '[[' content:(ref / (!']]' .))+ ']]'
29
+ '[[' content:(!']]' inline_item)+ ']]'
25
30
  <Remark>
26
31
  end
27
32
 
@@ -34,12 +39,25 @@ module Slaw
34
39
  <Image>
35
40
  end
36
41
 
42
+ rule bold
43
+ # **foo**
44
+ '**' content:(!'**' inline_item)+ '**'
45
+ <Bold>
46
+ end
47
+
48
+ rule italics
49
+ # //foo//
50
+ '//' content:(!'//' inline_item)+ '//'
51
+ <Italics>
52
+ end
53
+
37
54
  rule ref
38
55
  # links like markdown
39
56
  # eg. [link text](link url)
40
- '[' content:(!'](' [^\n])+ '](' href:([^)\n]+) ')'
57
+ '[' content:(!'](' inline_item)+ '](' href:([^)\n]+) ')'
41
58
  <Ref>
42
59
  end
60
+
43
61
  end
44
62
  end
45
63
  end
@@ -3,22 +3,18 @@ module Slaw
3
3
  module Inlines
4
4
  class NakedStatement < Treetop::Runtime::SyntaxNode
5
5
  def to_xml(b, idprefix, i=0)
6
- b.p { |b| clauses.to_xml(b, idprefix) } if clauses
6
+ b.p { |b| inline_items.to_xml(b, idprefix) } if inline_items
7
7
  end
8
8
 
9
9
  def content
10
- clauses
10
+ inline_items
11
11
  end
12
12
  end
13
13
 
14
- class Clauses < Treetop::Runtime::SyntaxNode
14
+ class InlineItems < Treetop::Runtime::SyntaxNode
15
15
  def to_xml(b, idprefix=nil)
16
16
  for e in elements
17
- if e.respond_to? :to_xml
18
- e.to_xml(b, idprefix)
19
- else
20
- b.text(e.text_value)
21
- end
17
+ e.to_xml(b, idprefix)
22
18
  end
23
19
  end
24
20
  end
@@ -28,11 +24,7 @@ module Slaw
28
24
  b.remark(status: 'editorial') do |b|
29
25
  b.text('[')
30
26
  for e in content.elements
31
- if e.respond_to? :to_xml
32
- e.to_xml(b, idprefix)
33
- else
34
- b.text(e.text_value)
35
- end
27
+ e.inline_item.to_xml(b, idprefix)
36
28
  end
37
29
  b.text(']')
38
30
  end
@@ -47,9 +39,39 @@ module Slaw
47
39
  end
48
40
  end
49
41
 
42
+ class InlineItem < Treetop::Runtime::SyntaxNode
43
+ def to_xml(b, idprefix)
44
+ b.text(text_value)
45
+ end
46
+ end
47
+
50
48
  class Ref < Treetop::Runtime::SyntaxNode
51
49
  def to_xml(b, idprefix)
52
- b.ref(content.text_value, href: href.text_value)
50
+ b.ref(href: href.text_value) { |b|
51
+ for e in content.elements
52
+ e.inline_item.to_xml(b, idprefix)
53
+ end
54
+ }
55
+ end
56
+ end
57
+
58
+ class Bold < Treetop::Runtime::SyntaxNode
59
+ def to_xml(b, idprefix)
60
+ b.b { |b|
61
+ for e in content.elements
62
+ e.inline_item.to_xml(b, idprefix)
63
+ end
64
+ }
65
+ end
66
+ end
67
+
68
+ class Italics < Treetop::Runtime::SyntaxNode
69
+ def to_xml(b, idprefix)
70
+ b.i { |b|
71
+ for e in content.elements
72
+ e.inline_item.to_xml(b, idprefix)
73
+ end
74
+ }
53
75
  end
54
76
  end
55
77
 
@@ -20,8 +20,8 @@ module Slaw
20
20
  end
21
21
 
22
22
  rule schedule_title
23
- space? schedule_title_prefix space? "\""? num:alphanums? "\""? [ \t:.-]* title:clauses?
24
- subheading:(newline space? clauses)?
23
+ space? schedule_title_prefix space? "\""? num:alphanums? "\""? [ \t:.-]* title:inline_items?
24
+ subheading:(newline space? inline_items)?
25
25
  eol
26
26
  end
27
27
 
@@ -27,7 +27,7 @@ module Slaw
27
27
  def alias
28
28
  if not schedule_title.title.text_value.blank?
29
29
  # plain-text elements only
30
- schedule_title.title.elements.select { |x| !x.respond_to? :to_xml }.map { |x| x.text_value }.join('').strip
30
+ schedule_title.title.elements.select { |x| x.instance_of? ::Slaw::Grammars::Inlines::InlineItem }.map { |x| x.text_value }.join('').strip
31
31
  elsif num
32
32
  "Schedule #{num}"
33
33
  else
@@ -45,7 +45,7 @@ module Slaw
45
45
 
46
46
  def subheading
47
47
  if not schedule_title.subheading.text_value.blank?
48
- schedule_title.subheading.clauses
48
+ schedule_title.subheading.inline_items
49
49
  else
50
50
  nil
51
51
  end
@@ -113,7 +113,7 @@ module Slaw
113
113
 
114
114
  class ScheduleStatement < Treetop::Runtime::SyntaxNode
115
115
  def to_xml(b, idprefix)
116
- b.p { |b| clauses.to_xml(b, idprefix) } if clauses
116
+ b.p { |b| inline_items.to_xml(b, idprefix) } if inline_items
117
117
  end
118
118
  end
119
119
  end
@@ -38,7 +38,7 @@ module Slaw
38
38
  end
39
39
 
40
40
  rule table_line
41
- clauses:clauses? eol
41
+ inline_items:inline_items? eol
42
42
  <TableLine>
43
43
  end
44
44
 
@@ -59,12 +59,12 @@ module Slaw
59
59
  class TableLine < Treetop::Runtime::SyntaxNode
60
60
  # line of table content
61
61
  def to_xml(b, i, tail)
62
- clauses.to_xml(b) unless clauses.empty?
62
+ inline_items.to_xml(b) unless inline_items.empty?
63
63
 
64
64
  # add trailing newlines.
65
65
  # for the first line, eat whitespace at the start
66
66
  # for the last line, eat whitespace at the end
67
- if not tail and (i > 0 or not clauses.empty?)
67
+ if not tail and (i > 0 or not inline_items.empty?)
68
68
  eol.text_value.count("\n").times { b.eol }
69
69
  end
70
70
  end
@@ -16,6 +16,8 @@ module Slaw
16
16
 
17
17
  ########
18
18
  # major containers
19
+ #
20
+ # These are AKN's heirarchical containers which wrap actual content.
19
21
 
20
22
  rule act
21
23
  empty_line*
@@ -28,33 +30,33 @@ module Slaw
28
30
  rule preface
29
31
  !'PREAMBLE'
30
32
  ('PREFACE'i space? eol)?
31
- statements:(!'PREAMBLE' pre_body_statement)* <Preface>
33
+ statements:(!'PREAMBLE' preface_statement)* <Preface>
32
34
  end
33
35
 
34
36
  rule preamble
35
37
  'PREAMBLE'i space? eol
36
- statements:pre_body_statement* <Preamble>
38
+ statements:preamble_statement* <Preamble>
37
39
  end
38
40
 
39
41
  rule body
40
- children:(chapter / part / section / subsection / block_paragraphs)+ <Body>
42
+ children:(chapter / part / section / subsection / generic_container)+ <Body>
41
43
  end
42
44
 
43
45
  rule chapter
44
46
  heading:chapter_heading
45
- children:(part / section / subsection / block_paragraphs)*
47
+ children:(part / section / subsection / generic_container)*
46
48
  <Chapter>
47
49
  end
48
50
 
49
51
  rule part
50
52
  heading:part_heading
51
- children:(section / subsection / block_paragraphs)*
53
+ children:(section / subsection / generic_container)*
52
54
  <Part>
53
55
  end
54
56
 
55
57
  rule section
56
58
  section_title
57
- children:(subsection / block_paragraphs)* <Section>
59
+ children:(subsection / generic_container)* <Section>
58
60
  end
59
61
 
60
62
  rule subsection
@@ -66,6 +68,22 @@ module Slaw
66
68
  children:block_element* <Subsection>
67
69
  end
68
70
 
71
+ rule generic_container
72
+ crossheading / block_elements
73
+ end
74
+
75
+ rule crossheading
76
+ 'CROSSHEADING ' inline_items:inline_items eol
77
+ <Crossheading>
78
+ end
79
+
80
+ # Consecutive non-structured content. We allow many elements
81
+ # here so that we wrap consecutive block elements in one <content> tag,
82
+ # rather than multiple containers for each.
83
+ rule block_elements
84
+ block_element+ <BlockElements>
85
+ end
86
+
69
87
  ##########
70
88
  # group elements
71
89
  #
@@ -129,10 +147,6 @@ module Slaw
129
147
  ##########
130
148
  # blocks of content inside containers
131
149
 
132
- rule block_paragraphs
133
- block_element+ <BlockParagraph>
134
- end
135
-
136
150
  rule block_element
137
151
  (table / blocklist / naked_statement)
138
152
  end
@@ -149,7 +163,7 @@ module Slaw
149
163
 
150
164
  rule blocklist_item
151
165
  # TODO: this whitespace should probably be space, to allow empty blocklist items followed by plain text
152
- space? blocklist_item_prefix whitespace item_content:(!blocklist_item_prefix clauses:clauses? eol)? eol?
166
+ space? blocklist_item_prefix whitespace item_content:(!blocklist_item_prefix inline_items:inline_items? eol)? eol?
153
167
  <BlocklistItem>
154
168
  end
155
169
 
@@ -164,15 +178,26 @@ module Slaw
164
178
  # and is ignored. This allows escaping of section headings, etc.
165
179
 
166
180
  rule naked_statement
167
- space? !(chapter_heading / part_heading / section_title / schedule_title / subsection_prefix) '\\'? clauses eol
181
+ space? !(chapter_heading / part_heading / section_title / schedule_title / subsection_prefix / crossheading) '\\'? inline_items eol
168
182
  <NakedStatement>
169
183
  end
170
184
 
171
- rule pre_body_statement
172
- space? !(chapter_heading / part_heading / section_title / schedule_title) '\\'? clauses eol
185
+ rule preface_statement
186
+ space? !(chapter_heading / part_heading / section_title / schedule_title)
187
+ content:(longtitle / ('\\'? inline_items:inline_items eol))
188
+ <PrefaceStatement>
189
+ end
190
+
191
+ rule preamble_statement
192
+ space? !(chapter_heading / part_heading / section_title / schedule_title) '\\'? inline_items eol
173
193
  <NakedStatement>
174
194
  end
175
195
 
196
+ rule longtitle
197
+ 'LONGTITLE ' inline_items:inline_items eol
198
+ <LongTitle>
199
+ end
200
+
176
201
  ##########
177
202
  # prefixes
178
203
 
@@ -91,6 +91,32 @@ module Slaw
91
91
  end
92
92
  end
93
93
 
94
+ class PrefaceStatement < Treetop::Runtime::SyntaxNode
95
+ def to_xml(b, idprefix, i=0)
96
+ if longtitle
97
+ longtitle.to_xml(b, idprefix)
98
+ else
99
+ b.p { |b| inline_items.to_xml(b, idprefix) }
100
+ end
101
+ end
102
+
103
+ def longtitle
104
+ self.content if self.content.is_a? LongTitle
105
+ end
106
+
107
+ def inline_items
108
+ content.inline_items if content.respond_to? :inline_items
109
+ end
110
+ end
111
+
112
+ class LongTitle < Treetop::Runtime::SyntaxNode
113
+ def to_xml(b, idprefix, i=0)
114
+ b.longTitle { |b|
115
+ b.p { |b| inline_items.to_xml(b, idprefix) }
116
+ }
117
+ end
118
+ end
119
+
94
120
  class Preamble < Treetop::Runtime::SyntaxNode
95
121
  def to_xml(b, *args)
96
122
  if text_value != ""
@@ -232,9 +258,17 @@ module Slaw
232
258
  end
233
259
  end
234
260
 
235
- class BlockParagraph < Treetop::Runtime::SyntaxNode
261
+ class BlockElements < Treetop::Runtime::SyntaxNode
262
+ @@counters = {}
263
+
264
+ def self.counters
265
+ @@counters
266
+ end
267
+
236
268
  def to_xml(b, idprefix='', i=0)
237
- id = "#{idprefix}paragraph-0"
269
+ @@counters[idprefix] ||= -1
270
+ @@counters[idprefix] += 1
271
+ id = "#{idprefix}paragraph#{@@counters[idprefix]}"
238
272
  idprefix = "#{id}."
239
273
 
240
274
  b.paragraph(id: id) { |b|
@@ -295,12 +329,31 @@ module Slaw
295
329
  b.item(id: idprefix + num.gsub(/[()]/, '')) { |b|
296
330
  b.num(num)
297
331
  b.p { |b|
298
- item_content.clauses.to_xml(b, idprefix) if respond_to? :item_content and item_content.respond_to? :clauses
332
+ item_content.inline_items.to_xml(b, idprefix) if respond_to? :item_content and item_content.respond_to? :inline_items
299
333
  }
300
334
  }
301
335
  end
302
336
  end
303
337
 
338
+ class Crossheading < Treetop::Runtime::SyntaxNode
339
+ @@counters = {}
340
+
341
+ def self.counters
342
+ @@counters
343
+ end
344
+
345
+ def to_xml(b, idprefix, i=0)
346
+ @@counters[idprefix] ||= -1
347
+ @@counters[idprefix] += 1
348
+ id = "#{idprefix}crossheading-#{@@counters[idprefix]}"
349
+
350
+ b.hcontainer(id: id, name: 'crossheading') { |b|
351
+ b.heading { |b|
352
+ inline_items.to_xml(b, idprefix)
353
+ }
354
+ }
355
+ end
356
+ end
304
357
  end
305
358
  end
306
359
  end
@@ -88,6 +88,20 @@
88
88
  <xsl:apply-templates select="./*[not(self::a:num) and not(self::a:heading)]" />
89
89
  </xsl:template>
90
90
 
91
+ <!-- crossheadings -->
92
+ <xsl:template match="a:hcontainer[@name='crossheading']">
93
+ <xsl:text>CROSSHEADING </xsl:text>
94
+ <xsl:apply-templates select="a:heading" />
95
+ <xsl:text>&#10;&#10;</xsl:text>
96
+ </xsl:template>
97
+
98
+ <!-- longtitle -->
99
+ <xsl:template match="a:longTitle">
100
+ <xsl:text>LONGTITLE </xsl:text>
101
+ <xsl:apply-templates />
102
+ <xsl:text>&#10;&#10;</xsl:text>
103
+ </xsl:template>
104
+
91
105
  <!-- p tags must end with a blank line -->
92
106
  <xsl:template match="a:p">
93
107
  <xsl:apply-templates/>
@@ -127,7 +141,7 @@
127
141
  <!-- components/schedules -->
128
142
  <!-- new-style schedules, "article" elements -->
129
143
  <xsl:template match="a:hcontainer[@name='schedule']">
130
- <xsl:text>Schedule - </xsl:text>
144
+ <xsl:text>SCHEDULE - </xsl:text>
131
145
  <xsl:apply-templates select="a:heading" />
132
146
  <xsl:text>&#10;</xsl:text>
133
147
 
@@ -143,16 +157,17 @@
143
157
 
144
158
  <!-- old-style schedules, "article" elements -->
145
159
  <xsl:template match="a:doc/a:mainBody/a:article">
146
- <xsl:text>Schedule - </xsl:text>
160
+ <xsl:text>SCHEDULE - </xsl:text>
147
161
  <xsl:value-of select="../../a:meta/a:identification/a:FRBRWork/a:FRBRalias/@value" />
148
162
  <xsl:text>&#10;</xsl:text>
149
163
 
150
- <xsl:if test="not(a:mainBody/a:article/a:heading)">
151
- <!-- ensure an extra blank line if there is no heading -->
164
+ <xsl:if test="a:heading">
165
+ <xsl:apply-templates select="a:heading" />
152
166
  <xsl:text>&#10;</xsl:text>
153
167
  </xsl:if>
154
168
 
155
- <xsl:apply-templates select="a:mainBody" />
169
+ <xsl:text>&#10;</xsl:text>
170
+ <xsl:apply-templates select="./*[not(self::a:heading)]"/>
156
171
  </xsl:template>
157
172
 
158
173
 
@@ -238,6 +253,18 @@
238
253
  <xsl:text>)</xsl:text>
239
254
  </xsl:template>
240
255
 
256
+ <xsl:template match="a:i">
257
+ <xsl:text>//</xsl:text>
258
+ <xsl:apply-templates />
259
+ <xsl:text>//</xsl:text>
260
+ </xsl:template>
261
+
262
+ <xsl:template match="a:b">
263
+ <xsl:text>**</xsl:text>
264
+ <xsl:apply-templates />
265
+ <xsl:text>**</xsl:text>
266
+ </xsl:template>
267
+
241
268
  <xsl:template match="a:eol">
242
269
  <xsl:text>&#10;</xsl:text>
243
270
  </xsl:template>