asciidoctor-dita-topic 1.0.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.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/dita-topic.rb +704 -0
  3. metadata +66 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a78953056690681fd5bd90e2ddc9bf86fc58a97e13ef88e3493aaccfd841af38
4
+ data.tar.gz: a6f0615ccc0706a2c70411596d7d6bf535530643548b45ca3647b9763e75c289
5
+ SHA512:
6
+ metadata.gz: e4844fa7069d23b72d084a398a1d9895e1ce34c8a2a888508d9b83aefefa36cf4c56d681a6b6ffdd5f5891f7223128f5806e73fdb94624228399726d085a9253
7
+ data.tar.gz: 47bf20454de4e0b2c4ad8386ac6a4f81d5d792c3ee7ff0b73b2b2fe1cba700a3cd93f65edce4ecf082f3ea2d0954aeada3a685213005de3e49bf95dc9920736c
data/lib/dita-topic.rb ADDED
@@ -0,0 +1,704 @@
1
+ # A custom AsciiDoc converter that generates individual DITA topics
2
+ # Copyright (C) 2024 Jaromir Hradilek
3
+
4
+ # MIT License
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining
7
+ # a copy of this software and associated documentation files (the "Soft-
8
+ # ware"), to deal in the Software without restriction, including without
9
+ # limitation the rights to use, copy, modify, merge, publish, distribute,
10
+ # sublicense, and/or sell copies of the Software, and to permit persons to
11
+ # whom the Software is furnished to do so, subject to the following condi-
12
+ # tions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included
15
+ # in all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18
+ # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABI-
19
+ # LITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
20
+ # SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
21
+ # OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22
+ # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
+ # OTHER DEALINGS IN THE SOFTWARE.
24
+
25
+ # frozen_string_literal: true
26
+
27
+ module Asciidoctor
28
+ class DitaConverter < Asciidoctor::Converter::Base
29
+ NAME = 'dita-topic'
30
+ register_for NAME
31
+
32
+ def initialize *args
33
+ super
34
+ outfilesuffix '.dita'
35
+ end
36
+
37
+ def convert_document node
38
+ # Check if the modular documentation content type is specified:
39
+ content_type = (node.attr? '_mod-docs-content-type') ? %( outputclass="#{(node.attr '_mod-docs-content-type').downcase}") : ''
40
+
41
+ # Return the XML output:
42
+ <<~EOF.chomp
43
+ <?xml version='1.0' encoding='utf-8' ?>
44
+ <!DOCTYPE topic PUBLIC "-//OASIS//DTD DITA Topic//EN" "topic.dtd">
45
+ <topic#{compose_id (node.id or node.attributes['docname'])}#{content_type}>
46
+ <title>#{node.doctitle}</title>
47
+ <body>
48
+ #{node.content}
49
+ </body>
50
+ </topic>
51
+ EOF
52
+ end
53
+
54
+ def convert_admonition node
55
+ # NOTE: Unlike admonitions in AsciiDoc, the <note> element in DITA
56
+ # cannot have its own <title>. Admonition titles are therefore not
57
+ # preserved.
58
+
59
+ # Issue a warning if the admonition has a title:
60
+ if node.title?
61
+ logger.warn "#{NAME}: Admonition title not supported in DITA: #{node.title}"
62
+ end
63
+
64
+ # Return the XML output:
65
+ <<~EOF.chomp
66
+ <note type="#{node.attr 'name'}">
67
+ #{node.content}
68
+ </note>
69
+ EOF
70
+ end
71
+
72
+ def convert_audio node
73
+ # Issue a warning if audio content is present:
74
+ logger.warn "#{NAME}: Audio macro not supported"
75
+ return ''
76
+ end
77
+
78
+ # FIXME: Figure out how to handle this along with convert_inline_callout.
79
+ # A definition list looks like a reasonable option.
80
+ def convert_colist node
81
+ # Issue a warning if a callout list is present:
82
+ logger.warn "#{NAME}: Callout list support not implemented"
83
+ return ''
84
+ end
85
+
86
+ # FIXME: Add support for a title.
87
+ def convert_dlist node
88
+ # Check if a different list style is set:
89
+ return compose_horizontal_dlist node if node.style == 'horizontal'
90
+ return compose_qanda_dlist node if node.style == 'qanda'
91
+
92
+ # Open the definition list:
93
+ result = ['<dl>']
94
+
95
+ # Process individual list items:
96
+ node.items.each do |terms, description|
97
+ # Open the definition entry:
98
+ result << %(<dlentry>)
99
+
100
+ # Process individual terms:
101
+ terms.each do |item|
102
+ result << %(<dt>#{item.text}</dt>)
103
+ end
104
+
105
+ # Check if the term description is specified:
106
+ if description
107
+ # Check if the description contains multiple block elements:
108
+ if description.blocks?
109
+ result << %(<dd>)
110
+ result << %(<p>#{description.text}</p>) if description.text?
111
+ result << description.content
112
+ result << %(</dd>)
113
+ else
114
+ result << %(<dd>#{description.text}</dd>)
115
+ end
116
+ end
117
+
118
+ # Close the definition entry:
119
+ result << %(</dlentry>)
120
+ end
121
+
122
+ # Close the definition list:
123
+ result << '</dl>'
124
+
125
+ # Return the XML output:
126
+ result.join LF
127
+ end
128
+
129
+ def convert_example node
130
+ <<~EOF.chomp
131
+ <example#{compose_id node.id}>
132
+ #{compose_title node.title}#{node.content}
133
+ </example>
134
+ EOF
135
+ end
136
+
137
+ def convert_floating_title node
138
+ compose_floating_title node.title, node.level
139
+ end
140
+
141
+ # FIXME: Add support for additional attributes.
142
+ def convert_image node
143
+ # Check if the image has a title specified:
144
+ if node.title?
145
+ <<~EOF.chomp
146
+ <fig>
147
+ <title>#{node.title}</title>
148
+ <image href="#{node.image_uri(node.attr 'target')}" placement="break">
149
+ <alt>#{node.alt}</alt>
150
+ </image>
151
+ </fig>
152
+ EOF
153
+ else
154
+ <<~EOF.chomp
155
+ <image href="#{node.image_uri(node.attr 'target')}" placement="break">
156
+ <alt>#{node.alt}</alt>
157
+ </image>
158
+ EOF
159
+ end
160
+ end
161
+
162
+ def convert_inline_anchor node
163
+ # Determine the type of the anchor:
164
+ case node.type
165
+ when :link
166
+ # Compose an external link:
167
+ %(<xref href="#{node.target}" scope="external">#{node.text}</xref>)
168
+ when :xref
169
+ # NOTE: While AsciiDoc is happy to reference an ID that is not
170
+ # defined in the same AsciiDoc file, DITA requires the topic ID as
171
+ # part of the reference. As this script does not have direct access
172
+ # to the topic IDs of external files and to avoid performance issues
173
+ # I do not want to process them from this script, I choose to issue a
174
+ # warning so that the user can resolve the problem.
175
+
176
+ # Determine whether the cross reference links to a file path or an ID:
177
+ if (path = node.attributes['path'])
178
+ # Issue a warning if the cross reference includes an ID:
179
+ logger.warn "#{NAME}: Possible invalid reference: #{node.target}" if node.target.include? '#'
180
+
181
+ # Compose a cross reference:
182
+ %(<xref href="#{node.target}">#{node.text || path}</xref>)
183
+ else
184
+ # Issue a warning as the cross reference is unlikely to work:
185
+ logger.warn "#{NAME}: Possible invalid reference: #{node.target}"
186
+
187
+ # Compose the cross reference:
188
+ node.text ? %(<xref href="#{node.target}">#{node.text}</xref>) : %(<xref href="#{node.target}" />)
189
+ end
190
+ when :ref
191
+ # NOTE: DITA does not have a dedicated element for inline anchors or
192
+ # a direct equivalent of the <span> element from HTML. The solution
193
+ # below is the least invasive way I could find to achieve the
194
+ # equivalent behavior.
195
+
196
+ # Compose an inline anchor:
197
+ %(<i id="#{node.id}" />)
198
+ when :bibref
199
+ # NOTE: DITA does not have a dedicated element for inline anchors or
200
+ # a direct equivalent of the <span> element from HTML. The solution
201
+ # below is the least invasive way I could find to achieve the
202
+ # equivalent behavior.
203
+
204
+ # Compose a bibliographic reference:
205
+ %(<i id="#{node.id}" />[#{node.reftext || node.id}])
206
+ else
207
+ # Issue a warning if an unknown anchor type is present:
208
+ logger.warn "#{NAME}: Unknown anchor type: #{node.type}"
209
+ ''
210
+ end
211
+ end
212
+
213
+ def convert_inline_break node
214
+ # NOTE: Unlike AsciiDoc, DITA does not support inline line breaks.
215
+
216
+ # Issue a warning if an inline line break is present:
217
+ logger.warn "#{NAME}: Inline breaks not supported in DITA"
218
+
219
+ # Return the XML output:
220
+ %(#{node.text}<!-- break -->)
221
+ end
222
+
223
+ def convert_inline_button node
224
+ %(<uicontrol outputclass="button">#{node.text}</uicontrol>)
225
+ end
226
+
227
+ def convert_inline_callout node
228
+ # Issue a warning if an inline callout is present:
229
+ logger.warn "#{NAME}: Inline callout support not implemented"
230
+ return ''
231
+ end
232
+
233
+ # FIXME: Add support for footnoteref equivalent.
234
+ def convert_inline_footnote node
235
+ %(<fn>#{node.text}</fn>)
236
+ end
237
+
238
+ # FIXME: Add support for additional attributes.
239
+ def convert_inline_image node
240
+ %(<image href="#{node.image_uri node.target}" placement="inline"><alt>#{node.alt}</alt></image>)
241
+ end
242
+
243
+ def convert_inline_indexterm node
244
+ # Issue a warning if an inline index term is present:
245
+ logger.warn "#{NAME}: Inline index terms not implemented"
246
+ return ''
247
+ end
248
+
249
+ # FIXME: Investigate if there is an equivalent of <span> in DITA that
250
+ # would group individual <uicontrol> elements together.
251
+ def convert_inline_kbd node
252
+ # Check if there is more than one key:
253
+ if (keys = node.attr 'keys').size == 1
254
+ %(<uicontrol outputclass="key">#{keys[0]}</uicontrol>)
255
+ else
256
+ %(<uicontrol outputclass="key">#{keys.join '</uicontrol>+<uicontrol outputclass="key">'}</uicontrol>)
257
+ end
258
+ end
259
+
260
+ def convert_inline_menu node
261
+ # Compose the markup for the menu:
262
+ menu = %(<uicontrol>#{node.attr 'menu'}</uicontrol>)
263
+
264
+ # Compose the markup for possible submenus:
265
+ submenus = (not (node.attr 'submenus').empty?) ? %(<uicontrol>#{(node.attr 'submenus').join '</uicontrol><uicontrol>'}</uicontrol>) : ''
266
+
267
+ # Compose the markup for the menu item:
268
+ menuitem = (node.attr 'menuitem') ? %(<uicontrol>#{node.attr 'menuitem'}</uicontrol>) : ''
269
+
270
+ # Return the XML output:
271
+ %(<menucascade>#{menu}#{submenus}#{menuitem}</menucascade>)
272
+ end
273
+
274
+ def convert_inline_quoted node
275
+ # Determine the inline markup type:
276
+ case node.type
277
+ when :emphasis
278
+ %(<i>#{node.text}</i>)
279
+ when :strong
280
+ %(<b>#{node.text}</b>)
281
+ when :monospaced
282
+ %(<tt>#{node.text}</tt>)
283
+ when :superscript
284
+ %(<sup>#{node.text}</sup>)
285
+ when :subscript
286
+ %(<sub>#{node.text}</sub>)
287
+ when :double
288
+ %(&#8220;#{node.text}&#8221;)
289
+ when :single
290
+ %(&#8216;#{node.text}&#8217;)
291
+ else
292
+ node.text
293
+ end
294
+ end
295
+
296
+ def convert_listing node
297
+ # Check the listing style:
298
+ if node.style == 'source'
299
+ # Check whether the source language is defined:
300
+ language = (node.attributes.key? 'language') ? %( outputclass="language-#{node.attributes['language']}") : ''
301
+
302
+ # Return the XML output:
303
+ <<~EOF.chomp
304
+ <codeblock#{language}>
305
+ #{node.content}
306
+ </codeblock>
307
+ EOF
308
+ else
309
+ # Return the XML output:
310
+ <<~EOF.chomp
311
+ <screen>
312
+ #{node.content}
313
+ </screen>
314
+ EOF
315
+ end
316
+ end
317
+
318
+ def convert_literal node
319
+ <<~EOF.chomp
320
+ <pre>
321
+ #{node.content}
322
+ </pre>
323
+ EOF
324
+ end
325
+
326
+ # FIXME: Add support for titles.
327
+ def convert_olist node
328
+ # Open the ordered list:
329
+ result = ['<ol>']
330
+
331
+ # Process individual list items:
332
+ node.items.each do |item|
333
+ # Check if the list item contains multiple block elements:
334
+ if item.blocks?
335
+ result << %(<li>)
336
+ result << %(<p>#{item.text}</p>)
337
+ result << item.content
338
+ result << %(</li>)
339
+ else
340
+ result << %(<li>#{item.text}</li>)
341
+ end
342
+ end
343
+
344
+ # Close the ordered list:
345
+ result << '</ol>'
346
+
347
+ # Return the XML output:
348
+ result.join LF
349
+ end
350
+
351
+ # FIXME: This is not the top priority.
352
+ def convert_open node
353
+ ''
354
+ end
355
+
356
+ def convert_page_break node
357
+ # NOTE: Unlike AsciiDoc, DITA does not support page breaks.
358
+
359
+ # Issue a warning if a page break is present:
360
+ logger.warn "#{NAME}: Page breaks not supported in DITA"
361
+
362
+ # Return the XML output:
363
+ %(<p outputclass="page-break"></p>)
364
+ end
365
+
366
+ def convert_paragraph node
367
+ # Check if the paragraph has a title assigned:
368
+ if node.title?
369
+ <<~EOF.chomp
370
+ <div outputclass="paragraph">
371
+ #{compose_floating_title node.title}<p>#{node.content}</p>
372
+ </div>
373
+ EOF
374
+ else
375
+ %(<p>#{node.content}</p>)
376
+ end
377
+ end
378
+
379
+ def convert_preamble node
380
+ node.content
381
+ end
382
+
383
+ def convert_quote node
384
+ # Check if the author is defined:
385
+ author = (node.attr? 'attribution') ? %(\n<p>&#8212; #{node.attr 'attribution'}</p>) : ''
386
+
387
+ # Check if the citation source is defined:
388
+ source = (node.attr? 'citetitle') ? %(\n<cite>#{node.attr 'citetitle'}</cite>) : ''
389
+
390
+ # Check if the content contains multiple block elements:
391
+ if node.content_model == :compound
392
+ <<~EOF.chomp
393
+ <lq>
394
+ #{compose_floating_title node.title}#{node.content}#{author}#{source}
395
+ </lq>
396
+ EOF
397
+ else
398
+ <<~EOF.chomp
399
+ <lq>
400
+ #{compose_floating_title node.title}<p>#{node.content}</p>#{author}#{source}
401
+ </lq>
402
+ EOF
403
+ end
404
+ end
405
+
406
+ def convert_section node
407
+ # NOTE: Unlike sections in AsciiDoc, the <section> element in DITA
408
+ # cannot be nested. Consequently, converting AsciiDoc files that do
409
+ # contain nested subsections will result in invalid markup.
410
+ #
411
+ # I explored the possibility to use the <topic> element instead as it
412
+ # can be nested, but that presents a problem with closing the <body>
413
+ # element of the parent <topic>. As only a very small number of
414
+ # AsciiDoc modules contain nested subsections, I chose the simple
415
+ # markup.
416
+
417
+ # Issue a warning if there are nested sections:
418
+ logger.warn "#{NAME}: Nesting of sections not supported in DITA" if node.level > 1
419
+
420
+ # Return the XML output:
421
+ <<~EOF.chomp
422
+ <section#{compose_id node.id}>
423
+ <title>#{node.title}</title>
424
+ #{node.content}
425
+ </section>
426
+ EOF
427
+ end
428
+
429
+ def convert_sidebar node
430
+ # NOTE: Unlike AsciiDoc, DITA does not provide markup for a sidebar. As
431
+ # a workaround, I decided to use a div with the outputclass attribute.
432
+
433
+ # Check if the content contains multiple block elements:
434
+ if node.content_model == :compound
435
+ <<~EOF.chomp
436
+ <div outputclass="sidebar">
437
+ #{compose_floating_title node.title}#{node.content}
438
+ </div>
439
+ EOF
440
+ else
441
+ <<~EOF.chomp
442
+ <div outputclass="sidebar">
443
+ #{compose_floating_title node.title}<p>#{node.content}</p>
444
+ </div>
445
+ EOF
446
+ end
447
+ end
448
+
449
+ def convert_stem node
450
+ # Issue a warning if a STEM content is present:
451
+ logger.warn "#{NAME}: STEM support not implemented"
452
+ return ''
453
+ end
454
+
455
+ def convert_table node
456
+ # Open the table:
457
+ result = ['<table>']
458
+
459
+ # Check if the title is specified:
460
+ result << %(<title>#{node.title}</title>) if node.title?
461
+
462
+ # Define the table properties and open the tgroup:
463
+ result << %(<tgroup cols="#{node.attr 'colcount'}">)
464
+
465
+ # Define column properties:
466
+ node.columns.each do |column|
467
+ result << %(<colspec colname="col_#{column.attr 'colnumber'}" colwidth="#{column.attr ((node.attr? 'width') ? 'colabswidth' : 'colpcwidth')}*"/>)
468
+ end
469
+
470
+ # Process each table section (header, body, and footer):
471
+ node.rows.to_h.each do |type, rows|
472
+ # Skip empty sections:
473
+ next if rows.empty?
474
+
475
+ # Issue a warning if a table footer is present:
476
+ if type == :foot
477
+ logger.warn "#{NAME}: Table footers not supported in DITA"
478
+ next
479
+ end
480
+
481
+ # Open the section:
482
+ result << %(<t#{type}>)
483
+
484
+ # Process each row:
485
+ rows.each do |row|
486
+ # Open the row:
487
+ result <<%(<row>)
488
+
489
+ # Process each cell:
490
+ row.each do |cell|
491
+ # Check if the cell spans multiple columns:
492
+ colspan = cell.colspan ? %( namest="col_#{colnum = cell.column.attr 'colnumber'}" nameend="col_#{column + cell.colspan - 1}") : ''
493
+
494
+ # Check if the cell spans multiple rows:
495
+ rowspan = cell.rowspan ? %( morerows="#{cell.rowspan - 1}") : ''
496
+
497
+ # Compose the entry tag:
498
+ entry_tag = %(entry#{colspan}#{rowspan})
499
+
500
+ # Determine the formatting of the entry:
501
+ if type == :head
502
+ result << %(<#{entry_tag}>#{cell.text}</entry>)
503
+ next
504
+ end
505
+ case cell.style
506
+ when :asciidoc
507
+ result << %(<#{entry_tag}>#{cell.content}</entry>)
508
+ when :literal
509
+ result << %(<#{entry_tag}><pre>#{cell.text}</pre></entry>)
510
+ else
511
+ result << %(<#{entry_tag}>)
512
+ cell.content.each do |line|
513
+ result << %(<p>#{line}</p>)
514
+ end
515
+ result << %(</entry>)
516
+ end
517
+ end
518
+
519
+ # Close the row:
520
+ result <<%(</row>)
521
+ end
522
+
523
+ # Close the section:
524
+ result << %(</t#{type}>)
525
+ end
526
+
527
+ # Close the table:
528
+ result << %(</tgroup>)
529
+ result << %(</table>)
530
+
531
+ # Return the XML output:
532
+ result.join LF
533
+ end
534
+
535
+ def convert_thematic_break node
536
+ # NOTE: Unlike AsciiDoc, DITA does not support thematic breaks.
537
+
538
+ # Issue a warning if a thematic break is present:
539
+ logger.warn "#{NAME}: Thematic breaks not supported in DITA"
540
+
541
+ # Return the XML output:
542
+ %(<p outputclass="thematic-break"></p>)
543
+ end
544
+
545
+ # FIXME: Add support for titles.
546
+ def convert_ulist node
547
+ # Open the unordered list:
548
+ result = ['<ul>']
549
+
550
+ # Process individual list items:
551
+ node.items.each do |item|
552
+ # Check if the list item is part of a checklist:
553
+ unless item.attr? 'checkbox'
554
+ check_box = ''
555
+ else
556
+ check_box = (item.attr? 'checked') ? '&#10003; ' : '&#10063; '
557
+ end
558
+
559
+ # Check if the list item contains multiple block elements:
560
+ if item.blocks?
561
+ result << %(<li>)
562
+ result << %(<p>#{check_box}#{item.text}</p>)
563
+ result << item.content
564
+ result << %(</li>)
565
+ else
566
+ result << %(<li>#{check_box}#{item.text}</li>)
567
+ end
568
+ end
569
+
570
+ # Close the unordered list:
571
+ result << '</ul>'
572
+
573
+ # Returned the XML output:
574
+ result.join LF
575
+ end
576
+
577
+ def convert_verse node
578
+ # Check if the author is defined:
579
+ author = (node.attr? 'attribution') ? %(\n&#8212; #{node.attr 'attribution'}) : ''
580
+
581
+ # Check if the citation source is defined:
582
+ source = (node.attr? 'citetitle') ? %(\n<cite>#{node.attr 'citetitle'}</cite>) : ''
583
+
584
+ # Return the XML output:
585
+ <<~EOF.chomp
586
+ <lines>
587
+ #{node.content}#{author}#{source}
588
+ </lines>
589
+ EOF
590
+ end
591
+
592
+ def convert_video node
593
+ # Issue a warning if video content is present:
594
+ logger.warn "#{NAME}: Video macro not supported"
595
+ return ''
596
+ end
597
+
598
+ def compose_qanda_dlist node
599
+ # Open the ordered list:
600
+ result = ['<ol>']
601
+
602
+ # Process individual list items:
603
+ node.items.each do |terms, description|
604
+ # Open the list item:
605
+ result << %(<li>)
606
+
607
+ # Process individual terms:
608
+ terms.each do |item|
609
+ result << %(<p outputclass="question"><i>#{item.text}</i></p>)
610
+ end
611
+
612
+ # Check if the term description is specified:
613
+ if description
614
+ result << %(<p>#{description.text}</p>)
615
+ result << description.content if description.blocks?
616
+ end
617
+
618
+ # Close the list item:
619
+ result << %(</li>)
620
+ end
621
+
622
+ # Close the ordered list:
623
+ result << '</ol>'
624
+
625
+ # Return the XML output:
626
+ result.join LF
627
+ end
628
+
629
+ def compose_horizontal_dlist node
630
+ # Open the table:
631
+ result = ['<table>']
632
+
633
+ # Define the table properties and open the tgroup:
634
+ result << %(<tgroup cols="2">)
635
+ result << %(<colspec colwidth="#{node.attr 'labelwidth', 15}*" />)
636
+ result << %(<colspec colwidth="#{node.attr 'itemwidth', 85}*" />)
637
+
638
+ # Open the table body:
639
+ result << %(<tbody>)
640
+
641
+ # Process individual list items:
642
+ node.items.each do |terms, description|
643
+ # Open the table row:
644
+ result << %(<row>)
645
+
646
+ # Check the number of terms to process:
647
+ if terms.count == 1
648
+ result << %(<entry><b>#{terms[0].text}</b></entry>)
649
+ else
650
+ # Process individual terms:
651
+ result << %(<entry>)
652
+ terms.each do |item|
653
+ result << %(<p><b>#{item.text}</b></p>)
654
+ end
655
+ result << %(</entry>)
656
+ end
657
+
658
+ # Check if the term description is specified:
659
+ if description
660
+ # Check if the description contains multiple block elements:
661
+ if description.blocks?
662
+ result << %(<entry>)
663
+ result << %(<p>#{description.text}</p>) if description.text?
664
+ result << description.content
665
+ result << %(</entry>)
666
+ else
667
+ result << %(<entry>#{description.text}</entry>) if description.text?
668
+ end
669
+ end
670
+
671
+ # Close the table row:
672
+ result << %(</row>)
673
+ end
674
+
675
+ # Close the table:
676
+ result << %(</tbody>)
677
+ result << %(</tgroup>)
678
+ result << %(</table>)
679
+
680
+ # Return the XML output:
681
+ result.join LF
682
+ end
683
+
684
+ def compose_floating_title title, section_level=false
685
+ # NOTE: Unlike AsciiDoc, DITA does not support floating titles or
686
+ # titles assigned to certain block elements. As a workaround, I decided
687
+ # to use a paragraph with the outputclass attribute.
688
+
689
+ # Check whether the section level is defined:
690
+ level = section_level ? %( sect#{section_level}) : ''
691
+
692
+ # Return the XML output:
693
+ title ? %(<p outputclass="title#{level}"><b>#{title}</b></p>\n) : ''
694
+ end
695
+
696
+ def compose_id id
697
+ id ? %( id="#{id}") : ''
698
+ end
699
+
700
+ def compose_title title
701
+ title ? %(<title>#{title}</title>\n) : ''
702
+ end
703
+ end
704
+ end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: asciidoctor-dita-topic
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jaromir Hradilek
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-06-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: asciidoctor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 2.0.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '2.0'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 2.0.0
33
+ description: An extension for AsciiDoctor that converts a single AsciiDoc file to
34
+ a DITA topic.
35
+ email: jhradilek@gmail.com
36
+ executables: []
37
+ extensions: []
38
+ extra_rdoc_files: []
39
+ files:
40
+ - lib/dita-topic.rb
41
+ homepage: https://github.com/jhradilek/asciidoctor-dita-topic
42
+ licenses:
43
+ - MIT
44
+ metadata:
45
+ homepage_uri: https://github.com/jhradilek/asciidoctor-dita-topic
46
+ bug_tracker_uri: https://github.com/jhradilek/asciidoctor-dita-topic/issues
47
+ post_install_message:
48
+ rdoc_options: []
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ requirements: []
62
+ rubygems_version: 3.5.9
63
+ signing_key:
64
+ specification_version: 4
65
+ summary: A custom AsciiDoc converter that generates individual DITA topics
66
+ test_files: []