slaw 2.2.0 → 3.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
  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>