asciidoctor 0.1.1 → 0.1.2

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.

Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +1 -1
  3. data/LICENSE +2 -2
  4. data/README.adoc +461 -0
  5. data/asciidoctor.gemspec +27 -16
  6. data/compat/asciidoc.conf +139 -0
  7. data/lib/asciidoctor.rb +212 -69
  8. data/lib/asciidoctor/abstract_block.rb +41 -0
  9. data/lib/asciidoctor/abstract_node.rb +128 -81
  10. data/lib/asciidoctor/attribute_list.rb +5 -2
  11. data/lib/asciidoctor/backends/base_template.rb +16 -4
  12. data/lib/asciidoctor/backends/docbook45.rb +112 -42
  13. data/lib/asciidoctor/backends/html5.rb +206 -90
  14. data/lib/asciidoctor/block.rb +5 -5
  15. data/lib/asciidoctor/cli/invoker.rb +38 -34
  16. data/lib/asciidoctor/cli/options.rb +3 -3
  17. data/lib/asciidoctor/document.rb +115 -13
  18. data/lib/asciidoctor/helpers.rb +16 -0
  19. data/lib/asciidoctor/lexer.rb +486 -359
  20. data/lib/asciidoctor/path_resolver.rb +360 -0
  21. data/lib/asciidoctor/reader.rb +122 -23
  22. data/lib/asciidoctor/renderer.rb +1 -33
  23. data/lib/asciidoctor/section.rb +1 -1
  24. data/lib/asciidoctor/substituters.rb +103 -19
  25. data/lib/asciidoctor/version.rb +1 -1
  26. data/man/asciidoctor.1 +6 -6
  27. data/man/asciidoctor.ad +5 -3
  28. data/stylesheets/asciidoctor.css +274 -0
  29. data/test/attributes_test.rb +133 -10
  30. data/test/blocks_test.rb +302 -17
  31. data/test/document_test.rb +269 -6
  32. data/test/fixtures/basic-docinfo.html +1 -0
  33. data/test/fixtures/basic-docinfo.xml +4 -0
  34. data/test/fixtures/basic.asciidoc +4 -0
  35. data/test/fixtures/docinfo.html +1 -0
  36. data/test/fixtures/docinfo.xml +2 -0
  37. data/test/fixtures/include-file.asciidoc +22 -1
  38. data/test/fixtures/stylesheets/custom.css +3 -0
  39. data/test/invoker_test.rb +38 -6
  40. data/test/lexer_test.rb +64 -21
  41. data/test/links_test.rb +4 -0
  42. data/test/lists_test.rb +251 -12
  43. data/test/paragraphs_test.rb +225 -30
  44. data/test/paths_test.rb +174 -0
  45. data/test/reader_test.rb +89 -2
  46. data/test/sections_test.rb +518 -16
  47. data/test/substitutions_test.rb +121 -10
  48. data/test/tables_test.rb +53 -13
  49. data/test/test_helper.rb +2 -2
  50. data/test/text_test.rb +5 -5
  51. metadata +46 -50
  52. data/README.asciidoc +0 -296
  53. data/lib/asciidoctor/errors.rb +0 -5
@@ -189,6 +189,47 @@ class AbstractBlock < AbstractNode
189
189
  }
190
190
  end
191
191
 
192
+ # Public: Generate a caption and assign it to this block if one
193
+ # is not already assigned.
194
+ #
195
+ # If the block has a title and a caption prefix is available
196
+ # for this block, then build a caption from this information,
197
+ # assign it a number and store it to the caption attribute on
198
+ # the block.
199
+ #
200
+ # If an explicit caption has been specified on this block, then
201
+ # do nothing.
202
+ #
203
+ # key - The prefix of the caption and counter attribute names.
204
+ # If not provided, the name of the context for this block
205
+ # is used. (default: nil).
206
+ #
207
+ # returns nothing
208
+ def assign_caption(caption = nil, key = nil)
209
+ unless title? || @caption.nil?
210
+ return nil
211
+ end
212
+
213
+ if caption.nil?
214
+ if @document.attr?('caption')
215
+ @caption = @document.attr('caption')
216
+ elsif title?
217
+ key ||= @context.to_s
218
+ caption_key = "#{key}-caption"
219
+ if @document.attributes.has_key?(caption_key)
220
+ caption_title = @document.attributes["#{key}-caption"]
221
+ caption_num = @document.counter_increment("#{key}-number", self)
222
+ @caption = @attributes['caption'] = "#{caption_title} #{caption_num}. "
223
+ end
224
+ else
225
+ @caption = caption
226
+ end
227
+ else
228
+ @caption = caption
229
+ end
230
+ nil
231
+ end
232
+
192
233
  # Internal: Assign the next index (0-based) to this section
193
234
  #
194
235
  # Assign the next index of this section within the parent
@@ -94,6 +94,27 @@ class AbstractNode
94
94
  end
95
95
  end
96
96
 
97
+ # Public: Assign the value to the specified key in this
98
+ # block's attributes hash.
99
+ #
100
+ # key - The attribute key (or name)
101
+ # val - The value to assign to the key
102
+ #
103
+ # returns a flag indicating whether the assignment was performed
104
+ def set_attr(key, val, overwrite = nil)
105
+ if overwrite.nil?
106
+ @attributes[key] = val
107
+ true
108
+ else
109
+ if overwrite || @attributes.has_key?(key)
110
+ @attributes[key] = val
111
+ true
112
+ else
113
+ false
114
+ end
115
+ end
116
+ end
117
+
97
118
  # Public: Get the execution context of this object (via Kernel#binding).
98
119
  #
99
120
  # This method is used to set the 'self' reference as well as local variables
@@ -156,11 +177,35 @@ class AbstractNode
156
177
  if attr? 'icon'
157
178
  image_uri(attr('icon'), nil)
158
179
  else
159
- image_uri(name + '.' + @document.attr('icontype', 'png'), 'iconsdir')
180
+ image_uri("#{name}.#{@document.attr('icontype', 'png')}", 'iconsdir')
181
+ end
182
+ end
183
+
184
+ # Public: Construct a URI reference to the target media.
185
+ #
186
+ # If the target media is a URI reference, then leave it untouched.
187
+ #
188
+ # The target media is resolved relative to the directory retrieved from the
189
+ # specified attribute key, if provided.
190
+ #
191
+ # The return value can be safely used in a media tag (img, audio, video).
192
+ #
193
+ # target - A String reference to the target media
194
+ # asset_dir_key - The String attribute key used to lookup the directory where
195
+ # the media is located (default: 'imagesdir')
196
+ #
197
+ # Returns A String reference for the target media
198
+ def media_uri(target, asset_dir_key = 'imagesdir')
199
+ if target.include?(':') && target.match(Asciidoctor::REGEXP[:uri_sniff])
200
+ target
201
+ elsif asset_dir_key && attr?(asset_dir_key)
202
+ normalize_web_path(target, @document.attr(asset_dir_key))
203
+ else
204
+ normalize_web_path(target)
160
205
  end
161
206
  end
162
207
 
163
- # Public: Construct a reference or data URI to the target image.
208
+ # Public: Construct a URI reference or data URI to the target image.
164
209
  #
165
210
  # If the target image is a URI reference, then leave it untouched.
166
211
  #
@@ -185,9 +230,9 @@ class AbstractNode
185
230
  elsif @document.safe < Asciidoctor::SafeMode::SECURE && @document.attr?('data-uri')
186
231
  generate_data_uri(target_image, asset_dir_key)
187
232
  elsif asset_dir_key && attr?(asset_dir_key)
188
- File.join(@document.attr(asset_dir_key), target_image)
233
+ normalize_web_path(target_image, @document.attr(asset_dir_key))
189
234
  else
190
- target_image
235
+ normalize_web_path(target_image)
191
236
  end
192
237
  end
193
238
 
@@ -208,9 +253,17 @@ class AbstractNode
208
253
 
209
254
  mimetype = 'image/' + File.extname(target_image)[1..-1]
210
255
  if asset_dir_key
211
- image_path = File.join(normalize_asset_path(@document.attr(asset_dir_key, '.'), asset_dir_key), target_image)
256
+ #asset_dir_path = normalize_system_path(@document.attr(asset_dir_key), nil, nil, :target_name => asset_dir_key)
257
+ #image_path = normalize_system_path(target_image, asset_dir_path, nil, :target_name => 'image')
258
+ image_path = normalize_system_path(target_image, @document.attr(asset_dir_key), nil, :target_name => 'image')
212
259
  else
213
- image_path = normalize_asset_path(target_image)
260
+ image_path = normalize_system_path(target_image)
261
+ end
262
+
263
+ if !File.readable? image_path
264
+ puts "asciidoctor: WARNING: image to embed not found or not readable: #{image_path}"
265
+ return "data:#{mimetype}:base64,"
266
+ #return 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=='
214
267
  end
215
268
 
216
269
  bindata = nil
@@ -219,88 +272,82 @@ class AbstractNode
219
272
  else
220
273
  bindata = File.open(image_path, 'rb') {|file| file.read }
221
274
  end
222
- 'data:' + mimetype + ';base64,' + Base64.encode64(bindata).delete("\n")
275
+ "data:#{mimetype};base64,#{Base64.encode64(bindata).delete("\n")}"
223
276
  end
224
277
 
225
- # Public: Normalize the asset file or directory to a concrete and rinsed path
226
- #
227
- # The most important functionality in this method is to prevent the asset
228
- # reference from resolving to a directory outside of the chroot directory
229
- # (which defaults to the directory of the source file, stored in the base_dir
230
- # instance variable on Document) if the document safe level is set to
231
- # SafeMode::SAFE or greater (a condition which is true by default).
232
- #
233
- # asset_ref - the String asset file or directory referenced in the document
234
- # or configuration attribute
235
- # asset_name - the String name of the file or directory being resolved (for use in
236
- # the warning message) (default: 'path')
237
- #
238
- # Examples
239
- #
240
- # # given these fixtures
241
- # document.base_dir
242
- # # => "/path/to/chroot"
243
- # document.safe >= Asciidoctor::SafeMode::SAFE
244
- # # => true
245
- #
246
- # # then
247
- # normalize_asset_path('images')
248
- # # => "/path/to/chroot/images"
249
- # normalize_asset_path('/etc/images')
250
- # # => "/path/to/chroot/images"
251
- # normalize_asset_path('../images')
252
- # # => "/path/to/chroot/images"
253
- #
254
- # # given these fixtures
255
- # document.base_dir
256
- # # => "/path/to/chroot"
257
- # document.safe >= Asciidoctor::SafeMode::SAFE
258
- # # => false
259
- #
260
- # # then
261
- # normalize_asset_path('images')
262
- # # => "/path/to/chroot/images"
263
- # normalize_asset_path('/etc/images')
264
- # # => "/etc/images"
265
- # normalize_asset_path('../images')
266
- # # => "/path/to/images"
267
- #
268
- # Returns The normalized asset file or directory as a String path
269
- #--
270
- # TODO this method is missing a coordinate; it should be able to resolve
271
- # both the directory reference and the path to an asset in it; callers
272
- # of this method are still doing a File.join to finish the task
273
- def normalize_asset_path(asset_ref, asset_name = 'path', autocorrect = true)
274
- # TODO we may use pathname enough to make it a top-level require
275
- Helpers.require_library 'pathname'
276
-
277
- input_path = @document.base_dir
278
- asset_path = Pathname.new(asset_ref)
279
-
280
- if asset_path.relative?
281
- asset_path = File.expand_path(File.join(input_path, asset_ref))
278
+ # Public: Read the contents of the file at the specified path.
279
+ # This method assumes that the path is safe to read. It checks
280
+ # that the file is readable before attempting to read it.
281
+ #
282
+ # path - the String path from which to read the contents
283
+ # warn_on_failure - a Boolean that controls whether a warning is issued if
284
+ # the file cannot be read
285
+ #
286
+ # returns the contents of the file at the specified path, or nil
287
+ # if the file does not exist.
288
+ def read_asset(path, warn_on_failure = false)
289
+ if File.readable? path
290
+ File.read path
282
291
  else
283
- asset_path = asset_path.cleanpath.to_s
292
+ puts "asciidoctor: WARNING: file does not exist or cannot be read: #{path}" if warn_on_failure
293
+ nil
284
294
  end
295
+ end
285
296
 
286
- if @document.safe >= SafeMode::SAFE
287
- relative_asset_path = Pathname.new(asset_path).relative_path_from(Pathname.new(input_path)).to_s
288
- if relative_asset_path.start_with?('..')
289
- if autocorrect
290
- puts "asciidoctor: WARNING: #{asset_name} has illegal reference to ancestor of base directory"
291
- else
292
- raise SecurityError, "#{asset_name} has reference to path outside of base directory, disallowed in safe mode: #{asset_path}"
293
- end
294
- relative_asset_path.sub!(/^(?:\.\.\/)*/, '')
295
- # just to be absolutely sure ;)
296
- if relative_asset_path[0..0] == '.'
297
- raise 'Substitution of parent path references failed for ' + relative_asset_path
298
- end
299
- asset_path = File.expand_path(File.join(input_path, relative_asset_path))
300
- end
297
+ # Public: Normalize the web page using the PathResolver.
298
+ #
299
+ # See PathResolver::web_path(target, start) for details.
300
+ #
301
+ # target - the String target path
302
+ # start - the String start (i.e, parent) path (optional, default: nil)
303
+ #
304
+ # returns the resolved String path
305
+ def normalize_web_path(target, start = nil)
306
+ PathResolver.new.web_path(target, start)
307
+ end
308
+
309
+ # Public: Resolve and normalize a secure path from the target and start paths
310
+ # using the PathResolver.
311
+ #
312
+ # See PathResolver::system_path(target, start, jail, opts) for details.
313
+ #
314
+ # The most important functionality in this method is to prevent resolving a
315
+ # path outside of the jail (which defaults to the directory of the source
316
+ # file, stored in the base_dir instance variable on Document) if the document
317
+ # safe level is set to SafeMode::SAFE or greater (a condition which is true
318
+ # by default).
319
+ #
320
+ # target - the String target path
321
+ # start - the String start (i.e., parent) path
322
+ # jail - the String jail path to confine the resolved path
323
+ # opts - an optional Hash of options to control processing (default: {}):
324
+ # * :recover is used to control whether the processor should auto-recover
325
+ # when an illegal path is encountered
326
+ # * :target_name is used in messages to refer to the path being resolved
327
+ #
328
+ # raises a SecurityError if a jail is specified and the resolved path is
329
+ # outside the jail.
330
+ #
331
+ # returns a String path resolved from the start and target paths, with any
332
+ # parent references resolved and self references removed. If a jail is provided,
333
+ # this path will be guaranteed to be contained within the jail.
334
+ def normalize_system_path(target, start = nil, jail = nil, opts = {})
335
+ if start.nil?
336
+ start = @document.base_dir
301
337
  end
338
+ if jail.nil? && @document.safe >= SafeMode::SAFE
339
+ jail = @document.base_dir
340
+ end
341
+ PathResolver.new.system_path(target, start, jail, opts)
342
+ end
302
343
 
303
- asset_path
344
+ # Public: Normalize the asset file or directory to a concrete and rinsed path
345
+ #
346
+ # Delegates to normalize_system_path, with the start path set to the value of
347
+ # the base_dir instance variable on the Document object.
348
+ def normalize_asset_path(asset_ref, asset_name = 'path', autocorrect = true)
349
+ normalize_system_path(asset_ref, @document.base_dir, nil,
350
+ :target_name => asset_name, :recover => autocorrect)
304
351
  end
305
352
 
306
353
  end
@@ -84,6 +84,7 @@ class AttributeList
84
84
 
85
85
  def self.rekey(attributes, pos_attrs)
86
86
  pos_attrs.each_with_index do |key, index|
87
+ next if key.nil?
87
88
  pos = index + 1
88
89
  unless (val = attributes[pos]).nil?
89
90
  attributes[key] = val
@@ -166,9 +167,11 @@ class AttributeList
166
167
  else
167
168
  resolved_value = value
168
169
  # example: options="opt1,opt2,opt3"
169
- if name == 'options'
170
+ # opts is an alias for options
171
+ if name == 'options' || name == 'opts'
172
+ name = 'options'
170
173
  resolved_value.split(CSV_SPLIT_PATTERN).each do |o|
171
- @attributes[o + '-option'] = nil
174
+ @attributes[o + '-option'] = ''
172
175
  end
173
176
  elsif single_quoted_value && !@block.nil?
174
177
  resolved_value = @block.apply_normal_subs(value)
@@ -40,15 +40,17 @@ class BaseTemplate
40
40
  # locals - A Hash of additional variables. Not currently in use.
41
41
  def render(node = Object.new, locals = {})
42
42
  tmpl = template
43
- if tmpl.equal? :content
43
+ case tmpl
44
+ when :invoke_result
45
+ return result(node)
46
+ when :content
44
47
  result = node.content
45
- #elsif tmpl.is_a?(String)
46
- # result = tmpl
47
48
  else
48
49
  result = tmpl.result(node.get_binding(self))
49
50
  end
50
51
 
51
- if (@view == 'document' || @view == 'embedded') && node.renderer.compact
52
+ if (@view == 'document' || @view == 'embedded') &&
53
+ node.renderer.compact && !node.document.nested?
52
54
  compact result
53
55
  else
54
56
  result
@@ -105,4 +107,14 @@ class BaseTemplate
105
107
  attribute('id', '@id')
106
108
  end
107
109
  end
110
+
111
+ module EmptyTemplate
112
+ def result(node)
113
+ ''
114
+ end
115
+
116
+ def template
117
+ :invoke_result
118
+ end
119
+ end
108
120
  end
@@ -1,11 +1,12 @@
1
1
  module Asciidoctor
2
2
  class BaseTemplate
3
- def tag(name, key)
3
+ def tag(name, key, dynamic = false)
4
4
  type = key.is_a?(Symbol) ? :attr : :var
5
5
  key = key.to_s
6
6
  if type == :attr
7
+ key_str = dynamic ? %("#{key}") : "'#{key}'"
7
8
  # example: <% if attr? 'foo' %><bar><%= attr 'foo' %></bar><% end %>
8
- %(<% if attr? '#{key}' %><#{name}><%= attr '#{key}' %></#{name}><% end %>)
9
+ %(<% if attr? #{key_str} %><#{name}><%= attr #{key_str} %></#{name}><% end %>)
9
10
  else
10
11
  # example: <% unless foo.to_s.empty? %><bar><%= foo %></bar><% end %>
11
12
  %(<% unless #{key}.to_s.empty? %><#{name}><%= #{key} %></#{name}><% end %>)
@@ -31,10 +32,20 @@ module Asciidoctor
31
32
 
32
33
  module DocBook45
33
34
  class DocumentTemplate < BaseTemplate
35
+ def title_tags(str)
36
+ if str.include?(': ')
37
+ title, _, subtitle = str.rpartition(': ')
38
+ %(<title>#{title}</title>
39
+ <subtitle>#{subtitle}</subtitle>)
40
+ else
41
+ %(<title>#{str}</title>)
42
+ end
43
+ end
44
+
34
45
  def docinfo
35
46
  <<-EOF
36
47
  <% if has_header? && !notitle %>
37
- #{tag 'title', '@header.title'}
48
+ <%= template.title_tags(@header.title) %>
38
49
  <% end %>
39
50
  <% if attr? :revdate %>
40
51
  <date><%= attr :revdate %></date>
@@ -43,6 +54,7 @@ class DocumentTemplate < BaseTemplate
43
54
  <% end %>
44
55
  <% if has_header? %>
45
56
  <% if attr? :author %>
57
+ <% if attr? :authorcount, 1 %>
46
58
  <author>
47
59
  #{tag 'firstname', :firstname}
48
60
  #{tag 'othername', :middlename}
@@ -50,15 +62,31 @@ class DocumentTemplate < BaseTemplate
50
62
  #{tag 'email', :email}
51
63
  </author>
52
64
  #{tag 'authorinitials', :authorinitials}
65
+ <% else %>
66
+ <authorgroup>
67
+ <% (1..(attr(:authorcount))).each do |idx| %>
68
+ <author>
69
+ #{tag 'firstname', :"firstname_\#{idx}", true}
70
+ #{tag 'othername', :"middlename_\#{idx}", true}
71
+ #{tag 'surname', :"lastname_\#{idx}", true}
72
+ #{tag 'email', :"email_\#{idx}", true}
73
+ </author>
74
+ <% end %>
75
+ </authorgroup>
76
+ <% end %>
53
77
  <% end %>
54
78
  <% if (attr? :revnumber) || (attr? :revremark) %>
55
79
  <revhistory>
56
- #{tag 'revision', :revnumber}
57
- #{tag 'date', :revdate}
58
- #{tag 'authorinitials', :authorinitials}
59
- #{tag 'revremark', :revremark}
80
+ <revision>
81
+ #{tag 'revnumber', :revnumber}
82
+ #{tag 'date', :revdate}
83
+ #{tag 'authorinitials', :authorinitials}
84
+ #{tag 'revremark', :revremark}
85
+ </revision>
60
86
  </revhistory>
61
87
  <% end %>
88
+ <%= docinfo %>
89
+ #{tag 'orgname', :orgname}
62
90
  <% end %>
63
91
  EOF
64
92
  end
@@ -94,12 +122,22 @@ class EmbeddedTemplate < BaseTemplate
94
122
  end
95
123
  end
96
124
 
125
+ class BlockTocTemplate < BaseTemplate
126
+ def result(node)
127
+ ''
128
+ end
129
+
130
+ def template
131
+ :invoke_result
132
+ end
133
+ end
134
+
97
135
  class BlockPreambleTemplate < BaseTemplate
98
136
  def template
99
137
  @template ||= @eruby.new <<-EOF
100
138
  <%#encoding:UTF-8%><% if @document.doctype == 'book' %>
101
139
  <preface#{common_attrs_erb}>
102
- <title><%= title %></title>
140
+ #{title_tag false}
103
141
  <%= content %>
104
142
  </preface>
105
143
  <% else %>
@@ -110,11 +148,11 @@ class BlockPreambleTemplate < BaseTemplate
110
148
  end
111
149
 
112
150
  class SectionTemplate < BaseTemplate
113
- def section(sec)
151
+ def result(sec)
114
152
  if sec.special
115
153
  tag = sec.level <= 1 ? sec.sectname : 'section'
116
154
  else
117
- tag = sec.document.doctype == 'book' && sec.level <= 1 ? 'chapter' : 'section'
155
+ tag = sec.document.doctype == 'book' && sec.level <= 1 ? (sec.level == 0 ? 'part' : 'chapter') : 'section'
118
156
  end
119
157
  %(<#{tag}#{common_attrs(sec.id, (sec.attr 'role'), (sec.attr 'reftext'))}>
120
158
  #{sec.title? ? "<title>#{sec.title}</title>" : nil}
@@ -123,10 +161,7 @@ class SectionTemplate < BaseTemplate
123
161
  end
124
162
 
125
163
  def template
126
- # hot piece of code, optimized for speed
127
- @template ||= @eruby.new <<-EOF
128
- <%#encoding:UTF-8%><%= template.section(self) %>
129
- EOF
164
+ :invoke_result
130
165
  end
131
166
  end
132
167
 
@@ -138,25 +173,38 @@ class BlockFloatingTitleTemplate < BaseTemplate
138
173
  end
139
174
  end
140
175
 
141
-
142
176
  class BlockParagraphTemplate < BaseTemplate
143
-
144
- def paragraph(id, role, reftext, title, content)
145
- if title
146
- %(<formalpara#{common_attrs(id, role, reftext)}>
177
+ def paragraph(id, style, role, reftext, title, content)
178
+ # FIXME temporary hack until I can generalize this feature
179
+ if style == 'partintro'
180
+ if title
181
+ %(<partintro#{common_attrs(id, role, reftext)}>
182
+ <title>#{title}</title>
183
+ <simpara>#{content}</simpara>
184
+ </partintro>)
185
+ else
186
+ %(<partintro#{common_attrs(id, role, reftext)}>
187
+ <simpara>#{content}</simpara>
188
+ </partintro>)
189
+ end
190
+ else
191
+ if title
192
+ %(<formalpara#{common_attrs(id, role, reftext)}>
147
193
  <title>#{title}</title>
148
194
  <para>#{content}</para>
149
195
  </formalpara>)
150
- else
151
- %(<simpara#{common_attrs(id, role, reftext)}>#{content}</simpara>)
196
+ else
197
+ %(<simpara#{common_attrs(id, role, reftext)}>#{content}</simpara>)
198
+ end
152
199
  end
153
200
  end
154
201
 
202
+ def result(node)
203
+ paragraph(node.id, node.attr('style'), node.attr('role'), node.attr('reftext'), (node.title? ? node.title : nil), node.content)
204
+ end
205
+
155
206
  def template
156
- # very hot piece of code, optimized for speed
157
- @template ||= @eruby.new <<-EOF
158
- <%#encoding:UTF-8%><%= template.paragraph(@id, (attr 'role'), (attr 'reftext'), title? ? title : nil, content) %>
159
- EOF
207
+ :invoke_result
160
208
  end
161
209
  end
162
210
 
@@ -254,7 +302,8 @@ class BlockDlistTemplate < BaseTemplate
254
302
  'qanda' => {
255
303
  :list => 'qandaset',
256
304
  :entry => 'qandaentry',
257
- :term => 'question',
305
+ :label => 'question',
306
+ :term => 'simpara',
258
307
  :item => 'answer'
259
308
  },
260
309
  'glossary' => {
@@ -272,9 +321,17 @@ class BlockDlistTemplate < BaseTemplate
272
321
  #{title_tag}
273
322
  <% content.each do |dt, dd| %>
274
323
  <<%= tags[:entry] %>>
324
+ <% if tags.has_key?(:label) %>
325
+ <<%= tags[:label] %>>
326
+ <<%= tags[:term] %>>
327
+ <%= dt.text %>
328
+ </<%= tags[:term] %>>
329
+ </<%= tags[:label] %>>
330
+ <% else %>
275
331
  <<%= tags[:term] %>>
276
332
  <%= dt.text %>
277
333
  </<%= tags[:term] %>>
334
+ <% end %>
278
335
  <% unless dd.nil? %>
279
336
  <<%= tags[:item] %>>
280
337
  <% if dd.text? %>
@@ -469,6 +526,14 @@ class BlockImageTemplate < BaseTemplate
469
526
  end
470
527
  end
471
528
 
529
+ class BlockAudioTemplate < BaseTemplate
530
+ include EmptyTemplate
531
+ end
532
+
533
+ class BlockVideoTemplate < BaseTemplate
534
+ include EmptyTemplate
535
+ end
536
+
472
537
  class BlockRulerTemplate < BaseTemplate
473
538
  def template
474
539
  @template ||= @eruby.new <<-EOF
@@ -494,6 +559,8 @@ class InlineBreakTemplate < BaseTemplate
494
559
  end
495
560
 
496
561
  class InlineQuotedTemplate < BaseTemplate
562
+ NO_TAGS = ['', '']
563
+
497
564
  QUOTED_TAGS = {
498
565
  :emphasis => ['<emphasis>', '</emphasis>'],
499
566
  :strong => ['<emphasis role="strong">', '</emphasis>'],
@@ -502,11 +569,10 @@ class InlineQuotedTemplate < BaseTemplate
502
569
  :subscript => ['<subscript>', '</subscript>'],
503
570
  :double => ['&#8220;', '&#8221;'],
504
571
  :single => ['&#8216;', '&#8217;']
505
- #:none => ['', '']
506
572
  }
507
573
 
508
- def quote(text, type, role)
509
- start_tag, end_tag = QUOTED_TAGS[type] || ['', '']
574
+ def quote_text(text, type, role)
575
+ start_tag, end_tag = QUOTED_TAGS[type] || NO_TAGS
510
576
  if role
511
577
  "#{start_tag}<phrase role=\"#{role}\">#{text}</phrase>#{end_tag}"
512
578
  else
@@ -514,11 +580,12 @@ class InlineQuotedTemplate < BaseTemplate
514
580
  end
515
581
  end
516
582
 
583
+ def result(node)
584
+ quote_text(node.text, node.type, node.attr('role'))
585
+ end
586
+
517
587
  def template
518
- # very hot piece of code, optimized for speed
519
- @template ||= @eruby.new <<-EOF
520
- <%#encoding:UTF-8%><%= template.quote(@text, @type, attr('role')) %>
521
- EOF
588
+ :invoke_result
522
589
  end
523
590
  end
524
591
 
@@ -536,11 +603,12 @@ class InlineAnchorTemplate < BaseTemplate
536
603
  end
537
604
  end
538
605
 
606
+ def result(node)
607
+ anchor(node.target, node.text, node.type)
608
+ end
609
+
539
610
  def template
540
- # hot piece of code, optimized for speed
541
- @template ||= @eruby.new <<-EOS
542
- <%#encoding:UTF-8%><%= template.anchor(@target, @text, @type) %>
543
- EOS
611
+ :invoke_result
544
612
  end
545
613
  end
546
614
 
@@ -571,10 +639,12 @@ end %>
571
639
  end
572
640
 
573
641
  class InlineCalloutTemplate < BaseTemplate
642
+ def result(node)
643
+ %(<co id="#{node.id}"/>)
644
+ end
645
+
574
646
  def template
575
- @template ||= @eruby.new <<-EOF
576
- <%#encoding:UTF-8%><co#{id}/>
577
- EOF
647
+ :invoke_result
578
648
  end
579
649
  end
580
650
 
@@ -588,10 +658,10 @@ if numterms > 2 %><indexterm>
588
658
  </indexterm>
589
659
  <% end %><%
590
660
  if numterms > 1 %><indexterm>
591
- <primary><%= terms[numterms - 2] %></primary><secondary><%= terms[numterms - 1] %></secondary>
661
+ <primary><%= terms[-2] %></primary><secondary><%= terms[-1] %></secondary>
592
662
  </indexterm>
593
663
  <% end %><indexterm>
594
- <primary><%= terms[numterms - 1] %></primary>
664
+ <primary><%= terms[-1] %></primary>
595
665
  </indexterm><% end %>
596
666
  EOS
597
667
  end