arrolio 0.1.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 (272) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +2 -0
  3. data/.rubocop.yml +343 -0
  4. data/CHANGELOG.md +18 -0
  5. data/CLAUDE.md +154 -0
  6. data/Gemfile +15 -0
  7. data/LICENSE +24 -0
  8. data/README.adoc +95 -0
  9. data/Rakefile +21 -0
  10. data/TODO.complete/01-true-type-font-metrics.md +56 -0
  11. data/TODO.complete/02-font-embedding.md +51 -0
  12. data/TODO.complete/03-knuth-plass-breaker.md +42 -0
  13. data/TODO.complete/04-table-flowable.md +60 -0
  14. data/TODO.complete/05-list-flowable.md +50 -0
  15. data/TODO.complete/06-notes-and-examples.md +41 -0
  16. data/TODO.complete/07-odd-even-templates-and-page-numbering.md +63 -0
  17. data/TODO.complete/08-image-flowable.md +45 -0
  18. data/TODO.complete/09-toc-and-leaders.md +66 -0
  19. data/TODO.complete/10-hyperlinks-and-destinations.md +46 -0
  20. data/TODO.complete/11-pdf-outline-bookmarks.md +47 -0
  21. data/TODO.complete/12-metadata-info-dict.md +42 -0
  22. data/TODO.complete/13-xmp-metadata.md +43 -0
  23. data/TODO.complete/14-footnotes.md +43 -0
  24. data/TODO.complete/15-color-management.md +33 -0
  25. data/TODO.complete/16-pdfua-struct-tree.md +35 -0
  26. data/TODO.complete/17-alt-text-and-actual-text.md +28 -0
  27. data/TODO.complete/18-math-rendering.md +41 -0
  28. data/TODO.complete/19-preformatted-and-code.md +31 -0
  29. data/TODO.complete/20-page-break-controls.md +46 -0
  30. data/TODO.complete/21-svg-renderer.md +40 -0
  31. data/TODO.complete/22-definition-lists.md +36 -0
  32. data/TODO.complete/23-multi-column.md +34 -0
  33. data/TODO.complete/24-cover-page-fidelity.md +40 -0
  34. data/TODO.complete/25-i18n-and-multi-language.md +28 -0
  35. data/TODO.complete/26-pixel-diff-harness.md +36 -0
  36. data/TODO.complete/27-pdfrb-only-text-extraction.md +37 -0
  37. data/TODO.complete/28-restore-nested-module-style.md +41 -0
  38. data/TODO.complete/29-font-embedding-wiring-debug.md +72 -0
  39. data/TODO.complete/30-adapter-decomposition.md +76 -0
  40. data/TODO.complete/31-subscript-superscript-inline-runs.md +56 -0
  41. data/TODO.complete/32-debug-output-cleanup.md +59 -0
  42. data/TODO.complete/33-comprehensive-adapter-specs.md +55 -0
  43. data/TODO.complete/34-table-column-auto-layout.md +50 -0
  44. data/TODO.complete/35-image-path-resolution.md +66 -0
  45. data/TODO.complete/36-xsl-converter-completeness.md +40 -0
  46. data/TODO.complete/37-content-model-completeness.md +54 -0
  47. data/TODO.complete/38-pipeline-config-externalization.md +55 -0
  48. data/TODO.complete/39-two-pass-cross-reference-resolution.md +66 -0
  49. data/TODO.complete/40-vertical-writing-modes.md +63 -0
  50. data/TODO.complete/41-pdf-annotations-hyperlinks.md +53 -0
  51. data/TODO.complete/42-font-manifest-configuration.md +75 -0
  52. data/TODO.complete/43-shrink-to-fit-containers.md +52 -0
  53. data/TODO.complete/44-back-of-book-index-generation.md +51 -0
  54. data/TODO.complete/45-pdf-forms-acroform.md +52 -0
  55. data/TODO.complete/46-pdf-digital-signatures.md +47 -0
  56. data/TODO.complete/47-ocp-flavor-separation.md +50 -0
  57. data/TODO.complete/48-oiml-as-pure-configuration.md +80 -0
  58. data/TODO.complete/49-oiml-flowbuilder-as-configuration.md +39 -0
  59. data/TODO.complete/50-delete-oiml-ruby-code.md +53 -0
  60. data/TODO.complete/51-xsl-as-authoritative-source.md +68 -0
  61. data/TODO.complete/52-flavor-packaging-separation.md +49 -0
  62. data/TODO.complete/53-second-flavor-spike.md +74 -0
  63. data/TODO.complete/54-flavor-manifest-contract.md +72 -0
  64. data/TODO.complete/55-header-footer-style-configuration.md +57 -0
  65. data/TODO.complete/56-generic-adapter-mece-decomposition.md +56 -0
  66. data/TODO.complete/57-strict-section-typing.md +49 -0
  67. data/TODO.complete/58-flavor-packaging-gem-convention.md +47 -0
  68. data/TODO.complete/59-xsl-converter-profiles.md +76 -0
  69. data/TODO.complete/60-adapter-fidelity-footnotes-notes-examples.md +62 -0
  70. data/TODO.complete/61-error-model-and-strict-mode.md +62 -0
  71. data/TODO.complete/62-font-resolution-and-strict-fonts.md +66 -0
  72. data/TODO.complete/63-purge-hardcoded-vocabulary-from-generic-core.md +68 -0
  73. data/TODO.complete/64-selector-driven-adapter-specs.md +46 -0
  74. data/TODO.complete/66-semantic-content-types.md +171 -0
  75. data/TODO.complete/README.md +48 -0
  76. data/TODO.implementation/01-foundation.md +46 -0
  77. data/TODO.implementation/02-content-contract.md +47 -0
  78. data/TODO.implementation/03-layoutspec-contract.md +46 -0
  79. data/TODO.implementation/04-style-system.md +43 -0
  80. data/TODO.implementation/05-visitor-pattern.md +40 -0
  81. data/TODO.implementation/06-afm-data-and-parser.md +37 -0
  82. data/TODO.implementation/07-afm-metrics.md +41 -0
  83. data/TODO.implementation/08-truetype-tables-and-metrics.md +48 -0
  84. data/TODO.implementation/09-font-registry-and-glyph-measurer.md +49 -0
  85. data/TODO.implementation/10-break-opportunity-and-inline-run.md +47 -0
  86. data/TODO.implementation/11-greedy-line-breaker.md +48 -0
  87. data/TODO.implementation/12-knuth-plass-line-breaker.md +46 -0
  88. data/TODO.implementation/13-line-and-alignment.md +45 -0
  89. data/TODO.implementation/14-knuth-elements-and-breaker.md +56 -0
  90. data/TODO.implementation/15-refactor-text-layout-on-knuth.md +47 -0
  91. data/TODO.implementation/16-flowable-and-frame.md +52 -0
  92. data/TODO.implementation/17-flow-context.md +50 -0
  93. data/TODO.implementation/18-text-flowable.md +52 -0
  94. data/TODO.implementation/19-spacer-and-page-break.md +52 -0
  95. data/TODO.implementation/20-engine-paged.md +63 -0
  96. data/TODO.implementation/21-output-tree.md +56 -0
  97. data/TODO.implementation/22-pdf-renderer.md +77 -0
  98. data/TODO.implementation/23-end-to-end-smoke.md +53 -0
  99. data/TODO.implementation/24-page-template-and-region.md +51 -0
  100. data/TODO.implementation/25-page-sequence-master.md +54 -0
  101. data/TODO.implementation/26-two-pass-layout.md +66 -0
  102. data/TODO.implementation/27-table-model.md +48 -0
  103. data/TODO.implementation/28-table-layouts.md +53 -0
  104. data/TODO.implementation/29-table-renderer.md +55 -0
  105. data/TODO.implementation/30-table-flowable.md +53 -0
  106. data/TODO.implementation/31-list-model.md +45 -0
  107. data/TODO.implementation/32-list-flowable.md +54 -0
  108. data/TODO.implementation/33-image-flowable.md +59 -0
  109. data/TODO.implementation/34-svg-renderer.md +58 -0
  110. data/TODO.implementation/35-svg-as-form-xobject.md +38 -0
  111. data/TODO.implementation/36-inline-builder.md +50 -0
  112. data/TODO.implementation/37-hyperlink.md +53 -0
  113. data/TODO.implementation/38-sub-superscript.md +44 -0
  114. data/TODO.implementation/39-leader-and-field-runs.md +60 -0
  115. data/TODO.implementation/40-bookmark-outline.md +45 -0
  116. data/TODO.implementation/41-destinations.md +52 -0
  117. data/TODO.implementation/42-toc-builder.md +52 -0
  118. data/TODO.implementation/43-footnotes.md +51 -0
  119. data/TODO.implementation/44-multi-column.md +45 -0
  120. data/TODO.implementation/45-page-numbering-and-section-tracking.md +50 -0
  121. data/TODO.implementation/46-color-management.md +47 -0
  122. data/TODO.implementation/47-metadata-and-xmp.md +41 -0
  123. data/TODO.implementation/48-struct-tree-and-marked-content.md +49 -0
  124. data/TODO.implementation/49-alt-text-and-actual-text.md +43 -0
  125. data/TODO.implementation/50-composer-facade.md +59 -0
  126. data/TODO.implementation/51-style-presets.md +44 -0
  127. data/TODO.implementation/52-oiml-adapter-and-e2e-pipeline.md +120 -0
  128. data/TODO.implementation/53-oiml-layout-spec.md +121 -0
  129. data/TODO.implementation/54-oiml-pipeline.md +97 -0
  130. data/TODO.implementation/55-pdf-comparator.md +98 -0
  131. data/TODO.implementation/56-diff-formatters.md +95 -0
  132. data/TODO.implementation/57-path-locator-and-enrichment.md +74 -0
  133. data/TODO.implementation/58-rspec-matchers-and-harness-api.md +124 -0
  134. data/TODO.implementation/59-pixel-diff-mode.md +93 -0
  135. data/TODO.implementation/60-yard-documentation.md +43 -0
  136. data/TODO.implementation/61-benchmarks-and-stress-tests.md +50 -0
  137. data/TODO.implementation/62-validation-framework.md +107 -0
  138. data/TODO.implementation/63-layout-rules-profile.md +110 -0
  139. data/TODO.implementation/64-pdfa-and-pdfua-conformance.md +74 -0
  140. data/TODO.implementation/65-feature-extractor.md +64 -0
  141. data/TODO.implementation/66-auto-fixer.md +75 -0
  142. data/TODO.implementation/README.md +169 -0
  143. data/data/arrolio/afm/Courier-Bold.afm +342 -0
  144. data/data/arrolio/afm/Courier-BoldOblique.afm +342 -0
  145. data/data/arrolio/afm/Courier-Oblique.afm +342 -0
  146. data/data/arrolio/afm/Courier.afm +342 -0
  147. data/data/arrolio/afm/Helvetica-Bold.afm +2827 -0
  148. data/data/arrolio/afm/Helvetica-BoldOblique.afm +2827 -0
  149. data/data/arrolio/afm/Helvetica-Oblique.afm +3051 -0
  150. data/data/arrolio/afm/Helvetica.afm +3051 -0
  151. data/data/arrolio/afm/Symbol.afm +213 -0
  152. data/data/arrolio/afm/Times-Bold.afm +2588 -0
  153. data/data/arrolio/afm/Times-BoldItalic.afm +2384 -0
  154. data/data/arrolio/afm/Times-Italic.afm +2667 -0
  155. data/data/arrolio/afm/Times-Roman.afm +2419 -0
  156. data/data/arrolio/afm/ZapfDingbats.afm +225 -0
  157. data/data/arrolio/glyphlist.txt +4306 -0
  158. data/exe/arrolio2pdf +28 -0
  159. data/lib/arrolio/asset_resolver.rb +36 -0
  160. data/lib/arrolio/color.rb +107 -0
  161. data/lib/arrolio/column_set.rb +64 -0
  162. data/lib/arrolio/composer.rb +10 -0
  163. data/lib/arrolio/config_driven_pipeline.rb +144 -0
  164. data/lib/arrolio/content/bibliography_item.rb +42 -0
  165. data/lib/arrolio/content/builder.rb +108 -0
  166. data/lib/arrolio/content/document.rb +60 -0
  167. data/lib/arrolio/content/example.rb +43 -0
  168. data/lib/arrolio/content/figure_group.rb +39 -0
  169. data/lib/arrolio/content/footnote.rb +46 -0
  170. data/lib/arrolio/content/form_field.rb +47 -0
  171. data/lib/arrolio/content/formula.rb +34 -0
  172. data/lib/arrolio/content/heading.rb +42 -0
  173. data/lib/arrolio/content/hyperlink.rb +42 -0
  174. data/lib/arrolio/content/image.rb +36 -0
  175. data/lib/arrolio/content/index_entry.rb +52 -0
  176. data/lib/arrolio/content/inline_run.rb +51 -0
  177. data/lib/arrolio/content/list.rb +60 -0
  178. data/lib/arrolio/content/note.rb +48 -0
  179. data/lib/arrolio/content/page_break.rb +28 -0
  180. data/lib/arrolio/content/paragraph.rb +38 -0
  181. data/lib/arrolio/content/preformatted.rb +47 -0
  182. data/lib/arrolio/content/section.rb +39 -0
  183. data/lib/arrolio/content/table.rb +117 -0
  184. data/lib/arrolio/content/term_entry.rb +43 -0
  185. data/lib/arrolio/content.rb +27 -0
  186. data/lib/arrolio/data_dir.rb +28 -0
  187. data/lib/arrolio/engine/cross_reference_registry.rb +69 -0
  188. data/lib/arrolio/engine/paged.rb +186 -0
  189. data/lib/arrolio/engine.rb +9 -0
  190. data/lib/arrolio/error.rb +70 -0
  191. data/lib/arrolio/flavor/manifest.rb +111 -0
  192. data/lib/arrolio/flavor/registry.rb +54 -0
  193. data/lib/arrolio/flavor.rb +23 -0
  194. data/lib/arrolio/flow_context.rb +37 -0
  195. data/lib/arrolio/flowable.rb +66 -0
  196. data/lib/arrolio/flowables/footnote_marker_flowable.rb +28 -0
  197. data/lib/arrolio/flowables/heading_flowable.rb +23 -0
  198. data/lib/arrolio/flowables/image_flowable.rb +53 -0
  199. data/lib/arrolio/flowables/list_flowable.rb +117 -0
  200. data/lib/arrolio/flowables/note_flowable.rb +19 -0
  201. data/lib/arrolio/flowables/page_break.rb +15 -0
  202. data/lib/arrolio/flowables/page_sequence_start.rb +28 -0
  203. data/lib/arrolio/flowables/spacer.rb +34 -0
  204. data/lib/arrolio/flowables/table_flowable.rb +147 -0
  205. data/lib/arrolio/flowables/text_flowable.rb +95 -0
  206. data/lib/arrolio/flowables/toc_line_flowable.rb +35 -0
  207. data/lib/arrolio/flowables/two_column_block.rb +56 -0
  208. data/lib/arrolio/flowables.rb +19 -0
  209. data/lib/arrolio/font/embedder.rb +197 -0
  210. data/lib/arrolio/font/manifest.rb +114 -0
  211. data/lib/arrolio/font/resolver.rb +161 -0
  212. data/lib/arrolio/font/text_encoder.rb +28 -0
  213. data/lib/arrolio/font.rb +10 -0
  214. data/lib/arrolio/font_metrics/afm_metrics.rb +91 -0
  215. data/lib/arrolio/font_metrics/registry.rb +55 -0
  216. data/lib/arrolio/font_metrics/true_type_metrics.rb +95 -0
  217. data/lib/arrolio/font_metrics.rb +10 -0
  218. data/lib/arrolio/frame.rb +36 -0
  219. data/lib/arrolio/generic_adapter.rb +672 -0
  220. data/lib/arrolio/generic_flow_builder.rb +338 -0
  221. data/lib/arrolio/glyph_measurer.rb +71 -0
  222. data/lib/arrolio/harness/pdf_diff.rb +104 -0
  223. data/lib/arrolio/harness/pixel_diff.rb +122 -0
  224. data/lib/arrolio/harness/text_diff.rb +53 -0
  225. data/lib/arrolio/harness/text_extractor.rb +58 -0
  226. data/lib/arrolio/harness.rb +10 -0
  227. data/lib/arrolio/inline_run.rb +59 -0
  228. data/lib/arrolio/layout_spec/flow.rb +17 -0
  229. data/lib/arrolio/layout_spec/loader.rb +117 -0
  230. data/lib/arrolio/layout_spec/page_template.rb +127 -0
  231. data/lib/arrolio/layout_spec/page_template_selector.rb +58 -0
  232. data/lib/arrolio/layout_spec/region.rb +38 -0
  233. data/lib/arrolio/layout_spec/scale_length.rb +34 -0
  234. data/lib/arrolio/layout_spec.rb +90 -0
  235. data/lib/arrolio/logger.rb +54 -0
  236. data/lib/arrolio/output/page.rb +69 -0
  237. data/lib/arrolio/output/placed_box.rb +68 -0
  238. data/lib/arrolio/output/region.rb +32 -0
  239. data/lib/arrolio/output.rb +10 -0
  240. data/lib/arrolio/renderer/accessibility_tagger.rb +70 -0
  241. data/lib/arrolio/renderer/font_registry.rb +32 -0
  242. data/lib/arrolio/renderer/link_annotator.rb +62 -0
  243. data/lib/arrolio/renderer/outline_builder.rb +102 -0
  244. data/lib/arrolio/renderer/pdf.rb +493 -0
  245. data/lib/arrolio/renderer/signature_config.rb +59 -0
  246. data/lib/arrolio/renderer/structure_tree_builder.rb +117 -0
  247. data/lib/arrolio/renderer/xmp_builder.rb +92 -0
  248. data/lib/arrolio/renderer.rb +17 -0
  249. data/lib/arrolio/style/definition.rb +98 -0
  250. data/lib/arrolio/style/loader.rb +25 -0
  251. data/lib/arrolio/style/registry.rb +53 -0
  252. data/lib/arrolio/style.rb +9 -0
  253. data/lib/arrolio/table/auto_layout.rb +91 -0
  254. data/lib/arrolio/table.rb +9 -0
  255. data/lib/arrolio/text_direction.rb +81 -0
  256. data/lib/arrolio/text_layout/break_opportunity.rb +103 -0
  257. data/lib/arrolio/text_layout/greedy.rb +110 -0
  258. data/lib/arrolio/text_layout/knuth_plass/breaker.rb +265 -0
  259. data/lib/arrolio/text_layout/knuth_plass/item.rb +84 -0
  260. data/lib/arrolio/text_layout/knuth_plass/item_builder.rb +103 -0
  261. data/lib/arrolio/text_layout/knuth_plass.rb +12 -0
  262. data/lib/arrolio/text_layout/line.rb +72 -0
  263. data/lib/arrolio/text_layout.rb +11 -0
  264. data/lib/arrolio/toc_builder.rb +31 -0
  265. data/lib/arrolio/version.rb +5 -0
  266. data/lib/arrolio/writing_mode.rb +75 -0
  267. data/lib/arrolio.rb +42 -0
  268. data/script/smoke.rb +32 -0
  269. data/scripts/write_content_extras.py +227 -0
  270. data/scripts/xsl_profiles/standoc.yml +218 -0
  271. data/scripts/xsl_to_config.rb +391 -0
  272. metadata +394 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: eb7855962c5ce79ad8835c3047502c8383bfd9aab11c3ecf885b94def434a05b
4
+ data.tar.gz: abb650933f49b7b58608446cbf05c319246289451ee89d29ad214bec091d1ce9
5
+ SHA512:
6
+ metadata.gz: 4ba64c22b8c3097f797e54c42905ba0a9b5afd92c16cdfaba9525ff3fc16a8829cace77d766daa020f6ef707e8c510a7c94acf9fd8cad326f03050e90b1aedeb
7
+ data.tar.gz: 67698e186ad720c1d46a14b75fe97f75c9b7e9db19364f3252983de16d43d055bda2c7a29f147136f2be48978d991a1ee132a952d143c6990f7e288499f4483e
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,343 @@
1
+ plugins:
2
+ - rubocop-performance
3
+ - rubocop-rake
4
+ - rubocop-rspec
5
+
6
+ AllCops:
7
+ NewCops: enable
8
+ TargetRubyVersion: 3.0
9
+ SuggestExtensions: false
10
+
11
+ Style/StringLiterals:
12
+ EnforcedStyle: single_quotes
13
+
14
+ Style/SymbolArray:
15
+ EnforcedStyle: brackets
16
+
17
+ Style/WordArray:
18
+ EnforcedStyle: brackets
19
+
20
+ Layout/LineLength:
21
+ Max: 120
22
+
23
+ Metrics/AbcSize:
24
+ Max: 80
25
+
26
+ Metrics/MethodLength:
27
+ Max: 60
28
+
29
+ Metrics/ClassLength:
30
+ Max: 600
31
+
32
+ Metrics/ModuleLength:
33
+ Max: 500
34
+
35
+ Metrics/CyclomaticComplexity:
36
+ Max: 30
37
+
38
+ Metrics/PerceivedComplexity:
39
+ Max: 30
40
+
41
+ Metrics/BlockLength:
42
+ Max: 150
43
+
44
+ Metrics/ParameterLists:
45
+ Max: 15
46
+
47
+ RSpec/ExampleLength:
48
+ Max: 15
49
+
50
+ RSpec/MultipleExpectations:
51
+ Max: 8
52
+
53
+ RSpec/DescribeClass:
54
+ Enabled: false
55
+
56
+ RSpec/LeakyLocalVariable:
57
+ Enabled: false
58
+
59
+ RSpec/ExampleLength:
60
+ Max: 30
61
+
62
+ RSpec/InstanceVariable:
63
+ Enabled: false
64
+
65
+ RSpec/HookArgument:
66
+ Enabled: false
67
+
68
+ RSpec/ContextWording:
69
+ Enabled: false
70
+
71
+ RSpec/BeEq:
72
+ Enabled: false
73
+
74
+ RSpec/StubbedMock:
75
+ Enabled: false
76
+
77
+ RSpec/AnyInstance:
78
+ Enabled: false
79
+
80
+ RSpec/SpecFilePathFormat:
81
+ Enabled: false
82
+
83
+ RSpec/MultipleDescribes:
84
+ Enabled: false
85
+
86
+ RSpec/NestedGroups:
87
+ Max: 5
88
+
89
+ RSpec/MultipleMemoizedHelpers:
90
+ Enabled: false
91
+
92
+ Style/HashSyntax:
93
+ EnforcedShorthandSyntax: either
94
+
95
+ Style/MapToHash:
96
+ Enabled: false
97
+
98
+ Style/HashTransformKeys:
99
+ Enabled: false
100
+
101
+ Style/RedundantCondition:
102
+ Enabled: false
103
+
104
+ Style/ReturnNilInPredicateMethodDefinition:
105
+ Enabled: false
106
+
107
+ Style/SafeNavigationChain:
108
+ Enabled: false
109
+
110
+ Style/GuardClause:
111
+ Enabled: false
112
+
113
+ Style/MutableConstant:
114
+ Enabled: false
115
+
116
+ Style/ParallelAssignment:
117
+ Enabled: false
118
+
119
+ Style/SoleNestedConditional:
120
+ Enabled: false
121
+
122
+ Style/IfUnlessModifier:
123
+ Enabled: false
124
+
125
+ Style/Next:
126
+ Enabled: false
127
+
128
+ Style/EmptyElse:
129
+ Enabled: false
130
+
131
+ Style/MultipleComparison:
132
+ Enabled: false
133
+
134
+ Style/RedundantReturn:
135
+ Enabled: false
136
+
137
+ Style/NestedTernaryOperator:
138
+ Enabled: false
139
+
140
+ Style/RedundantParentheses:
141
+ Enabled: false
142
+
143
+ Style/RedundantSelf:
144
+ Enabled: false
145
+
146
+ Naming/MethodParameterName:
147
+ Enabled: false
148
+
149
+ Style/IdenticalConditionalBranches:
150
+ Enabled: false
151
+
152
+ Style/RedundantCondition:
153
+ Enabled: false
154
+
155
+ Layout/IndentationWidth:
156
+ Enabled: false
157
+
158
+ Lint/BinaryOperatorWithIdenticalOperands:
159
+ Enabled: false
160
+
161
+ Lint/DuplicateBranch:
162
+ Enabled: false
163
+
164
+ Lint/DuplicateCaseCondition:
165
+ Enabled: false
166
+
167
+ Performance/CollectionLiteralInLoop:
168
+ Enabled: false
169
+
170
+ Style/ClassAndModuleChildren:
171
+ EnforcedStyle: nested
172
+ Enabled: false
173
+
174
+ Layout/RescueEnsureAlignment:
175
+ Enabled: false
176
+
177
+ Style/SymbolArray:
178
+ Enabled: false
179
+
180
+ Style/ArrayFirstLast:
181
+ Enabled: false
182
+
183
+ RSpec/RepeatedExample:
184
+ Enabled: false
185
+
186
+ RSpec/RepeatedDescription:
187
+ Enabled: false
188
+
189
+ Style/ArgumentsForwarding:
190
+ Enabled: false
191
+
192
+ Style/HashEachMethods:
193
+ Enabled: false
194
+
195
+ Style/SymbolProc:
196
+ Enabled: false
197
+
198
+ Style/PerlBackrefs:
199
+ Enabled: false
200
+
201
+ Style/GlobalStdStream:
202
+ Enabled: false
203
+
204
+ Style/StringConcatenation:
205
+ Enabled: false
206
+
207
+ Style/RescueModifier:
208
+ Enabled: false
209
+
210
+ Layout/MultilineMethodCallIndentation:
211
+ Enabled: false
212
+
213
+ Layout/MultilineOperationIndentation:
214
+ Enabled: false
215
+
216
+ Layout/ElseAlignment:
217
+ Enabled: false
218
+
219
+ Layout/FirstHashElementIndentation:
220
+ Enabled: false
221
+
222
+ Layout/FirstArrayElementIndentation:
223
+ Enabled: false
224
+
225
+ Layout/FirstArgumentIndentation:
226
+ Enabled: false
227
+
228
+ Layout/EndAlignment:
229
+ Enabled: false
230
+
231
+ Layout/BeginEndAlignment:
232
+ Enabled: false
233
+
234
+ Layout/CaseIndentation:
235
+ Enabled: false
236
+
237
+ Layout/ClosingParenthesisIndentation:
238
+ Enabled: false
239
+
240
+ Layout/SpaceAroundOperators:
241
+ Enabled: false
242
+
243
+ Layout/ExtraSpacing:
244
+ Enabled: false
245
+
246
+ Layout/SpaceBeforeBlockBraces:
247
+ Enabled: false
248
+
249
+ Layout/SpaceInsideBlockBraces:
250
+ Enabled: false
251
+
252
+ Layout/SpaceInsideHashLiteralBraces:
253
+ Enabled: false
254
+
255
+ Layout/EmptyLineAfterGuardClause:
256
+ Enabled: false
257
+
258
+ Layout/EmptyLinesAroundAttributeAccessor:
259
+ Enabled: false
260
+
261
+ Layout/EmptyLinesAroundClassBody:
262
+ Enabled: false
263
+
264
+ Layout/EmptyLinesAroundModuleBody:
265
+ Enabled: false
266
+
267
+ Layout/EmptyLinesAroundMethodBody:
268
+ Enabled: false
269
+
270
+ Layout/LeadingEmptyLines:
271
+ Enabled: false
272
+
273
+ Layout/EmptyLines:
274
+ Enabled: false
275
+
276
+ Layout/SpaceAroundKeyword:
277
+ Enabled: false
278
+
279
+ Layout/SpaceAfterColon:
280
+ Enabled: false
281
+
282
+ Layout/SpaceAfterComma:
283
+ Enabled: false
284
+
285
+ Lint/SuppressedException:
286
+ Enabled: false
287
+
288
+ Lint/UselessAccessModifier:
289
+ Enabled: false
290
+
291
+ Lint/ConstantDefinitionInBlock:
292
+ Enabled: false
293
+
294
+ Lint/EmptyBlock:
295
+ Enabled: false
296
+
297
+ Lint/ShadowingOuterLocalVariable:
298
+ Enabled: false
299
+
300
+ Lint/NonLocalExitFromIterator:
301
+ Enabled: false
302
+
303
+ Naming/VariableNumber:
304
+ Enabled: false
305
+
306
+ Naming/AccessorMethodName:
307
+ Enabled: false
308
+
309
+ Naming/PredicateName:
310
+ Enabled: false
311
+
312
+ Naming/MemoizedInstanceVariableName:
313
+ Enabled: false
314
+
315
+ Performance/MapMethodChain:
316
+ Enabled: false
317
+
318
+ Performance/FlatMap:
319
+ Enabled: false
320
+
321
+ Performance/UnfreezeString:
322
+ Enabled: false
323
+
324
+ Performance/StringInclude:
325
+ Enabled: false
326
+
327
+ Style/Documentation:
328
+ Enabled: false
329
+
330
+ Style/DocumentationMethod:
331
+ Enabled: false
332
+
333
+ Style/CommentedKeyword:
334
+ Enabled: false
335
+
336
+ Style/AsciiComments:
337
+ Enabled: false
338
+
339
+ Style/FormatStringToken:
340
+ Enabled: false
341
+
342
+ Lint/MissingSuper:
343
+ Enabled: false
data/CHANGELOG.md ADDED
@@ -0,0 +1,18 @@
1
+ # Changelog
2
+
3
+ All notable changes to the arrolio gem will be documented in this file.
4
+
5
+ ## [Unreleased]
6
+
7
+ ### Added — 2026-08-01 (initial scaffold)
8
+
9
+ * Project skeleton: gemspec, Gemfile, Rakefile, README.adoc, LICENSE,
10
+ `.rspec`, `.gitignore`.
11
+ * `Arrolio::VERSION` (`0.1.0.alpha1`).
12
+ * `Arrolio::Error` base + typed subclasses (`LayoutError`,
13
+ `RenderError`, `ContentError`, `LayoutSpecError`).
14
+ * Top-level autoload tree declaring the module structure: `Content`,
15
+ `LayoutSpec`, `Engine`, `Output`, `Renderer`, `Style`,
16
+ `FontMetrics`, `TextLayout`, `Flowables`, `Table`, `List`, `SVG`,
17
+ `FieldRun`, `Composer`. Subclass implementations land in follow-up
18
+ commits as code is ported from `Pdfrb::Layout::*`.
data/CLAUDE.md ADDED
@@ -0,0 +1,154 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## What Arrolio is
6
+
7
+ Arrolio is the middle layer of a three-library stack for paged-media PDF generation in pure Ruby:
8
+
9
+ - **`pdfrb`** (sibling gem, `~/src/claricle/pdfrb`) — pure-Ruby PDF byte format (streams, fonts, xref, encryption). No layout knowledge.
10
+ - **`arrolio`** (this gem) — FOP-like paged layout: page templates, threaded flows, line/page breaking, tables, lists, SVG, page-model selection, running headers/footers. **Flavor-agnostic**: the gem knows nothing about any specific document format.
11
+ - **`loom`** (separate gem, not yet built) — multi-target layout compiler (DSL → Arrolio IR, CSS, XSL-FO, IDML).
12
+
13
+ Arrolio deliberately does NOT own: PDF byte format (Pdfrb), DSL authoring (Loom), multi-target compilation (Loom), the semantic content model (`metanorma-document` and friends — Arrolio defines a *contract*, not a parser), or **any flavor-specific artifact** (no OIML/ISO/IEC/BSI code, data, XSL, or YAML inside the gem).
14
+
15
+ ## The flavor-encapsulation invariant (non-negotiable)
16
+
17
+ **Flavors live OUTSIDE the gem.** A flavor is a directory containing XSL-derived YAML configuration (and the upstream XSL itself). The gem ships zero flavor artifacts:
18
+
19
+ - `lib/` contains no flavor-named files (`oiml`, `iso`, `iec`, `bsi`, …).
20
+ - `lib/arrolio.rb` has no flavor autoloads and no flavor-specific Ruby anywhere.
21
+ - `lib/arrolio/generic_adapter.rb` has zero hardcoded XML element names outside a clearly-labelled `DEFAULT_SELECTORS` constant (Metanorma standoc convention).
22
+ - `lib/arrolio/renderer/pdf.rb` reads header/footer and cover-logo values from `layout_spec.yml`, not hardcoded constants (the only literals are engine-safe fallback defaults).
23
+ - `lib/arrolio/content/document.rb` constructor validates that `sections`, `preface`, `bibliography` are `Content::Section[]` — non-Section items raise `ContentError` at the construction site.
24
+ - `flavors/` (sibling of `lib/`) is excluded from the gemspec's `spec.files`.
25
+ - `spec/fixtures/flavors/sample/` is a synthetic, flavor-neutral fixture used by the gem's own tests.
26
+ - `flavors/PACKAGING.md` documents the flavor gem convention for external authors.
27
+
28
+ A flavor is rendered by pointing `Arroolio::ConfigDrivenPipeline` at the flavor directory:
29
+
30
+ ```ruby
31
+ Arroolio::ConfigDrivenPipeline.render(xml, io: io, flavor_dir: '/path/to/flavor')
32
+ ```
33
+
34
+ Or via CLI: `exe/arrolio2pdf input.xml output.pdf /path/to/flavor`.
35
+
36
+ The user's principle: **"OIML FLAVOR SHOULD ONLY BE CONFIGURATION — like how the XSL is PURE CONFIGURATION!! NO CODE!"** A flavor is XSL + 3 generated YAML files. Zero Ruby.
37
+
38
+ ## Two-pass model — the central architectural invariant
39
+
40
+ ```
41
+ Content tree + LayoutSpec
42
+ ↓ (layout pass)
43
+ Engine::Paged
44
+
45
+ Output::Page[] ← medium-neutral contract between Engine and Renderer
46
+ ↓ (render pass)
47
+ Renderer::Pdf
48
+
49
+ PDF bytes (via Pdfrb)
50
+ ```
51
+
52
+ **Output::Page[] is the only contract between Engine and Renderer.** The renderer must never make layout decisions — every coordinate, style, and content reference comes from the Output tree. Future renderers (PostScript, PPML, in-memory test canvas) walk the same tree.
53
+
54
+ Each layer is independently testable. Keep layer boundaries airtight: Content knows nothing about pages or PDF; Engine knows nothing about PDF bytes; Renderer knows nothing about layout algorithms.
55
+
56
+ ## Project state (as of 2026-08-03)
57
+
58
+ Generic config-driven pipeline works end-to-end: the OIML r060/1 fixture renders to a 25-page A4 PDF (~194 KB) via `Arroolio::ConfigDrivenPipeline` pointed at `flavors/oiml/`. 232 specs pass.
59
+
60
+ What's in the gem (core, flavor-agnostic):
61
+ - `lib/arrolio/{content,style,layout_spec,font,font_metrics,glyph_measurer,inline_run,text_layout,flowable,flowables,frame,flow_context,engine,output,renderer,harness,flavor}/`
62
+ - `lib/arrolio/generic_adapter.rb` — reads `adapter_rules.yml`, parses any flavor's XML into `Content::Document`.
63
+ - `lib/arrolio/generic_flow_builder.rb` — reads `flow_rules.yml`, builds flowables for any flavor.
64
+ - `lib/arrolio/config_driven_pipeline.rb` — orchestrates adapter + flow builder + engine + renderer + ToC.
65
+ - `lib/arrolio/asset_resolver.rb`, `lib/arrolio/toc_builder.rb` — generic helpers.
66
+ - `exe/arrolio2pdf` — generic CLI taking a flavor directory argument.
67
+ - `scripts/xsl_to_config.rb` — generates all three flavor YAML files from an XSL stylesheet.
68
+ - `data/arrolio/` — AFM metrics + glyphlist for the 14 PDF standard fonts (core data, not flavor data).
69
+
70
+ What's outside the gem (flavor artifacts):
71
+ - `flavors/oiml/{layout_spec,adapter_rules,flow_rules}.yml` — generated by `xsl_to_config.rb` from the authoritative XSL at `~/src/mn/metanorma-taste/data/oiml/oiml.xsl`.
72
+ - `spec/fixtures/flavors/sample/` — synthetic flavor-neutral fixture for the gem's tests.
73
+
74
+ What's deferred (intentionally — see `TODO.complete/`):
75
+ - TODO 53: second flavor spike (proves the generic design works beyond OIML).
76
+ - TODO 54: `flavors/<name>/manifest.yml` contract.
77
+ - TODO 55: header/footer style in `layout_spec.yml` (currently hardcoded in renderer).
78
+ - TODO 56: split `GenericAdapter` into MECE per-element converters.
79
+ - TODO 57: strict `Content::Document#sections` typing (only `Section[]`).
80
+ - TODO 58: flavor packaging convention (`arrolio-<flavor>` gems).
81
+ - TODO 59: XSL converter profiles (metanorma, dita, docbook).
82
+ - TODO 60: footnote / note-hanging-indent / example-body-margin fidelity.
83
+ - TODO 61: typed error model + strict mode.
84
+ - TODO 62: font resolution via fontist (currently absolute paths in YAML).
85
+ - Plus the older TODO.implementation items (Knuth-Plass, PageSequenceMaster, table layout, etc.).
86
+
87
+ The TODO files in `TODO.complete/` and `TODO.implementation/` are the roadmap. `TODO.complete/README.md` covers the parity roadmap; `TODO.implementation/README.md` covers the foundation phase plan.
88
+
89
+ **Naming:** the code uses `Arroolio` (one r); the gemspec/gem name is also `arrolio`. Some TODO files use `Arroolio` (two r's) — the code is authoritative.
90
+
91
+ ## Commands
92
+
93
+ ```bash
94
+ bundle exec rake # rspec + rubocop (the default task)
95
+ bundle exec rspec # full suite
96
+ bundle exec rspec spec/arrolio/style_spec.rb # one file
97
+ bundle exec rspec spec/arrolio/style_spec.rb:42 # one example by line
98
+ bundle exec rspec -t ~e2e # skip slow end-to-end specs
99
+ bundle exec rubocop
100
+ bundle exec rubocop -A # auto-correct safe offences
101
+
102
+ # Render any flavor via the generic CLI:
103
+ bundle exec ruby exe/arrolio2pdf input.xml out.pdf flavors/oiml
104
+
105
+ # Regenerate a flavor's YAML from its XSL (development time, not runtime):
106
+ bundle exec rake flavor:generate XSL=path/to/flavor.xsl OUT=flavors/name
107
+ # Or directly:
108
+ bundle exec ruby scripts/xsl_to_config.rb path/to/flavor.xsl flavors/name
109
+ ```
110
+
111
+ The OIML reference PDF for r060/1 is at `~/src/mn/mn-samples-oiml/_site/documents/r060/1/document.pdf` (mn2pdf v2.55, 28 pages). The OIML fixture XML is at `~/src/mn/mn-samples-oiml/_site/documents/r060/1/document.presentation.xml`.
112
+
113
+ `pdfrb` is pinned to a local path (`/Users/mulgogi/src/claricle/pdfrb`) in the Gemfile until it ships to RubyGems.
114
+
115
+ ## Architectural conventions (non-negotiable)
116
+
117
+ - **`autoload` only — never `require_relative`, never `require` for internal code.** Autoloads live in the immediate parent namespace's file (create that file if it doesn't exist yet). Example: classes under `Arroolio::Content::*` are autoloaded from `lib/arrolio/content.rb`, which itself is autoloaded from `lib/arrolio.rb`.
118
+ - **Nested module/class style, NOT compact.** Always write `module Arroolio; class Foo; end; end`, never `class Arroolio::Foo`. Compact style breaks Ruby's lexical constant lookup — sibling constants resolved by short name (e.g. `FontMetrics::Registry` inside `class Arroolio::GlyphMeasurer`) won't autoload.
119
+ - **`# frozen_string_literal: true` at the top of every Ruby file.**
120
+ - **Immutable value objects.** Models that cross a layer boundary freeze in their constructor and define `==`, `eql?`, `hash` by value. Builders accumulate into Arrays; the immutable node is constructed in one shot.
121
+ - **Dispatch by `is_a?` and `role` Symbols, not by `respond_to?`.** Each content/layout node carries a `style_id` Symbol used for style registry lookup.
122
+ - **No `send` to private methods, no `instance_variable_set`/`instance_variable_get`, no `respond_to?` type checks.** Redesign the boundary instead of bypassing encapsulation.
123
+ - **No `double()` in specs.** Use real model instances, or `Struct.new(...)` stand-ins for plain data.
124
+ - **No hand-rolled `to_h`/`from_h`/`to_json`/`serialize` on model classes.** (Style::Definition#to_h is allowed: Definition is a value object whose Hash form is internal config shape, not a persisted wire contract.)
125
+ - **Validation in constructors.** Bad input raises typed errors from `Arroolio::Error` (`ContentError`, `LayoutSpecError`, `LayoutError`, `RenderError`) carrying structured metadata, not generic `RuntimeError`.
126
+ - **No flavor artifacts in the gem.** No OIML/ISO/IEC/BSI Ruby, YAML, or XSL under `lib/` or `data/`. Flavors live in `flavors/` (excluded from the gemspec).
127
+
128
+ ## Design principles for new code
129
+
130
+ When extending any layer, apply OCP/DRY/MECE strictly:
131
+
132
+ - **Open/Closed:** adding a new flavor = adding a `flavors/<name>/` directory with XSL + 3 generated YAML files. Zero core changes. Adding a new flowable, content node, renderer, or visitor = *registering* a new class — not editing a switch statement.
133
+ - **MECE per layer:** Content describes *what*, LayoutSpec describes *how*, Engine produces *where*, Output freezes the result, Renderer emits bytes. Flavor describes *what the source format looks like* (adapter_rules.yml) and *how to lay it out* (flow_rules.yml + layout_spec.yml). If a class reaches across these boundaries, the responsibility is in the wrong place.
134
+ - **Greedy line breaking** is the only breaker today. When Knuth-Plass lands (TODO 12), it plugs into `TextLayout::*` without touching flowables or the engine.
135
+ - **Specs follow layer boundaries.** Each layer has its own spec directory; the `:e2e` tag is reserved for full-pipeline specs. The gem's own specs use the synthetic `spec/fixtures/flavors/sample/` flavor — they never depend on OIML.
136
+
137
+ ## Renderer/Pdfrb coupling notes
138
+
139
+ - `Renderer::Pdf#render_page` deliberately points each pdfrb page's `Resources` Hash at the catalog's. Pdfrb's `Fonts#add` attaches fonts to the *catalog* Resources, but each Page shadows with its own empty Hash — without this workaround, fonts are invisible to readers.
140
+ - `Renderer::FontRegistry` memoises font family name → Pdfrb resource Symbol per render pass. Falls back to Helvetica for unknown families so the render never crashes mid-document. TODO 62 makes this strict.
141
+ - TODO 55 moves the header/footer visual style (Arial 9pt + 0.5pt border, currently hardcoded in the renderer) into `layout_spec.yml` so each flavor controls its own header/footer look.
142
+
143
+ ## Key files to read first
144
+
145
+ - `lib/arrolio.rb` — the autoload tree; this is the map of every module.
146
+ - `lib/arrolio/error.rb` — the typed error hierarchy; raise these, never `RuntimeError`.
147
+ - `lib/arrolio/config_driven_pipeline.rb` — the end-to-end orchestration: adapter → flow builder → engine → ToC → renderer.
148
+ - `lib/arrolio/generic_adapter.rb` — XML → `Content::Document`, driven by `adapter_rules.yml`.
149
+ - `lib/arrolio/generic_flow_builder.rb` — `Content::Document` → flowables, driven by `flow_rules.yml`.
150
+ - `scripts/xsl_to_config.rb` — generates all three flavor YAML files from an XSL stylesheet.
151
+ - `spec/fixtures/flavors/sample/` — the synthetic flavor-neutral fixture used by the gem's specs.
152
+ - `flavors/oiml/` — the real OIML flavor (generated YAML + upstream XSL); lives outside the gem package.
153
+ - `TODO.complete/README.md` — parity roadmap and critical path.
154
+ - `TODO.implementation/README.md` — foundation phase plan.
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gemspec
6
+
7
+ gem 'pry', '~> 0.14'
8
+ gem 'rake', '~> 13.0'
9
+ gem 'rspec', '~> 3.13'
10
+ gem 'rubocop', '~> 1.75'
11
+ gem 'rubocop-performance', '~> 1.23'
12
+ gem 'rubocop-rake', '~> 0.7'
13
+ gem 'rubocop-rspec', '~> 3.5'
14
+
15
+ gem 'rexml'
data/LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ BSD 2-Clause License
2
+
3
+ Copyright (c) 2026, Ribose Inc.
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.adoc ADDED
@@ -0,0 +1,95 @@
1
+ = Arrolio
2
+
3
+ FOP-like paged layout engine for Ruby. Renders to PDF via the sibling
4
+ https://github.com/claricle/pdfrb[pdfrb] gem.
5
+
6
+ == What this is
7
+
8
+ Arrolio is the middle layer of a three-library stack:
9
+
10
+ [cols="1,4,3"]
11
+ |===
12
+ | Library | Owns | Depends on
13
+
14
+ | `pdfrb`
15
+ | Pure-Ruby PDF library (bytes ↔ model; streams, fonts, xref, encryption)
16
+ | —
17
+
18
+ | `arrolio` (this gem)
19
+ | FOP-like paged layout: page templates, threaded flows, Knuth-Plass
20
+ line/page breaking, tables, lists, SVG, page-model selection,
21
+ running headers/footers
22
+ | `pdfrb`
23
+
24
+ | `loom` (separate gem, not yet built)
25
+ | Multi-target layout compiler. Compiles a higher-level DSL to
26
+ Arrolio's IR, plus CSS, XSL-FO, and IDML.
27
+ | `arrolio` (for the PDF target only)
28
+ |===
29
+
30
+ Arrolio's job: take a content tree plus a layout spec, produce a
31
+ sequence of laid-out pages, render those to PDF (or, in future, to
32
+ other paged formats).
33
+
34
+ == Two-direction contract
35
+
36
+ * *Content + LayoutSpec → Arrolio::Engine::Paged → Output::Page[]*
37
+ (the layout pass).
38
+ * *Output::Page[] → Arrolio::Renderer::Pdf → bytes*
39
+ (the render pass; uses Pdfrb internally).
40
+
41
+ == Quick start
42
+
43
+ [source,ruby]
44
+ ----
45
+ require "arrolio"
46
+
47
+ content = Arrolio::Content::Document.new
48
+ content.add_section("Introduction", level: 1) do |section|
49
+ section.add_paragraph("Hello, World!")
50
+ end
51
+
52
+ layout = Arrolio::LayoutSpec.new
53
+ layout.add_page_template(:body, page_size: :A4, margins: 25)
54
+ layout.add_style(:body, font: "Times-Roman", size: 11)
55
+
56
+ engine = Arrolio::Engine::Paged.new(layout)
57
+ pages = engine.layout(content)
58
+ renderer = Arrolio::Renderer::Pdf.new
59
+
60
+ File.binwrite("out.pdf", renderer.render(pages))
61
+ ----
62
+
63
+ Higher-level convenience API:
64
+
65
+ [source,ruby]
66
+ ----
67
+ Arrolio.compose("out.pdf") do |doc|
68
+ doc.page_size = :A4
69
+ doc.margins = 25
70
+ doc.heading "Introduction"
71
+ doc.text "Hello, World!"
72
+ end
73
+ ----
74
+
75
+ == Where Arrolio's responsibilities end
76
+
77
+ Arrolio deliberately does *not* own:
78
+
79
+ * *PDF byte format* — that's Pdfrb's job.
80
+ * *DSL authoring* (YAML, FO XML, etc.) — that's Loom's job.
81
+ * *Multi-target compilation* (CSS / XSL-FO / IDML) — Loom.
82
+ * *The semantic content model* — that's
83
+ https://github.com/metanorma/metanorma-document[metanorma-document]
84
+ (or any conforming source). Arrolio defines a *contract*, not an
85
+ implementation.
86
+
87
+ == Status
88
+
89
+ Pre-1.0. The skeleton lands first; modules port incrementally from
90
+ `Pdfrb::Layout::*` (which will eventually be removed from Pdfrb once
91
+ Arrolio is stable).
92
+
93
+ == License
94
+
95
+ BSD-2-Clause. See link:LICENSE[].
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+ require 'rubocop/rake_task'
6
+
7
+ RSpec::Core::RakeTask.new(:spec)
8
+ RuboCop::RakeTask.new
9
+
10
+ task default: [:spec, :rubocop]
11
+
12
+ namespace :flavor do
13
+ GENERATOR = File.expand_path('scripts/xsl_to_config.rb', __dir__)
14
+
15
+ desc 'Regenerate flavor config from an XSL stylesheet (XSL=, OUT=)'
16
+ task :generate do
17
+ xsl = ENV.fetch('XSL') { raise 'Set XSL= to the stylesheet path' }
18
+ out = ENV.fetch('OUT') { raise 'Set OUT= to the flavor directory' }
19
+ sh "bundle exec ruby #{GENERATOR} #{File.expand_path(xsl)} #{File.expand_path(out)}"
20
+ end
21
+ end