asciidoctor 0.0.7 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of asciidoctor might be problematic. Click here for more details.
- data/Gemfile +2 -0
- data/README.asciidoc +35 -26
- data/Rakefile +9 -6
- data/asciidoctor.gemspec +27 -8
- data/bin/asciidoctor +1 -1
- data/lib/asciidoctor.rb +351 -63
- data/lib/asciidoctor/abstract_block.rb +218 -0
- data/lib/asciidoctor/abstract_node.rb +249 -0
- data/lib/asciidoctor/attribute_list.rb +211 -0
- data/lib/asciidoctor/backends/base_template.rb +99 -0
- data/lib/asciidoctor/backends/docbook45.rb +510 -0
- data/lib/asciidoctor/backends/html5.rb +585 -0
- data/lib/asciidoctor/block.rb +27 -254
- data/lib/asciidoctor/callouts.rb +117 -0
- data/lib/asciidoctor/debug.rb +7 -4
- data/lib/asciidoctor/document.rb +229 -77
- data/lib/asciidoctor/inline.rb +29 -0
- data/lib/asciidoctor/lexer.rb +1330 -502
- data/lib/asciidoctor/list_item.rb +33 -34
- data/lib/asciidoctor/reader.rb +305 -142
- data/lib/asciidoctor/renderer.rb +115 -19
- data/lib/asciidoctor/section.rb +100 -189
- data/lib/asciidoctor/substituters.rb +468 -0
- data/lib/asciidoctor/table.rb +499 -0
- data/lib/asciidoctor/version.rb +1 -1
- data/test/attributes_test.rb +301 -87
- data/test/blocks_test.rb +568 -0
- data/test/document_test.rb +221 -24
- data/test/fixtures/dot.gif +0 -0
- data/test/fixtures/encoding.asciidoc +1 -0
- data/test/fixtures/include-file.asciidoc +1 -0
- data/test/fixtures/tip.gif +0 -0
- data/test/headers_test.rb +411 -43
- data/test/lexer_test.rb +265 -45
- data/test/links_test.rb +144 -3
- data/test/lists_test.rb +2252 -74
- data/test/paragraphs_test.rb +21 -30
- data/test/preamble_test.rb +24 -0
- data/test/reader_test.rb +248 -12
- data/test/renderer_test.rb +22 -0
- data/test/substitutions_test.rb +414 -0
- data/test/tables_test.rb +484 -0
- data/test/test_helper.rb +70 -6
- data/test/text_test.rb +30 -6
- metadata +64 -10
- data/lib/asciidoctor/render_templates.rb +0 -317
- data/lib/asciidoctor/string.rb +0 -12
data/lib/asciidoctor/block.rb
CHANGED
@@ -5,77 +5,26 @@
|
|
5
5
|
# block = Asciidoctor::Block.new(document, :paragraph, ["`This` is a <test>"])
|
6
6
|
# block.content
|
7
7
|
# => ["<em>This</em> is a <test>"]
|
8
|
-
class Asciidoctor::Block
|
9
|
-
# Public: Get the Symbol context for this section block.
|
10
|
-
attr_reader :context
|
8
|
+
class Asciidoctor::Block < Asciidoctor::AbstractBlock
|
11
9
|
|
12
10
|
# Public: Create alias for context to be consistent w/ AsciiDoc
|
13
11
|
alias :blockname :context
|
14
12
|
|
15
|
-
# Public: Get the Hash of attributes for this block
|
16
|
-
attr_reader :attributes
|
17
|
-
|
18
|
-
# Public: Get the Array of sub-blocks for this section block.
|
19
|
-
attr_reader :blocks
|
20
|
-
|
21
13
|
# Public: Get/Set the original Array content for this section block.
|
22
14
|
attr_accessor :buffer
|
23
15
|
|
24
|
-
# Public: Get/Set the
|
25
|
-
attr_accessor :anchor
|
26
|
-
alias :id :anchor
|
27
|
-
|
28
|
-
# Public: Get/Set the Integer block level (for nested elements, like
|
29
|
-
# list elements).
|
30
|
-
attr_accessor :level
|
31
|
-
|
32
|
-
# Public: Get/Set the String block title.
|
33
|
-
attr_accessor :title
|
34
|
-
|
35
|
-
# Public: Get/Set the String block caption.
|
16
|
+
# Public: Get/Set the caption for this block
|
36
17
|
attr_accessor :caption
|
37
18
|
|
38
19
|
# Public: Initialize an Asciidoctor::Block object.
|
39
20
|
#
|
40
21
|
# parent - The parent Asciidoc Object.
|
41
22
|
# context - The Symbol context name for the type of content.
|
42
|
-
# buffer - The Array buffer of source data.
|
23
|
+
# buffer - The Array buffer of source data (default: nil).
|
43
24
|
|
44
|
-
|
45
|
-
|
46
|
-
# elements). Would probably be better to pass in just the document.
|
47
|
-
def initialize(parent, context, buffer=nil)
|
48
|
-
@parent = parent
|
49
|
-
@context = context
|
25
|
+
def initialize(parent, context, buffer = nil)
|
26
|
+
super(parent, context)
|
50
27
|
@buffer = buffer
|
51
|
-
@attributes = {}
|
52
|
-
@blocks = []
|
53
|
-
end
|
54
|
-
|
55
|
-
# Public: Get the Asciidoctor::Document instance to which this Block belongs
|
56
|
-
def document
|
57
|
-
return @document if @document
|
58
|
-
@document = (@parent.is_a?(Asciidoctor::Document) ? @parent : @parent.document)
|
59
|
-
end
|
60
|
-
|
61
|
-
def attr(name, default = nil)
|
62
|
-
default.nil? ? @attributes.fetch(name.to_s, self.document.attr(name)) :
|
63
|
-
@attributes.fetch(name.to_s, self.document.attr(name, default))
|
64
|
-
end
|
65
|
-
|
66
|
-
def attr?(name)
|
67
|
-
@attributes.has_key?(name.to_s) || self.document.attr?(name)
|
68
|
-
end
|
69
|
-
|
70
|
-
def update_attributes(attributes)
|
71
|
-
@attributes.update(attributes)
|
72
|
-
end
|
73
|
-
|
74
|
-
# Public: Get the Asciidoctor::Renderer instance being used for the ancestor
|
75
|
-
# Asciidoctor::Document instance.
|
76
|
-
def renderer
|
77
|
-
# wouldn't @parent.renderer work here? I believe so
|
78
|
-
document.renderer
|
79
28
|
end
|
80
29
|
|
81
30
|
# Public: Get the rendered String content for this Block. If the block
|
@@ -83,16 +32,16 @@ class Asciidoctor::Block
|
|
83
32
|
# rendered and returned as content that can be included in the
|
84
33
|
# parent block's template.
|
85
34
|
def render
|
86
|
-
Asciidoctor.debug "Now
|
87
|
-
|
88
|
-
|
89
|
-
|
35
|
+
Asciidoctor.debug { "Now rendering #{@context} block for #{self}" }
|
36
|
+
out = renderer.render("block_#{@context}", self)
|
37
|
+
@document.callouts.next_list if @context == :colist
|
38
|
+
out
|
90
39
|
end
|
91
40
|
|
92
41
|
def splain(parent_level = 0)
|
93
42
|
parent_level += 1
|
43
|
+
Asciidoctor.puts_indented(parent_level, "Block id: #{id}") unless self.id.nil?
|
94
44
|
Asciidoctor.puts_indented(parent_level, "Block title: #{title}") unless self.title.nil?
|
95
|
-
Asciidoctor.puts_indented(parent_level, "Block anchor: #{anchor}") unless self.anchor.nil?
|
96
45
|
Asciidoctor.puts_indented(parent_level, "Block caption: #{caption}") unless self.caption.nil?
|
97
46
|
Asciidoctor.puts_indented(parent_level, "Block level: #{level}") unless self.level.nil?
|
98
47
|
Asciidoctor.puts_indented(parent_level, "Block context: #{context}") unless self.context.nil?
|
@@ -103,7 +52,7 @@ class Asciidoctor::Block
|
|
103
52
|
buffer.each_with_index do |buf, i|
|
104
53
|
Asciidoctor.puts_indented(parent_level, "v" * (60 - parent_level*2))
|
105
54
|
Asciidoctor.puts_indented(parent_level, "Buffer ##{i} is a #{buf.class}")
|
106
|
-
Asciidoctor.puts_indented(parent_level, "Name is #{buf.
|
55
|
+
Asciidoctor.puts_indented(parent_level, "Name is #{buf.title rescue 'n/a'}")
|
107
56
|
|
108
57
|
if buf.respond_to? :splain
|
109
58
|
buf.splain(parent_level)
|
@@ -123,11 +72,12 @@ class Asciidoctor::Block
|
|
123
72
|
@blocks.each_with_index do |block, i|
|
124
73
|
Asciidoctor.puts_indented(parent_level, "v" * (60 - parent_level*2))
|
125
74
|
Asciidoctor.puts_indented(parent_level, "Block ##{i} is a #{block.class}")
|
126
|
-
Asciidoctor.puts_indented(parent_level, "Name is #{block.
|
75
|
+
Asciidoctor.puts_indented(parent_level, "Name is #{block.title rescue 'n/a'}")
|
127
76
|
|
128
77
|
block.splain(parent_level) if block.respond_to? :splain
|
129
78
|
Asciidoctor.puts_indented(parent_level, "^" * (60 - parent_level*2))
|
130
79
|
end
|
80
|
+
|
131
81
|
nil
|
132
82
|
end
|
133
83
|
|
@@ -136,213 +86,36 @@ class Asciidoctor::Block
|
|
136
86
|
#
|
137
87
|
# Examples
|
138
88
|
#
|
139
|
-
# doc = Asciidoctor::Document.new
|
89
|
+
# doc = Asciidoctor::Document.new
|
140
90
|
# block = Asciidoctor::Block.new(doc, :paragraph,
|
141
91
|
# ['`This` is what happens when you <meet> a stranger in the <alps>!'])
|
142
92
|
# block.content
|
143
93
|
# => ["<em>This</em> is what happens when you <meet> a stranger in the <alps>!"]
|
144
|
-
#
|
145
|
-
# TODO:
|
146
|
-
# * forced line breaks (partly done, at least in regular paragraphs)
|
147
|
-
# * bold, mono
|
148
|
-
# * double/single quotes
|
149
|
-
# * super/sub script
|
150
94
|
def content
|
151
95
|
|
152
|
-
#Asciidoctor.debug "For the record, buffer is:"
|
153
|
-
#Asciidoctor.debug @buffer.inspect
|
154
|
-
|
155
96
|
case @context
|
156
|
-
when :preamble, :
|
157
|
-
blocks.map{|
|
158
|
-
|
159
|
-
@buffer.map do |li|
|
160
|
-
htmlify(li.text) + li.blocks.map{|block| block.render}.join
|
161
|
-
end
|
162
|
-
# lists get iterated in template
|
97
|
+
when :preamble, :open, :example, :sidebar
|
98
|
+
@blocks.map {|b| b.render }.join
|
99
|
+
# lists get iterated in the template (for now)
|
163
100
|
# list items recurse into this block when their text and content methods are called
|
164
|
-
when :ulist, :olist, :dlist
|
101
|
+
when :ulist, :olist, :dlist, :colist
|
165
102
|
@buffer
|
166
|
-
when :listing
|
167
|
-
|
168
|
-
when :
|
169
|
-
|
103
|
+
when :listing, :literal
|
104
|
+
apply_literal_subs(@buffer)
|
105
|
+
when :pass
|
106
|
+
apply_passthrough_subs(@buffer)
|
170
107
|
when :quote, :verse, :admonition
|
171
108
|
if !@buffer.nil?
|
172
|
-
|
109
|
+
apply_normal_subs(@buffer)
|
173
110
|
else
|
174
|
-
blocks.map{|
|
111
|
+
@blocks.map {|b| b.render }.join
|
175
112
|
end
|
176
113
|
else
|
177
|
-
|
178
|
-
line.strip
|
179
|
-
line.gsub(Asciidoctor::REGEXP[:line_break], '\1{br-asciidoctor}')
|
180
|
-
end
|
181
|
-
lines = htmlify( lines.join )
|
182
|
-
sub_html_attributes(lines) # got to clean up the br-asciidoctor line-break
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
# Attribute substitution
|
187
|
-
#
|
188
|
-
# TODO: Tom all the docs
|
189
|
-
def sub_attributes(lines)
|
190
|
-
Asciidoctor.debug "Entering #{__method__} from #{caller[0]}"
|
191
|
-
if lines.is_a? String
|
192
|
-
return_string = true
|
193
|
-
lines = Array(lines)
|
194
|
-
end
|
195
|
-
|
196
|
-
result = lines.map do |line|
|
197
|
-
Asciidoctor.debug "#{__method__} -> Processing line: #{line}"
|
198
|
-
f = sub_special_chars(line)
|
199
|
-
# gsub! doesn't have lookbehind, so we have to capture and re-insert
|
200
|
-
f = f.gsub(/ (^|[^\\]) \{ (\w([\w\-_]+)?\w) \} /x) do
|
201
|
-
if self.document.attributes.has_key?($2)
|
202
|
-
# Substitute from user attributes first
|
203
|
-
$1 + self.document.attributes[$2]
|
204
|
-
elsif Asciidoctor::INTRINSICS.has_key?($2)
|
205
|
-
# Then do intrinsics
|
206
|
-
$1 + Asciidoctor::INTRINSICS[$2]
|
207
|
-
elsif Asciidoctor::HTML_ELEMENTS.has_key?($2)
|
208
|
-
$1 + Asciidoctor::HTML_ELEMENTS[$2]
|
209
|
-
else
|
210
|
-
Asciidoctor.debug "Bailing on key: #{$2}"
|
211
|
-
# delete the line if it has a bad attribute
|
212
|
-
# TODO: According to AsciiDoc, we're supposed to delete any line
|
213
|
-
# containing a bad attribute. Eek! Can't do that here via gsub!.
|
214
|
-
# (See `subs_attrs` function in asciidoc.py for many gory details.)
|
215
|
-
"{ZZZZZ}"
|
216
|
-
end
|
217
|
-
end
|
218
|
-
Asciidoctor.debug "#{__method__} -> Processed line: #{f}"
|
219
|
-
f
|
220
|
-
end
|
221
|
-
#Asciidoctor.debug "#{__method__} -> result looks like #{result.inspect}"
|
222
|
-
result.reject! {|l| l =~ /\{ZZZZZ\}/}
|
223
|
-
|
224
|
-
if return_string
|
225
|
-
result = result.join
|
226
|
-
end
|
227
|
-
result
|
228
|
-
end
|
229
|
-
|
230
|
-
def sub_html_attributes(lines)
|
231
|
-
Asciidoctor.debug "Entering #{__method__} from #{caller[0]}"
|
232
|
-
if lines.is_a? String
|
233
|
-
return_string = true
|
234
|
-
lines = Array(lines)
|
235
|
-
end
|
236
|
-
|
237
|
-
result = lines.map do |line|
|
238
|
-
Asciidoctor.debug "#{__method__} -> Processing line: #{line}"
|
239
|
-
# gsub! doesn't have lookbehind, so we have to capture and re-insert
|
240
|
-
line.gsub(/ (^|[^\\]) \{ (\w[\w\-_]+\w) \} /x) do
|
241
|
-
if Asciidoctor::HTML_ELEMENTS.has_key?($2)
|
242
|
-
$1 + Asciidoctor::HTML_ELEMENTS[$2]
|
243
|
-
else
|
244
|
-
$1 + "{#{$2}}"
|
245
|
-
end
|
246
|
-
end
|
247
|
-
end
|
248
|
-
#Asciidoctor.debug "#{__method__} -> result looks like #{result.inspect}"
|
249
|
-
result.reject! {|l| l =~ /\{ZZZZZ\}/}
|
250
|
-
|
251
|
-
if return_string
|
252
|
-
result = result.join
|
253
|
-
end
|
254
|
-
result
|
255
|
-
end
|
256
|
-
|
257
|
-
# Public: Append a sub-block to this section block
|
258
|
-
#
|
259
|
-
# block - The new sub-block.
|
260
|
-
#
|
261
|
-
# block = Block.new(parent, :preamble)
|
262
|
-
#
|
263
|
-
# block << Block.new(block, :paragraph, 'p1')
|
264
|
-
# block << Block.new(block, :paragraph, 'p2')
|
265
|
-
# block.blocks
|
266
|
-
# => ["p1", "p2"]
|
267
|
-
def <<(block)
|
268
|
-
@blocks << block
|
269
|
-
end
|
270
|
-
|
271
|
-
private
|
272
|
-
|
273
|
-
# Private: Return a String HTML version of the source string, with
|
274
|
-
# Asciidoc characters converted and HTML entities escaped.
|
275
|
-
#
|
276
|
-
# string - The String source string in Asciidoc format.
|
277
|
-
#
|
278
|
-
# Examples
|
279
|
-
#
|
280
|
-
# asciidoc_string = "Make 'this' <emphasized>"
|
281
|
-
# htmlify(asciidoc_string)
|
282
|
-
# => "Make <em>this</em> <emphasized>"
|
283
|
-
def htmlify(string)
|
284
|
-
unless string.nil?
|
285
|
-
html = string.dup
|
286
|
-
|
287
|
-
# Convert reference links to "link:" asciidoc for later HTMLification.
|
288
|
-
# This ensures that eg. "<<some reference>>" is turned into a link but
|
289
|
-
# "`<<<<<` and `>>>>>` are conflict markers" is not. This is much
|
290
|
-
# easier before the HTML is escaped and <> are turned into entities.
|
291
|
-
html.gsub!( /(^|[^<])<<([^<>,]+)(,([^>]*))?>>/ ) { "#{$1}link:##{$2}[" + ($4.nil? ? document.references[$2] : $4).to_s + "]" }
|
292
|
-
|
293
|
-
# Do the same with URLs
|
294
|
-
html.gsub!( /(^|[^(`|link:)])(https?:\/\/[^\[ ]+)(\[+[^\]]*\]+)?/ ) do
|
295
|
-
pre = $1
|
296
|
-
url = $2
|
297
|
-
link = ( $3 || $2 ).gsub( /(^\[|\]$)/,'' )
|
298
|
-
link = url if link.empty?
|
299
|
-
|
300
|
-
"#{pre}link:#{url}[#{link}]"
|
301
|
-
end
|
302
|
-
|
303
|
-
html.gsub!(Asciidoctor::REGEXP[:biblio], '<a name="\1">[\1]</a>')
|
304
|
-
html.gsub!(Asciidoctor::REGEXP[:ruler], "<hr>\n")
|
305
|
-
html.gsub!(/``([^`']*)''/m, '“\1”')
|
306
|
-
html.gsub!(/(?:\s|^)`([^`']*)'/m, '‘\1’')
|
307
|
-
|
308
|
-
# TODO: This text thus quoted is supposed to be rendered as an
|
309
|
-
# "inline literal passthrough", meaning that it is rendered
|
310
|
-
# in a monospace font, but also doesn't go through any further
|
311
|
-
# text substitution, except for special character substitution.
|
312
|
-
# So we need to technically pull this text out, sha it and store
|
313
|
-
# a marker and replace it after the other gsub!s are done in here.
|
314
|
-
# See: http://www.methods.co.nz/asciidoc/userguide.html#X80
|
315
|
-
html.gsub!(/`([^`]+)`/m) { "<tt>#{$1.gsub( '*', '{asterisk}' ).gsub( '\'', '{apostrophe}' )}</tt>" }
|
316
|
-
html.gsub!(/([\s\W])#(.+?)#([\s\W])/, '\1\2\3')
|
317
|
-
|
318
|
-
# "Unconstrained" quotes
|
319
|
-
html.gsub!(/\_\_([^\_]+)\_\_/m, '<em>\1</em>')
|
320
|
-
html.gsub!(/\*\*([^\*]+)\*\*/m, '<strong>\1</strong>')
|
321
|
-
html.gsub!(/\+\+([^\+]+)\+\+/m, '<tt>\1</tt>')
|
322
|
-
html.gsub!(/\^\^([^\^]+)\^\^/m, '<sup>\1</sup>')
|
323
|
-
html.gsub!(/\~\~([^\~]+)\~\~/m, '<sub>\1</sub>')
|
324
|
-
|
325
|
-
# "Constrained" quotes, which must be bounded by white space or
|
326
|
-
# common punctuation characters
|
327
|
-
html.gsub!(/(^|\s|\W)\*([^\*]+)\*(\s|\W|$)/m, '\1<strong>\2</strong>\3')
|
328
|
-
html.gsub!(/(^|\s|\W)'(.+?)'(\s|\W|$)/m, '\1<em>\2</em>\3')
|
329
|
-
# restore escaped single quotes after processing emphasis
|
330
|
-
html.gsub!(/(\w)\\'(\w)/, '\1\'\2')
|
331
|
-
html.gsub!(/(^|\s|\W)_([^_]+)_(\s|\W|$)/m, '\1<em>\2</em>\3')
|
332
|
-
html.gsub!(/(^|\s|\W)\+([^\+]+)\+(\s|\W|$)/m, '\1<tt>\2</tt>\3')
|
333
|
-
html.gsub!(/(^|\s|\W)\^([^\^]+)\^(\s|\W|$)/m, '\1<sup>\2</sup>\3')
|
334
|
-
html.gsub!(/(^|\s|\W)\~([^\~]+)\~(\s|\W|$)/m, '\1<sub>\2</sub>\3')
|
335
|
-
|
336
|
-
html.gsub!(/\\([\{\}\-])/, '\1')
|
337
|
-
html.gsub!(/linkgit:([^\]]+)\[(\d+)\]/, '<a href="\1.html">\1(\2)</a>')
|
338
|
-
html.gsub!(/link:([^\[]+)(\[+[^\]]*\]+)/ ) { "<a href=\"#{$1}\">#{$2.gsub( /(^\[|\]$)/,'' )}</a>" }
|
339
|
-
html.gsub!(Asciidoctor::REGEXP[:line_break], '\1<br/>')
|
340
|
-
html
|
114
|
+
apply_normal_subs(@buffer)
|
341
115
|
end
|
342
116
|
end
|
343
117
|
|
344
|
-
def
|
345
|
-
|
118
|
+
def to_s
|
119
|
+
"#{super.to_s} - #@context [blocks:#{(@blocks || []).size}]"
|
346
120
|
end
|
347
|
-
# end private
|
348
121
|
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# Public: Maintains a catalog of callouts and their associations.
|
2
|
+
class Asciidoctor::Callouts
|
3
|
+
def initialize
|
4
|
+
@lists = []
|
5
|
+
@list_index = 0
|
6
|
+
next_list
|
7
|
+
end
|
8
|
+
|
9
|
+
# Public: Register a new callout for the given list item ordinal.
|
10
|
+
#
|
11
|
+
# Generates a unique id for this callout based on the index of the next callout
|
12
|
+
# list in the document and the index of this callout since the end of the last
|
13
|
+
# callout list.
|
14
|
+
#
|
15
|
+
# li_ordinal - the Integer ordinal (1-based) of the list item to which this
|
16
|
+
# callout is to be associated
|
17
|
+
#
|
18
|
+
# Examples
|
19
|
+
#
|
20
|
+
# callouts = Asciidoctor::Callouts.new
|
21
|
+
# callouts.register(1)
|
22
|
+
# # => "CO1-1"
|
23
|
+
# callouts.next_list
|
24
|
+
# callouts.register(2)
|
25
|
+
# # => "CO2-1"
|
26
|
+
#
|
27
|
+
# Returns The unique String id of this callout
|
28
|
+
def register(li_ordinal)
|
29
|
+
current_list << {:ordinal => li_ordinal.to_i, :id => (id = generate_next_callout_id)}
|
30
|
+
@co_index += 1
|
31
|
+
|
32
|
+
id
|
33
|
+
end
|
34
|
+
|
35
|
+
# Public: Get the next callout index in the document
|
36
|
+
#
|
37
|
+
# Reads the next callout index in the document and advances the pointer.
|
38
|
+
# This method is used during rendering to retrieve the unique id of the
|
39
|
+
# callout that was generated during lexing.
|
40
|
+
#
|
41
|
+
# Returns The unique String id of the next callout in the document
|
42
|
+
def read_next_id
|
43
|
+
id = nil
|
44
|
+
list = current_list
|
45
|
+
|
46
|
+
if @co_index <= list.size
|
47
|
+
id = list[@co_index - 1][:id]
|
48
|
+
end
|
49
|
+
|
50
|
+
@co_index += 1
|
51
|
+
|
52
|
+
id
|
53
|
+
end
|
54
|
+
|
55
|
+
# Public: Get a space-separated list of callout ids for the specified list item
|
56
|
+
#
|
57
|
+
# li_ordinal - the Integer ordinal (1-based) of the list item for which to
|
58
|
+
# retrieve the callouts
|
59
|
+
#
|
60
|
+
# Returns A space-separated String of callout ids associated with the specified list item
|
61
|
+
def callout_ids(li_ordinal)
|
62
|
+
current_list.inject([]) {|collector, element|
|
63
|
+
collector << element[:id] if element[:ordinal] == li_ordinal
|
64
|
+
collector
|
65
|
+
} * ' '
|
66
|
+
end
|
67
|
+
|
68
|
+
# Public: The current list for which callouts are being collected
|
69
|
+
#
|
70
|
+
# Returns The Array of callouts at the position of the list index pointer
|
71
|
+
def current_list
|
72
|
+
@lists[@list_index - 1]
|
73
|
+
end
|
74
|
+
|
75
|
+
# Public: Advance to the next callout list in the document
|
76
|
+
#
|
77
|
+
# Returns nothing
|
78
|
+
def next_list
|
79
|
+
@list_index += 1
|
80
|
+
|
81
|
+
if @lists.size < @list_index
|
82
|
+
@lists << []
|
83
|
+
end
|
84
|
+
|
85
|
+
@co_index = 1
|
86
|
+
|
87
|
+
nil
|
88
|
+
end
|
89
|
+
|
90
|
+
# Public: Rewind the list index pointer, intended to be used when switching
|
91
|
+
# from the parsing to rendering phase.
|
92
|
+
#
|
93
|
+
# Returns nothing
|
94
|
+
def rewind
|
95
|
+
@list_index = 1
|
96
|
+
@co_index = 1
|
97
|
+
|
98
|
+
nil
|
99
|
+
end
|
100
|
+
|
101
|
+
# Internal: Generate a unique id for the callout based on the internal indexes
|
102
|
+
#
|
103
|
+
# Returns A unique String id for this callout
|
104
|
+
def generate_next_callout_id
|
105
|
+
generate_callout_id(@list_index, @co_index)
|
106
|
+
end
|
107
|
+
|
108
|
+
# Internal: Generate a unique id for the callout at the specified position
|
109
|
+
#
|
110
|
+
# list_index - The 1-based Integer index of the callout list within the document
|
111
|
+
# co_index - The 1-based Integer index of the callout since the end of the last callout list
|
112
|
+
#
|
113
|
+
# Returns A unique String id for a callout
|
114
|
+
def generate_callout_id(list_index, co_index)
|
115
|
+
"CO#{list_index}-#{co_index}"
|
116
|
+
end
|
117
|
+
end
|