coradoc-adoc 2.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.
Files changed (217) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/lib/coradoc/asciidoc/model/admonition.rb +37 -0
  4. data/lib/coradoc/asciidoc/model/anchorable.rb +64 -0
  5. data/lib/coradoc/asciidoc/model/attached.rb +26 -0
  6. data/lib/coradoc/asciidoc/model/attribute.rb +22 -0
  7. data/lib/coradoc/asciidoc/model/attribute_list/matchers.rb +45 -0
  8. data/lib/coradoc/asciidoc/model/attribute_list.rb +230 -0
  9. data/lib/coradoc/asciidoc/model/attribute_list_attribute.rb +11 -0
  10. data/lib/coradoc/asciidoc/model/audio.rb +44 -0
  11. data/lib/coradoc/asciidoc/model/author.rb +36 -0
  12. data/lib/coradoc/asciidoc/model/base.rb +141 -0
  13. data/lib/coradoc/asciidoc/model/bibliography.rb +37 -0
  14. data/lib/coradoc/asciidoc/model/bibliography_entry.rb +38 -0
  15. data/lib/coradoc/asciidoc/model/block/core.rb +139 -0
  16. data/lib/coradoc/asciidoc/model/block/example.rb +14 -0
  17. data/lib/coradoc/asciidoc/model/block/listing.rb +14 -0
  18. data/lib/coradoc/asciidoc/model/block/literal.rb +14 -0
  19. data/lib/coradoc/asciidoc/model/block/open.rb +14 -0
  20. data/lib/coradoc/asciidoc/model/block/pass.rb +14 -0
  21. data/lib/coradoc/asciidoc/model/block/quote.rb +14 -0
  22. data/lib/coradoc/asciidoc/model/block/reviewer_comment.rb +14 -0
  23. data/lib/coradoc/asciidoc/model/block/side.rb +14 -0
  24. data/lib/coradoc/asciidoc/model/block/source_code.rb +14 -0
  25. data/lib/coradoc/asciidoc/model/block.rb +21 -0
  26. data/lib/coradoc/asciidoc/model/break.rb +33 -0
  27. data/lib/coradoc/asciidoc/model/comment_block.rb +33 -0
  28. data/lib/coradoc/asciidoc/model/comment_line.rb +30 -0
  29. data/lib/coradoc/asciidoc/model/content_list.rb +334 -0
  30. data/lib/coradoc/asciidoc/model/document.rb +197 -0
  31. data/lib/coradoc/asciidoc/model/document_attributes.rb +43 -0
  32. data/lib/coradoc/asciidoc/model/glossaries.rb +11 -0
  33. data/lib/coradoc/asciidoc/model/header.rb +57 -0
  34. data/lib/coradoc/asciidoc/model/highlight.rb +11 -0
  35. data/lib/coradoc/asciidoc/model/image/block_image/attribute_list.rb +23 -0
  36. data/lib/coradoc/asciidoc/model/image/block_image.rb +25 -0
  37. data/lib/coradoc/asciidoc/model/image/core/attribute_list.rb +43 -0
  38. data/lib/coradoc/asciidoc/model/image/core.rb +72 -0
  39. data/lib/coradoc/asciidoc/model/image/inline_image.rb +17 -0
  40. data/lib/coradoc/asciidoc/model/image.rb +14 -0
  41. data/lib/coradoc/asciidoc/model/include.rb +66 -0
  42. data/lib/coradoc/asciidoc/model/inline/anchor.rb +41 -0
  43. data/lib/coradoc/asciidoc/model/inline/attribute_reference.rb +25 -0
  44. data/lib/coradoc/asciidoc/model/inline/base.rb +15 -0
  45. data/lib/coradoc/asciidoc/model/inline/bold.rb +38 -0
  46. data/lib/coradoc/asciidoc/model/inline/cross_reference.rb +29 -0
  47. data/lib/coradoc/asciidoc/model/inline/cross_reference_arg.rb +15 -0
  48. data/lib/coradoc/asciidoc/model/inline/footnote.rb +34 -0
  49. data/lib/coradoc/asciidoc/model/inline/hard_line_break.rb +24 -0
  50. data/lib/coradoc/asciidoc/model/inline/highlight.rb +36 -0
  51. data/lib/coradoc/asciidoc/model/inline/italic.rb +38 -0
  52. data/lib/coradoc/asciidoc/model/inline/link.rb +46 -0
  53. data/lib/coradoc/asciidoc/model/inline/monospace.rb +39 -0
  54. data/lib/coradoc/asciidoc/model/inline/quotation.rb +25 -0
  55. data/lib/coradoc/asciidoc/model/inline/small.rb +25 -0
  56. data/lib/coradoc/asciidoc/model/inline/span.rb +38 -0
  57. data/lib/coradoc/asciidoc/model/inline/stem.rb +24 -0
  58. data/lib/coradoc/asciidoc/model/inline/strikethrough.rb +39 -0
  59. data/lib/coradoc/asciidoc/model/inline/subscript.rb +33 -0
  60. data/lib/coradoc/asciidoc/model/inline/superscript.rb +33 -0
  61. data/lib/coradoc/asciidoc/model/inline/underline.rb +25 -0
  62. data/lib/coradoc/asciidoc/model/inline.rb +31 -0
  63. data/lib/coradoc/asciidoc/model/line_break.rb +11 -0
  64. data/lib/coradoc/asciidoc/model/list/core.rb +61 -0
  65. data/lib/coradoc/asciidoc/model/list/definition.rb +27 -0
  66. data/lib/coradoc/asciidoc/model/list/definition_item.rb +43 -0
  67. data/lib/coradoc/asciidoc/model/list/item.rb +72 -0
  68. data/lib/coradoc/asciidoc/model/list/nestable.rb +14 -0
  69. data/lib/coradoc/asciidoc/model/list/ordered.rb +34 -0
  70. data/lib/coradoc/asciidoc/model/list/unordered.rb +34 -0
  71. data/lib/coradoc/asciidoc/model/list.rb +29 -0
  72. data/lib/coradoc/asciidoc/model/named_attribute.rb +12 -0
  73. data/lib/coradoc/asciidoc/model/paragraph.rb +59 -0
  74. data/lib/coradoc/asciidoc/model/rejected_positional_attribute.rb +12 -0
  75. data/lib/coradoc/asciidoc/model/resolvable.rb +71 -0
  76. data/lib/coradoc/asciidoc/model/resolver.rb +430 -0
  77. data/lib/coradoc/asciidoc/model/reviewer_note.rb +54 -0
  78. data/lib/coradoc/asciidoc/model/revision.rb +47 -0
  79. data/lib/coradoc/asciidoc/model/section.rb +109 -0
  80. data/lib/coradoc/asciidoc/model/serialization/asciidoc_adapter.rb +28 -0
  81. data/lib/coradoc/asciidoc/model/serialization/asciidoc_mapping.rb +42 -0
  82. data/lib/coradoc/asciidoc/model/serialization/asciidoc_mapping_rule.rb +41 -0
  83. data/lib/coradoc/asciidoc/model/serialization/asciidoc_transform.rb +211 -0
  84. data/lib/coradoc/asciidoc/model/serialization/errors.rb +57 -0
  85. data/lib/coradoc/asciidoc/model/serialization.rb +39 -0
  86. data/lib/coradoc/asciidoc/model/spacing.rb +282 -0
  87. data/lib/coradoc/asciidoc/model/table.rb +44 -0
  88. data/lib/coradoc/asciidoc/model/table_cell.rb +122 -0
  89. data/lib/coradoc/asciidoc/model/table_row.rb +26 -0
  90. data/lib/coradoc/asciidoc/model/tag.rb +36 -0
  91. data/lib/coradoc/asciidoc/model/term.rb +48 -0
  92. data/lib/coradoc/asciidoc/model/text_element.rb +66 -0
  93. data/lib/coradoc/asciidoc/model/title.rb +85 -0
  94. data/lib/coradoc/asciidoc/model/video/attribute_list.rb +43 -0
  95. data/lib/coradoc/asciidoc/model/video.rb +49 -0
  96. data/lib/coradoc/asciidoc/model.rb +75 -0
  97. data/lib/coradoc/asciidoc/parse_error.rb +161 -0
  98. data/lib/coradoc/asciidoc/parser/admonition.rb +26 -0
  99. data/lib/coradoc/asciidoc/parser/attribute_list.rb +110 -0
  100. data/lib/coradoc/asciidoc/parser/base.rb +159 -0
  101. data/lib/coradoc/asciidoc/parser/bibliography.rb +31 -0
  102. data/lib/coradoc/asciidoc/parser/block.rb +186 -0
  103. data/lib/coradoc/asciidoc/parser/block_assembler.rb +183 -0
  104. data/lib/coradoc/asciidoc/parser/cache.rb +155 -0
  105. data/lib/coradoc/asciidoc/parser/citation.rb +32 -0
  106. data/lib/coradoc/asciidoc/parser/content.rb +76 -0
  107. data/lib/coradoc/asciidoc/parser/document_attributes.rb +27 -0
  108. data/lib/coradoc/asciidoc/parser/fix_files.rb +76 -0
  109. data/lib/coradoc/asciidoc/parser/header.rb +31 -0
  110. data/lib/coradoc/asciidoc/parser/inline.rb +199 -0
  111. data/lib/coradoc/asciidoc/parser/list.rb +130 -0
  112. data/lib/coradoc/asciidoc/parser/metadata_detector.rb +164 -0
  113. data/lib/coradoc/asciidoc/parser/paragraph.rb +64 -0
  114. data/lib/coradoc/asciidoc/parser/section.rb +62 -0
  115. data/lib/coradoc/asciidoc/parser/stem.rb +19 -0
  116. data/lib/coradoc/asciidoc/parser/table.rb +166 -0
  117. data/lib/coradoc/asciidoc/parser/term.rb +70 -0
  118. data/lib/coradoc/asciidoc/parser/text.rb +156 -0
  119. data/lib/coradoc/asciidoc/parser.rb +10 -0
  120. data/lib/coradoc/asciidoc/serializer/adoc_serializer.rb +86 -0
  121. data/lib/coradoc/asciidoc/serializer/element_registry.rb +95 -0
  122. data/lib/coradoc/asciidoc/serializer/fallback_serializer.rb +21 -0
  123. data/lib/coradoc/asciidoc/serializer/formatter.rb +144 -0
  124. data/lib/coradoc/asciidoc/serializer/registrations.rb +108 -0
  125. data/lib/coradoc/asciidoc/serializer/serialization_context.rb +238 -0
  126. data/lib/coradoc/asciidoc/serializer/serializers/admonition.rb +19 -0
  127. data/lib/coradoc/asciidoc/serializer/serializers/attribute.rb +23 -0
  128. data/lib/coradoc/asciidoc/serializer/serializers/attribute_list.rb +40 -0
  129. data/lib/coradoc/asciidoc/serializer/serializers/attribute_list_attribute.rb +18 -0
  130. data/lib/coradoc/asciidoc/serializer/serializers/audio.rb +33 -0
  131. data/lib/coradoc/asciidoc/serializer/serializers/author.rb +20 -0
  132. data/lib/coradoc/asciidoc/serializer/serializers/base.rb +152 -0
  133. data/lib/coradoc/asciidoc/serializer/serializers/bibliography.rb +35 -0
  134. data/lib/coradoc/asciidoc/serializer/serializers/bibliography_entry.rb +24 -0
  135. data/lib/coradoc/asciidoc/serializer/serializers/block/core.rb +70 -0
  136. data/lib/coradoc/asciidoc/serializer/serializers/block/example.rb +17 -0
  137. data/lib/coradoc/asciidoc/serializer/serializers/block/listing.rb +22 -0
  138. data/lib/coradoc/asciidoc/serializer/serializers/block/literal.rb +17 -0
  139. data/lib/coradoc/asciidoc/serializer/serializers/block/open.rb +22 -0
  140. data/lib/coradoc/asciidoc/serializer/serializers/block/pass.rb +17 -0
  141. data/lib/coradoc/asciidoc/serializer/serializers/block/quote.rb +17 -0
  142. data/lib/coradoc/asciidoc/serializer/serializers/block/reviewer_comment.rb +17 -0
  143. data/lib/coradoc/asciidoc/serializer/serializers/block/side.rb +22 -0
  144. data/lib/coradoc/asciidoc/serializer/serializers/block/source_code.rb +22 -0
  145. data/lib/coradoc/asciidoc/serializer/serializers/block.rb +23 -0
  146. data/lib/coradoc/asciidoc/serializer/serializers/break.rb +18 -0
  147. data/lib/coradoc/asciidoc/serializer/serializers/comment_block.rb +22 -0
  148. data/lib/coradoc/asciidoc/serializer/serializers/comment_line.rb +22 -0
  149. data/lib/coradoc/asciidoc/serializer/serializers/document.rb +65 -0
  150. data/lib/coradoc/asciidoc/serializer/serializers/document_attributes.rb +21 -0
  151. data/lib/coradoc/asciidoc/serializer/serializers/header.rb +24 -0
  152. data/lib/coradoc/asciidoc/serializer/serializers/highlight.rb +23 -0
  153. data/lib/coradoc/asciidoc/serializer/serializers/image/core.rb +30 -0
  154. data/lib/coradoc/asciidoc/serializer/serializers/image.rb +14 -0
  155. data/lib/coradoc/asciidoc/serializer/serializers/include.rb +19 -0
  156. data/lib/coradoc/asciidoc/serializer/serializers/inline/anchor.rb +20 -0
  157. data/lib/coradoc/asciidoc/serializer/serializers/inline/attribute_reference.rb +20 -0
  158. data/lib/coradoc/asciidoc/serializer/serializers/inline/bold.rb +26 -0
  159. data/lib/coradoc/asciidoc/serializer/serializers/inline/cross_reference.rb +30 -0
  160. data/lib/coradoc/asciidoc/serializer/serializers/inline/cross_reference_arg.rb +20 -0
  161. data/lib/coradoc/asciidoc/serializer/serializers/inline/footnote.rb +24 -0
  162. data/lib/coradoc/asciidoc/serializer/serializers/inline/hard_line_break.rb +20 -0
  163. data/lib/coradoc/asciidoc/serializer/serializers/inline/highlight.rb +26 -0
  164. data/lib/coradoc/asciidoc/serializer/serializers/inline/italic.rb +26 -0
  165. data/lib/coradoc/asciidoc/serializer/serializers/inline/link.rb +38 -0
  166. data/lib/coradoc/asciidoc/serializer/serializers/inline/monospace.rb +26 -0
  167. data/lib/coradoc/asciidoc/serializer/serializers/inline/quotation.rb +21 -0
  168. data/lib/coradoc/asciidoc/serializer/serializers/inline/small.rb +20 -0
  169. data/lib/coradoc/asciidoc/serializer/serializers/inline/span.rb +35 -0
  170. data/lib/coradoc/asciidoc/serializer/serializers/inline/stem.rb +23 -0
  171. data/lib/coradoc/asciidoc/serializer/serializers/inline/strikethrough.rb +29 -0
  172. data/lib/coradoc/asciidoc/serializer/serializers/inline/subscript.rb +29 -0
  173. data/lib/coradoc/asciidoc/serializer/serializers/inline/superscript.rb +26 -0
  174. data/lib/coradoc/asciidoc/serializer/serializers/inline/underline.rb +20 -0
  175. data/lib/coradoc/asciidoc/serializer/serializers/inline.rb +32 -0
  176. data/lib/coradoc/asciidoc/serializer/serializers/line_break.rb +18 -0
  177. data/lib/coradoc/asciidoc/serializer/serializers/list/core.rb +47 -0
  178. data/lib/coradoc/asciidoc/serializer/serializers/list/definition.rb +35 -0
  179. data/lib/coradoc/asciidoc/serializer/serializers/list/definition_item.rb +38 -0
  180. data/lib/coradoc/asciidoc/serializer/serializers/list/item.rb +120 -0
  181. data/lib/coradoc/asciidoc/serializer/serializers/list/ordered.rb +24 -0
  182. data/lib/coradoc/asciidoc/serializer/serializers/list/unordered.rb +29 -0
  183. data/lib/coradoc/asciidoc/serializer/serializers/list.rb +19 -0
  184. data/lib/coradoc/asciidoc/serializer/serializers/named_attribute.rb +22 -0
  185. data/lib/coradoc/asciidoc/serializer/serializers/paragraph.rb +65 -0
  186. data/lib/coradoc/asciidoc/serializer/serializers/reviewer_note.rb +28 -0
  187. data/lib/coradoc/asciidoc/serializer/serializers/revision.rb +26 -0
  188. data/lib/coradoc/asciidoc/serializer/serializers/section.rb +37 -0
  189. data/lib/coradoc/asciidoc/serializer/serializers/table.rb +24 -0
  190. data/lib/coradoc/asciidoc/serializer/serializers/table_cell.rb +75 -0
  191. data/lib/coradoc/asciidoc/serializer/serializers/table_row.rb +24 -0
  192. data/lib/coradoc/asciidoc/serializer/serializers/tag.rb +19 -0
  193. data/lib/coradoc/asciidoc/serializer/serializers/term.rb +20 -0
  194. data/lib/coradoc/asciidoc/serializer/serializers/text_element.rb +23 -0
  195. data/lib/coradoc/asciidoc/serializer/serializers/title.rb +55 -0
  196. data/lib/coradoc/asciidoc/serializer/serializers/video.rb +33 -0
  197. data/lib/coradoc/asciidoc/serializer/spacing_strategy.rb +70 -0
  198. data/lib/coradoc/asciidoc/serializer.rb +75 -0
  199. data/lib/coradoc/asciidoc/transform/from_core_model.rb +502 -0
  200. data/lib/coradoc/asciidoc/transform/from_core_model_registrations.rb +126 -0
  201. data/lib/coradoc/asciidoc/transform/registry.rb +146 -0
  202. data/lib/coradoc/asciidoc/transform/to_core_model.rb +564 -0
  203. data/lib/coradoc/asciidoc/transform/to_core_model_registrations.rb +257 -0
  204. data/lib/coradoc/asciidoc/transform.rb +13 -0
  205. data/lib/coradoc/asciidoc/transformer/block_rules.rb +101 -0
  206. data/lib/coradoc/asciidoc/transformer/header_rules.rb +91 -0
  207. data/lib/coradoc/asciidoc/transformer/inline_rules.rb +179 -0
  208. data/lib/coradoc/asciidoc/transformer/list_rules.rb +131 -0
  209. data/lib/coradoc/asciidoc/transformer/misc_rules.rb +196 -0
  210. data/lib/coradoc/asciidoc/transformer/structural_rules.rb +216 -0
  211. data/lib/coradoc/asciidoc/transformer/text_rules.rb +107 -0
  212. data/lib/coradoc/asciidoc/transformer.rb +406 -0
  213. data/lib/coradoc/asciidoc/version.rb +7 -0
  214. data/lib/coradoc/asciidoc.rb +148 -0
  215. data/lib/coradoc/util/asciidoc.rb +71 -0
  216. data/lib/coradoc/util.rb +8 -0
  217. metadata +343 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c26d9ebfcf6853d33150a149234dbb84d35fa07afe3cba77894fa6bcc96dc0cd
4
+ data.tar.gz: d9208da701b03723fedcbe52bc40dad2c7c880fbc48d2817e309a7fdfd439d35
5
+ SHA512:
6
+ metadata.gz: 0c10a653ea35637819bd299247cfa100793dc16ec9a02e4c9d96e4e54dbf8f6d38fd053feab58e8849a5b06d4cf24c2b9a97fd29048e584e76ca1a732cbb0628
7
+ data.tar.gz: 76fb17f26249012cc48d581cb4dce02ffee066260d41cd010b7bcf8f2c7bfa46ac4ef83330d5d14d568099b059abf2cb910d19b397d4b12401833bb4867a0282
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --require spec_helper
2
+ --format documentation
3
+ --color
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Model
6
+ # Admonition block for AsciiDoc documents.
7
+ #
8
+ # Admonitions are special callout boxes that highlight important
9
+ # information: NOTE, TIP, WARNING, CAUTION, IMPORTANT.
10
+ #
11
+ # @!attribute [r] content
12
+ # @return [String] The admonition text content
13
+ #
14
+ # @!attribute [r] type
15
+ # @return [String] The admonition type (e.g., "NOTE", "TIP", "WARNING")
16
+ #
17
+ # @!attribute [r] line_break
18
+ # @return [String] Line break character (default: "")
19
+ #
20
+ # @example Create a note admonition
21
+ # admonition = Coradoc::AsciiDoc::Model::Admonition.new
22
+ # admonition.type = "NOTE"
23
+ # admonition.content = "This is important information"
24
+ #
25
+ # @example Create a warning admonition
26
+ # admonition = Coradoc::AsciiDoc::Model::Admonition.new
27
+ # admonition.type = "WARNING"
28
+ # admonition.content = "Be careful!"
29
+ #
30
+ class Admonition < Attached
31
+ attribute :content, :string
32
+ attribute :type, :string
33
+ attribute :line_break, :string, default: -> { '' }
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Model
6
+ # Mixin for elements that can have anchors (IDs and references).
7
+ #
8
+ # The Anchorable module provides functionality for elements that can
9
+ # be referenced from other parts of the document. It automatically
10
+ # creates an Inline::Anchor based on the element's id attribute.
11
+ #
12
+ # @example Including Anchorable in a class
13
+ # class MyElement < Coradoc::AsciiDoc::Model::Base
14
+ # include Coradoc::AsciiDoc::Model::Anchorable
15
+ # attribute :id, :string
16
+ # end
17
+ #
18
+ # @example Using the generated anchor
19
+ # element = MyElement.new(id: "section1")
20
+ # element.anchor.to_adoc # => "[[section1]]"
21
+ #
22
+ module Anchorable
23
+ # Hook called when module is included in a class
24
+ #
25
+ # Automatically adds the :anchor attribute to the including class.
26
+ #
27
+ # @param base [Class] The class including this module
28
+ def self.included(base)
29
+ base.class_eval do
30
+ attribute :anchor, :string
31
+ end
32
+ end
33
+
34
+ # Override initialize to set default anchor
35
+ def initialize(*args)
36
+ super
37
+ @anchor ||= default_anchor
38
+ end
39
+
40
+ # Generate the default anchor based on the element's id
41
+ #
42
+ # @return [String, nil] The anchor string, or nil if no id
43
+ def default_anchor
44
+ id.nil? ? nil : "[[#{id}]]"
45
+ end
46
+
47
+ # Generate the anchor string for serialization
48
+ #
49
+ # @param inline [Boolean] If true, don't add trailing newline
50
+ # @return [String] The serialized anchor string
51
+ def gen_anchor(inline: false)
52
+ return '' if anchor.nil?
53
+
54
+ anchor_str = anchor.to_adoc
55
+ if anchor_str.empty?
56
+ ''
57
+ else
58
+ "#{anchor_str}#{inline ? '' : "\n"}"
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Model
6
+ # Base class for attached elements in AsciiDoc documents.
7
+ #
8
+ # Attached elements are those that can be attached to other elements
9
+ # such as list items or blocks. They include admonitions, paragraphs,
10
+ # and other block types.
11
+ #
12
+ # This class provides the foundation for elements that can be
13
+ # "attached" to parent elements in the document structure.
14
+ #
15
+ # @see Coradoc::AsciiDoc::Model::Admonition
16
+ # @see Coradoc::AsciiDoc::Model::Paragraph
17
+ # @see Coradoc::AsciiDoc::Model::Block::Core
18
+ #
19
+ class Attached < Base
20
+ def block_level?
21
+ true
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Model
6
+ class Attribute < Base
7
+ attribute :key, :string
8
+ attribute :value, :string, collection: true
9
+ attribute :line_break, :string, default: -> { "\n" }
10
+
11
+ private
12
+
13
+ # Build values from comma-separated string
14
+ # NOTE: This method allows for multiple values in format-specific attributes.
15
+ def build_values(value)
16
+ values = value.split(',').map(&:strip)
17
+ values.length > 1 ? values : values.first
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Model
6
+ class AttributeList < Base
7
+ module Matchers
8
+ def one(*args)
9
+ One.new(*args)
10
+ end
11
+
12
+ class One
13
+ def initialize(*possibilities)
14
+ @possibilities = possibilities
15
+ end
16
+
17
+ def ===(other)
18
+ @possibilities.any? { |i| i === other }
19
+ end
20
+ end
21
+
22
+ def many(*args)
23
+ Many.new(*args)
24
+ end
25
+
26
+ # NOTE: The Many matcher validates that all values in an array/string match
27
+ # one of the specified possibilities. Currently accepts all matching values
28
+ # without selective rejection - this may be enhanced in future versions.
29
+ class Many
30
+ def initialize(*possibilities)
31
+ @possibilities = possibilities
32
+ end
33
+
34
+ def ===(other)
35
+ other = other.split(',') if other.is_a?(String)
36
+
37
+ other.is_a?(Array) &&
38
+ other.all? { |i| @possibilities.any? { |p| p === i } }
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,230 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Model
6
+ # Attribute list for AsciiDoc elements.
7
+ #
8
+ # Attribute lists represent the square-bracket attribute syntax in AsciiDoc:
9
+ # [positional1, pos2, name1=value1, name2=value2]
10
+ #
11
+ # This class manages both positional and named attributes, with support
12
+ # for validation and rejection of invalid values.
13
+ #
14
+ # @!attribute [r] positional
15
+ # @return [Array<Coradoc::AsciiDoc::Model::AttributeListAttribute>] Positional attributes (by position)
16
+ #
17
+ # @!attribute [r] named
18
+ # @return [Array<Coradoc::AsciiDoc::Model::NamedAttribute>] Named attributes (key-value pairs)
19
+ #
20
+ # @!attribute [r] rejected_positional
21
+ # @return [Array<Coradoc::AsciiDoc::Model::RejectedPositionalAttribute>] Rejected positional attributes
22
+ #
23
+ # @!attribute [r] rejected_named
24
+ # @return [Array<Coradoc::AsciiDoc::Model::NamedAttribute>] Rejected named attributes
25
+ #
26
+ # @example Create an attribute list
27
+ # attrs = Coradoc::AsciiDoc::Model::Coradoc::AsciiDoc::Model::AttributeList.new
28
+ # attrs.add_positional("value1")
29
+ # attrs.add_named("option", "value")
30
+ # attrs.to_adoc # => "[value1,option=value]\n"
31
+ #
32
+ # @example Empty attribute list
33
+ # attrs = Coradoc::AsciiDoc::Model::Coradoc::AsciiDoc::Model::AttributeList.new
34
+ # attrs.to_adoc # => "[]"
35
+ #
36
+ # @example Hide empty attribute list
37
+ # attrs = Coradoc::AsciiDoc::Model::Coradoc::AsciiDoc::Model::AttributeList.new
38
+ # attrs.to_adoc(show_empty: false) # => ""
39
+ #
40
+ class AttributeList < Base
41
+ # Autoload Matchers module
42
+ autoload :Matchers, 'coradoc/asciidoc/model/attribute_list/matchers'
43
+
44
+ # Include Matchers module for validation methods
45
+ include Matchers
46
+
47
+ attribute :positional,
48
+ Coradoc::AsciiDoc::Model::AttributeListAttribute,
49
+ collection: true,
50
+ initialize_empty: true
51
+ attribute :named, Coradoc::AsciiDoc::Model::NamedAttribute, collection: true, initialize_empty: true
52
+ attribute :rejected_positional,
53
+ Coradoc::AsciiDoc::Model::RejectedPositionalAttribute,
54
+ collection: true,
55
+ initialize_empty: true
56
+ attribute :rejected_named,
57
+ Coradoc::AsciiDoc::Model::NamedAttribute,
58
+ collection: true,
59
+ initialize_empty: true
60
+
61
+ # Add positional attributes to this list
62
+ #
63
+ # @param attr [Array<Object>] Values to add as positional attributes
64
+ #
65
+ # @example Adding positional attributes
66
+ # attrs.add_positional("value1", "value2")
67
+ #
68
+ def add_positional(*attr)
69
+ attr.each do |a|
70
+ @positional << AttributeListAttribute.new(value: a)
71
+ end
72
+ end
73
+
74
+ # Add a named attribute to this list
75
+ #
76
+ # @param name [String, Symbol] The attribute name
77
+ # @param value [Object] The attribute value (will be converted to array)
78
+ #
79
+ # @example Adding named attributes
80
+ # attrs.add_named("title", "My Title")
81
+ # attrs.add_named("cols", "3,2,1")
82
+ #
83
+ def add_named(name, value)
84
+ @named << NamedAttribute.new(
85
+ name:,
86
+ value: value.is_a?(Array) ? value : [value]
87
+ )
88
+ end
89
+
90
+ # Validate named attributes against validators
91
+ #
92
+ # @param validators [Hash] Hash of name => matcher pairs
93
+ # @yield [name, value] Block called for each invalid attribute
94
+ #
95
+ # @example Validate with custom validator
96
+ # attrs.validate_named(title: /./) do |name, value|
97
+ # puts "Invalid #{name}: #{value}"
98
+ # end
99
+ #
100
+ def validate_named(validators: {})
101
+ named.each_with_index do |named_attribute, _i|
102
+ name = named_attribute.name.to_sym
103
+ value = named_attribute.value
104
+
105
+ matcher = validators[name]
106
+
107
+ next if matcher && matcher === value
108
+
109
+ # Previous implementation would remove the value from the list
110
+ # named.delete(name)
111
+ rejected_named << named_attribute.dup
112
+ yield(name, value) if block_given?
113
+ end
114
+ end
115
+
116
+ # Validate positional attributes against validators
117
+ #
118
+ # @param validators [Array] Array of [position, matcher] pairs
119
+ # @yield [position, value] Block called for each invalid attribute
120
+ #
121
+ # @example Validate positional attributes
122
+ # attrs.validate_positional([[0, /./], [1, Integer]])
123
+ #
124
+ def validate_positional(validators: [])
125
+ positional.each_with_index do |positional_attribute, i|
126
+ matcher = validators[i][1]
127
+ value = positional_attribute.value
128
+
129
+ next unless matcher && !(matcher === value)
130
+
131
+ warn "#{value} does not match #{matcher}"
132
+ # Previous implementation would remove the value from the list
133
+ # positional[i] = nil
134
+ rejected_positional << RejectedPositionalAttribute.new(
135
+ position: i, value:
136
+ )
137
+ yield(i, value) if block_given?
138
+ end
139
+ end
140
+
141
+ # To be overridden in subclasses.
142
+ # @return [Array] Array of positional validators
143
+ def positional_validators
144
+ []
145
+ end
146
+
147
+ # To be overridden in subclasses.
148
+ # @return [Hash] Hash of named validators
149
+ def named_validators
150
+ {}
151
+ end
152
+
153
+ # Validate this attribute list
154
+ #
155
+ # @return [Array<Lutaml::Model::Error>] Validation errors (empty if valid)
156
+ def validate
157
+ errors = super
158
+
159
+ validate_positional(positional_validators) do |i, value|
160
+ errors << Lutaml::Model::Error.new(
161
+ "Positional attribute at position #{i} with value '#{value}' is not valid"
162
+ )
163
+ end
164
+
165
+ validate_named(named_validators) do |name, value|
166
+ errors << Lutaml::Model::Error.new(
167
+ "Named attribute #{name} with value '#{value}' is not valid"
168
+ )
169
+ end
170
+
171
+ errors
172
+ end
173
+
174
+ # Serialize this attribute list to AsciiDoc
175
+ #
176
+ # Generates the square-bracket syntax with valid attributes only.
177
+ #
178
+ # @param show_empty [Boolean] If true, show "[]" for empty lists (default: true)
179
+ # @return [String] AsciiDoc representation of this attribute list
180
+ #
181
+ # @example Serialize with options
182
+ # attrs.to_adoc(show_empty: true) # => "[value1,name=val]"
183
+ # attrs.to_adoc(show_empty: false) # => "[value1,name=val]"
184
+ # empty.to_adoc # => "[]"
185
+ # empty.to_adoc(show_empty: false) # => ""
186
+ #
187
+ def to_adoc(show_empty: true)
188
+ valid_positional = positional.reject.with_index do |_p, i|
189
+ rejected_positional.any? { |r| r.position == i }
190
+ end
191
+
192
+ valid_named = named.reject do |n|
193
+ rejected_named.any? { |r| r.name == n.name }
194
+ end
195
+
196
+ adoc = [valid_positional,
197
+ valid_named].flatten.map(&:to_adoc).join(',')
198
+
199
+ if adoc.empty? && show_empty
200
+ '[]'
201
+ elsif adoc.empty?
202
+ ''
203
+ else
204
+ "[#{adoc}]"
205
+ end
206
+ end
207
+
208
+ def empty?
209
+ positional.empty? && named.empty?
210
+ end
211
+
212
+ # Get a named attribute value by name
213
+ # @param name [String, Symbol] The attribute name
214
+ # @return [Object, nil] The attribute value or nil if not found
215
+ def [](name)
216
+ name_str = name.to_s
217
+ named.find { |n| n.name.to_s == name_str }&.value
218
+ end
219
+
220
+ # Get a named attribute value with default
221
+ # @param name [String, Symbol] The attribute name
222
+ # @param default [Object] The default value if not found
223
+ # @return [Object] The attribute value or default
224
+ def fetch(name, default = nil)
225
+ self[name] || default
226
+ end
227
+ end
228
+ end
229
+ end
230
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Model
6
+ class AttributeListAttribute < Base
7
+ attribute :value, :string
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Model
6
+ # Audio block element for AsciiDoc documents.
7
+ #
8
+ # Audio elements are embedded multimedia content with support for
9
+ # various audio formats and custom attributes.
10
+ #
11
+ # @!attribute [r] id
12
+ # @return [String, nil] Optional identifier for the audio
13
+ #
14
+ # @!attribute [r] title
15
+ # @return [String, nil] Optional audio title
16
+ #
17
+ # @!attribute [r] src
18
+ # @return [String] The audio source URL or path
19
+ #
20
+ # @!attribute [r] attributes
21
+ # @return [Coradoc::AsciiDoc::Model::AttributeList] Audio attributes
22
+ #
23
+ # @!attribute [r] line_break
24
+ # @return [String] Line break character (default: "\n")
25
+ #
26
+ # @example Create an audio block
27
+ # audio = Coradoc::AsciiDoc::Model::Audio.new
28
+ # audio.src = "https://example.com/audio.mp3"
29
+ # audio.title = "Podcast Episode"
30
+ #
31
+ class Audio < Base
32
+ include Coradoc::AsciiDoc::Model::Anchorable
33
+
34
+ attribute :id, :string
35
+ attribute :title, :string
36
+ attribute :src, :string, default: -> { '' }
37
+ attribute :attributes, Coradoc::AsciiDoc::Model::AttributeList, default: lambda {
38
+ Coradoc::AsciiDoc::Model::AttributeList.new
39
+ }
40
+ attribute :line_break, :string, default: -> { "\n" }
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Model
6
+ # Author information for document headers.
7
+ #
8
+ # Author metadata captures document author names and contact information.
9
+ #
10
+ # @!attribute [r] first_name
11
+ # @return [String, nil] Author's first name
12
+ #
13
+ # @!attribute [r] middle_name
14
+ # @return [String, nil] Author's middle name or initial
15
+ #
16
+ # @!attribute [r] last_name
17
+ # @return [String, nil] Author's last name
18
+ #
19
+ # @!attribute [r] email
20
+ # @return [String, nil] Author's email address
21
+ #
22
+ # @example Create an author
23
+ # author = Coradoc::AsciiDoc::Model::Author.new
24
+ # author.first_name = "John"
25
+ # author.last_name = "Doe"
26
+ # author.email = "john@example.com"
27
+ #
28
+ class Author < Base
29
+ attribute :first_name, :string
30
+ attribute :last_name, :string
31
+ attribute :email, :string
32
+ attribute :middle_name, :string
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+
3
+ # require "lutaml/model"
4
+
5
+ module Coradoc
6
+ module AsciiDoc
7
+ module Model
8
+ # Base class for all Coradoc model objects.
9
+ #
10
+ # The Base class provides common functionality for all document model elements,
11
+ # including serialization support, tree traversal, and attribute management.
12
+ #
13
+ # All model classes inherit from this class to get:
14
+ # - Lutaml::Model serialization capabilities
15
+ # - ComparableModel functionality
16
+ # - Visit pattern for tree traversal
17
+ # - Polymorphic content serialization
18
+ #
19
+ # @!attribute [r] id
20
+ # @return [String, nil] Optional identifier for the element
21
+ #
22
+ # @example Implementing a custom model class
23
+ # class CustomBlock < Coradoc::AsciiDoc::Model::Base
24
+ # attribute :content, :string
25
+ # attribute :children, array: true
26
+ # end
27
+ #
28
+ # @example Using the visit pattern
29
+ # doc.visit do |element, phase|
30
+ # puts "#{phase}: #{element.class}" if element.is_a?(Paragraph)
31
+ # end
32
+ #
33
+ class Base < Lutaml::Model::Serializable
34
+ include Lutaml::Model::ComparableModel
35
+
36
+ attribute :id, :string
37
+
38
+ # Element classification for spacing and serialization decisions.
39
+ # Subclasses override these to declare their level.
40
+ def block_level?
41
+ false
42
+ end
43
+
44
+ def inline?
45
+ false
46
+ end
47
+
48
+ # Generate a warning message whenever this method is called.
49
+ def simplify_block_content(content)
50
+ warn '[DEPRECATION] #simplify_block_content is called inside a Lutaml Model. This is still a WIP.'
51
+ # print part of the stack trace
52
+ caller_locations(1, 3).each do |location|
53
+ warn " #{location.path}:#{location.lineno} in #{location.label}"
54
+ end
55
+
56
+ content
57
+ end
58
+
59
+ # Visit pattern for traversing the document tree
60
+ def self.visit(element, &block)
61
+ return element if element.nil?
62
+
63
+ element = yield element, :pre
64
+ element = case element
65
+ when Coradoc::AsciiDoc::Model::Base
66
+ element.visit(&block)
67
+ when Array
68
+ element.map { |child| visit(child, &block) }
69
+ .flatten.compact
70
+ when Hash
71
+ result = {}
72
+ element.each do |k, v|
73
+ result[k] = visit(v, &block)
74
+ end
75
+ result
76
+ else
77
+ element
78
+ end
79
+ yield element, :post
80
+ end
81
+
82
+ def visit(&block)
83
+ self.class.attributes.each_key do |attr_name|
84
+ child = public_send(attr_name)
85
+ result = self.class.visit(child, &block)
86
+ public_send(:"#{attr_name}=", result) if result != child
87
+ end
88
+ self
89
+ end
90
+
91
+ # Serialize polymorphic content to AsciiDoc string
92
+ # Handles: Arrays, Strings, nil, and model objects
93
+ # Raises ArgumentError for unknown types to force proper handling
94
+ def serialize_content(content)
95
+ case content
96
+ when Array
97
+ content.map { |elem| serialize_content(elem) }.join
98
+ when String
99
+ content
100
+ when nil
101
+ ''
102
+ when Coradoc::AsciiDoc::Model::Base, Lutaml::Model::Serializable
103
+ # All model objects should respond to to_adoc
104
+ content.to_adoc
105
+ else
106
+ # This is a programming error - we received an unexpected type
107
+ raise ArgumentError,
108
+ "Cannot serialize #{content.class.name} in content. " \
109
+ 'Expected String, nil, Array, Coradoc::AsciiDoc::Model::Base, or ' \
110
+ "Lutaml::Model::Serializable. Got: #{content.inspect[0..100]}"
111
+ end
112
+ end
113
+
114
+ # Does a shallow attribute dump of the object,
115
+ # for use when instantiating a new object (e.g. of a subclass) from an
116
+ # existing one.
117
+ def to_h
118
+ self.class.attributes.keys.each_with_object({}) do |attribute, acc|
119
+ acc[attribute] = public_send(attribute)
120
+ end
121
+ end
122
+
123
+ # Serialize this model element to AsciiDoc
124
+ #
125
+ # This is the unified serialization method for all Model objects.
126
+ # It uses the ElementRegistry system which provides serializers
127
+ # for each model type.
128
+ #
129
+ # @return [String] AsciiDoc representation of this element
130
+ #
131
+ # @example Serialize a paragraph to AsciiDoc
132
+ # para = Coradoc::AsciiDoc::Model::Paragraph.new("Hello World")
133
+ # para.to_adoc # => "Hello World\n"
134
+ #
135
+ def to_adoc
136
+ Coradoc::AsciiDoc::Serializer.serialize(self)
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end