postsvg 0.1.0 → 0.3.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 (201) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +105 -0
  3. data/CLAUDE.md +173 -0
  4. data/Gemfile +2 -3
  5. data/README.adoc +456 -179
  6. data/Rakefile +100 -0
  7. data/TODO.roadmap/00-architecture.md +139 -0
  8. data/TODO.roadmap/01-autoload-migration.md +39 -0
  9. data/TODO.roadmap/02-isolate-dormant-code.md +51 -0
  10. data/TODO.roadmap/03-domain-model.md +66 -0
  11. data/TODO.roadmap/04-lexer.md +40 -0
  12. data/TODO.roadmap/05-parser.md +43 -0
  13. data/TODO.roadmap/06-graphics-state.md +45 -0
  14. data/TODO.roadmap/07-matrix-and-color.md +37 -0
  15. data/TODO.roadmap/08-svg-builder.md +51 -0
  16. data/TODO.roadmap/09-renderer.md +52 -0
  17. data/TODO.roadmap/10-visitor.md +58 -0
  18. data/TODO.roadmap/11-operator-coverage.md +103 -0
  19. data/TODO.roadmap/12-svg-domain.md +62 -0
  20. data/TODO.roadmap/13-translation-handlers.md +69 -0
  21. data/TODO.roadmap/14-ps-serializer.md +49 -0
  22. data/TODO.roadmap/15-cli-and-public-api.md +47 -0
  23. data/TODO.roadmap/16-specs.md +84 -0
  24. data/TODO.roadmap/17-docs-sync.md +47 -0
  25. data/TODO.roadmap/18-performance-and-determinism.md +47 -0
  26. data/TODO.roadmap/19-error-model.md +45 -0
  27. data/TODO.roadmap/20-font-and-text.md +46 -0
  28. data/TODO.roadmap/21-images.md +45 -0
  29. data/TODO.roadmap/22-forms-and-resources.md +25 -0
  30. data/TODO.roadmap/23-level2-level3.md +52 -0
  31. data/TODO.roadmap/24-ci-and-release.md +42 -0
  32. data/TODO.roadmap/README.md +77 -0
  33. data/docs/.gitignore +29 -0
  34. data/docs/CHANGELOG.md +114 -0
  35. data/docs/COMPLETE_DOCUMENTATION_STATUS.md +376 -0
  36. data/docs/DEPLOYMENT.md +456 -0
  37. data/docs/DEPLOYMENT_INSTRUCTIONS.md +229 -0
  38. data/docs/DOCUMENTATION_PLAN.md +425 -0
  39. data/docs/FINAL_SUMMARY.md +657 -0
  40. data/docs/Gemfile +15 -0
  41. data/docs/README.md +327 -0
  42. data/docs/_config.yml +99 -0
  43. data/docs/advanced-topics.adoc +370 -0
  44. data/docs/api-reference/colors.adoc +705 -0
  45. data/docs/api-reference/converter.adoc +699 -0
  46. data/docs/api-reference/execution-context.adoc +1210 -0
  47. data/docs/api-reference/graphics-state.adoc +1070 -0
  48. data/docs/api-reference/interpreter.adoc +810 -0
  49. data/docs/api-reference/matrix.adoc +1179 -0
  50. data/docs/api-reference/path-builder.adoc +1284 -0
  51. data/docs/api-reference/postsvg-module.adoc +388 -0
  52. data/docs/api-reference/svg-generator.adoc +891 -0
  53. data/docs/api-reference/tokenizer.adoc +925 -0
  54. data/docs/api-reference.adoc +221 -0
  55. data/docs/architecture/command-registry.adoc +1191 -0
  56. data/docs/architecture/conversion-pipeline.adoc +746 -0
  57. data/docs/architecture/design-decisions.adoc +999 -0
  58. data/docs/architecture/generator-stage.adoc +1115 -0
  59. data/docs/architecture/graphics-state-model.adoc +1089 -0
  60. data/docs/architecture/interpreter-stage.adoc +1125 -0
  61. data/docs/architecture/parser-stage.adoc +1051 -0
  62. data/docs/architecture.adoc +354 -0
  63. data/docs/cli-reference/batch-command.adoc +616 -0
  64. data/docs/cli-reference/check-command.adoc +677 -0
  65. data/docs/cli-reference/cli-options.adoc +802 -0
  66. data/docs/cli-reference/convert-command.adoc +462 -0
  67. data/docs/cli-reference/version-command.adoc +296 -0
  68. data/docs/cli-reference.adoc +317 -0
  69. data/docs/concepts/conversion-pipeline.adoc +903 -0
  70. data/docs/concepts/coordinate-systems.adoc +836 -0
  71. data/docs/concepts/graphics-state.adoc +861 -0
  72. data/docs/concepts/path-operations.adoc +1076 -0
  73. data/docs/concepts/postscript-language.adoc +859 -0
  74. data/docs/concepts/svg-generation.adoc +937 -0
  75. data/docs/concepts.adoc +198 -0
  76. data/docs/contributing.adoc +443 -0
  77. data/docs/development.adoc +420 -0
  78. data/docs/faq.adoc +493 -0
  79. data/docs/getting-started/basic-usage.adoc +538 -0
  80. data/docs/getting-started/common-workflows.adoc +577 -0
  81. data/docs/getting-started/first-conversion.adoc +492 -0
  82. data/docs/getting-started/installation.adoc +534 -0
  83. data/docs/getting-started.adoc +94 -0
  84. data/docs/index.adoc +248 -0
  85. data/docs/optimization.adoc +196 -0
  86. data/docs/ps2svg_compatibility.adoc +149 -0
  87. data/docs/quick-reference.adoc +453 -0
  88. data/docs/sitemap.adoc +337 -0
  89. data/docs/troubleshooting.adoc +486 -0
  90. data/docs/validation.adoc +772 -0
  91. data/exe/postsvg +1 -0
  92. data/lib/postsvg/cli.rb +104 -57
  93. data/lib/postsvg/color.rb +132 -0
  94. data/lib/postsvg/errors.rb +68 -3
  95. data/lib/postsvg/format_number.rb +22 -0
  96. data/lib/postsvg/graphics_context.rb +80 -0
  97. data/lib/postsvg/graphics_stack.rb +43 -0
  98. data/lib/postsvg/model/literals/array.rb +41 -0
  99. data/lib/postsvg/model/literals/dictionary.rb +34 -0
  100. data/lib/postsvg/model/literals/hex.rb +37 -0
  101. data/lib/postsvg/model/literals/name.rb +40 -0
  102. data/lib/postsvg/model/literals/number.rb +36 -0
  103. data/lib/postsvg/model/literals/procedure.rb +41 -0
  104. data/lib/postsvg/model/literals/string.rb +30 -0
  105. data/lib/postsvg/model/literals.rb +19 -0
  106. data/lib/postsvg/model/operator.rb +58 -0
  107. data/lib/postsvg/model/operators/arithmetic.rb +264 -0
  108. data/lib/postsvg/model/operators/boolean.rb +182 -0
  109. data/lib/postsvg/model/operators/color.rb +74 -0
  110. data/lib/postsvg/model/operators/container.rb +186 -0
  111. data/lib/postsvg/model/operators/control_flow.rb +119 -0
  112. data/lib/postsvg/model/operators/device.rb +21 -0
  113. data/lib/postsvg/model/operators/dictionary.rb +118 -0
  114. data/lib/postsvg/model/operators/font.rb +121 -0
  115. data/lib/postsvg/model/operators/graphics_state.rb +84 -0
  116. data/lib/postsvg/model/operators/painting.rb +29 -0
  117. data/lib/postsvg/model/operators/path.rb +169 -0
  118. data/lib/postsvg/model/operators/stack.rb +72 -0
  119. data/lib/postsvg/model/operators/transformations.rb +103 -0
  120. data/lib/postsvg/model/operators.rb +89 -0
  121. data/lib/postsvg/model/program.rb +68 -0
  122. data/lib/postsvg/model/token.rb +43 -0
  123. data/lib/postsvg/model.rb +17 -0
  124. data/lib/postsvg/options.rb +29 -0
  125. data/lib/postsvg/renderer.rb +85 -0
  126. data/lib/postsvg/serializer.rb +325 -0
  127. data/lib/postsvg/source/ast_builder.rb +308 -0
  128. data/lib/postsvg/source/lexer.rb +322 -0
  129. data/lib/postsvg/source/operand_stack.rb +55 -0
  130. data/lib/postsvg/source.rb +21 -0
  131. data/lib/postsvg/svg/attribute_parser.rb +45 -0
  132. data/lib/postsvg/svg/clip_path_registry.rb +44 -0
  133. data/lib/postsvg/svg/document.rb +22 -0
  134. data/lib/postsvg/svg/element.rb +84 -0
  135. data/lib/postsvg/svg/elements/circle.rb +36 -0
  136. data/lib/postsvg/svg/elements/clip_path.rb +26 -0
  137. data/lib/postsvg/svg/elements/defs.rb +24 -0
  138. data/lib/postsvg/svg/elements/ellipse.rb +38 -0
  139. data/lib/postsvg/svg/elements/group.rb +37 -0
  140. data/lib/postsvg/svg/elements/image.rb +35 -0
  141. data/lib/postsvg/svg/elements/line.rb +36 -0
  142. data/lib/postsvg/svg/elements/path.rb +32 -0
  143. data/lib/postsvg/svg/elements/polygon.rb +12 -0
  144. data/lib/postsvg/svg/elements/polyline.rb +32 -0
  145. data/lib/postsvg/svg/elements/rect.rb +44 -0
  146. data/lib/postsvg/svg/elements/svg.rb +39 -0
  147. data/lib/postsvg/svg/elements/text.rb +42 -0
  148. data/lib/postsvg/svg/elements.rb +31 -0
  149. data/lib/postsvg/svg/paint.rb +34 -0
  150. data/lib/postsvg/svg/parser.rb +39 -0
  151. data/lib/postsvg/svg/path_data/command.rb +27 -0
  152. data/lib/postsvg/svg/path_data/parser.rb +82 -0
  153. data/lib/postsvg/svg/path_data.rb +17 -0
  154. data/lib/postsvg/svg/stroke.rb +31 -0
  155. data/lib/postsvg/svg/transform_list.rb +59 -0
  156. data/lib/postsvg/svg.rb +22 -0
  157. data/lib/postsvg/svg_builder.rb +249 -0
  158. data/lib/postsvg/translation/arc_converter.rb +86 -0
  159. data/lib/postsvg/translation/bounding_box.rb +59 -0
  160. data/lib/postsvg/translation/context.rb +34 -0
  161. data/lib/postsvg/translation/handler_registry.rb +38 -0
  162. data/lib/postsvg/translation/handlers/circle_handler.rb +28 -0
  163. data/lib/postsvg/translation/handlers/clip_path_handler.rb +13 -0
  164. data/lib/postsvg/translation/handlers/defs_handler.rb +15 -0
  165. data/lib/postsvg/translation/handlers/ellipse_handler.rb +31 -0
  166. data/lib/postsvg/translation/handlers/group_handler.rb +21 -0
  167. data/lib/postsvg/translation/handlers/image_handler.rb +20 -0
  168. data/lib/postsvg/translation/handlers/line_handler.rb +23 -0
  169. data/lib/postsvg/translation/handlers/open_handler.rb +18 -0
  170. data/lib/postsvg/translation/handlers/path_handler.rb +356 -0
  171. data/lib/postsvg/translation/handlers/polygon_handler.rb +33 -0
  172. data/lib/postsvg/translation/handlers/polyline_handler.rb +31 -0
  173. data/lib/postsvg/translation/handlers/rect_handler.rb +27 -0
  174. data/lib/postsvg/translation/handlers/shared.rb +110 -0
  175. data/lib/postsvg/translation/handlers/svg_handler.rb +25 -0
  176. data/lib/postsvg/translation/handlers/text_handler.rb +56 -0
  177. data/lib/postsvg/translation/handlers.rb +25 -0
  178. data/lib/postsvg/translation/ps_renderer.rb +105 -0
  179. data/lib/postsvg/translation/record_emitter.rb +35 -0
  180. data/lib/postsvg/translation.rb +17 -0
  181. data/lib/postsvg/version.rb +1 -1
  182. data/lib/postsvg/visitors/ps_visitor/arithmetic.rb +125 -0
  183. data/lib/postsvg/visitors/ps_visitor/boolean.rb +105 -0
  184. data/lib/postsvg/visitors/ps_visitor/color.rb +53 -0
  185. data/lib/postsvg/visitors/ps_visitor/common.rb +66 -0
  186. data/lib/postsvg/visitors/ps_visitor/container.rb +164 -0
  187. data/lib/postsvg/visitors/ps_visitor/control_flow.rb +110 -0
  188. data/lib/postsvg/visitors/ps_visitor/device.rb +20 -0
  189. data/lib/postsvg/visitors/ps_visitor/dictionary.rb +89 -0
  190. data/lib/postsvg/visitors/ps_visitor/font.rb +93 -0
  191. data/lib/postsvg/visitors/ps_visitor/graphics_state.rb +55 -0
  192. data/lib/postsvg/visitors/ps_visitor/painting.rb +90 -0
  193. data/lib/postsvg/visitors/ps_visitor/path.rb +112 -0
  194. data/lib/postsvg/visitors/ps_visitor/stack.rb +47 -0
  195. data/lib/postsvg/visitors/ps_visitor/transformations.rb +101 -0
  196. data/lib/postsvg/visitors/ps_visitor.rb +208 -0
  197. data/lib/postsvg/visitors.rb +9 -0
  198. data/lib/postsvg.rb +93 -59
  199. data/lychee.toml +86 -0
  200. metadata +216 -11
  201. data/postsvg.gemspec +0 -38
@@ -0,0 +1,370 @@
1
+ = Advanced Topics
2
+ :page-nav_order: 7
3
+
4
+ == Purpose
5
+
6
+ This section covers advanced Postsvg usage patterns, optimization techniques, and complex scenarios. These topics are intended for users who need to extend Postsvg, integrate it into complex workflows, or handle edge cases.
7
+
8
+ == References
9
+
10
+ * link:index.adoc[Documentation Home]
11
+ * link:api-reference.adoc[API Reference]
12
+ * link:architecture.adoc[Architecture Documentation]
13
+ * link:development.adoc[Development Guide]
14
+
15
+ == Concepts
16
+
17
+ **Strict Mode**:: A validation mode that fails on unknown or unsupported operators.
18
+
19
+ **BoundingBox Handling**:: Extracting and applying document dimensions from PostScript comments.
20
+
21
+ **Custom Operators**:: Extending Postsvg with custom PostScript operator implementations.
22
+
23
+ **Error Recovery**:: Strategies for handling malformed or partially valid PostScript files.
24
+
25
+ **Optimization Techniques**:: Methods for improving conversion performance and output quality.
26
+
27
+ == Advanced Topics
28
+
29
+ link:advanced-topics/custom-operators.adoc[**Custom Operators**]::
30
+ How to extend Postsvg by implementing custom PostScript operators.
31
+
32
+ link:advanced-topics/strict-mode.adoc[**Strict Mode**]::
33
+ Enable strict validation to catch unknown operators and ensure complete PostScript support.
34
+
35
+ link:advanced-topics/bounding-box-handling.adoc[**BoundingBox Handling**]::
36
+ Extract, validate, and apply BoundingBox information for proper SVG dimensions.
37
+
38
+ link:advanced-topics/error-handling.adoc[**Error Handling**]::
39
+ Strategies for handling conversion errors, validation failures, and partial conversions.
40
+
41
+ link:advanced-topics/memory-considerations.adoc[**Memory Considerations**]::
42
+ Handling large PostScript files, memory optimization, and batch processing strategies.
43
+
44
+ link:advanced-topics/compatibility.adoc[**ps2svg Compatibility**]::
45
+ Compatibility notes, differences, and migration guide from ps2svg.
46
+
47
+ == Strict Mode
48
+
49
+ Strict mode causes Postsvg to fail immediately when encountering unknown operators:
50
+
51
+ [source,ruby]
52
+ ----
53
+ # Enable strict mode
54
+ converter = Postsvg::Converter.new(
55
+ ps_content,
56
+ strict_mode: true
57
+ )
58
+
59
+ begin
60
+ svg = converter.convert
61
+ rescue Postsvg::Error => e
62
+ puts "Unknown operator: #{e.message}"
63
+ end
64
+ ----
65
+
66
+ **Use Cases:**
67
+ * Development and testing
68
+ * Ensuring complete PostScript support
69
+ * Validating operator coverage
70
+ * Debugging conversion issues
71
+
72
+ **Trade-offs:**
73
+ * May fail on harmless unsupported operators
74
+ * More verbose error handling required
75
+ * Not suitable for production with varied input
76
+
77
+ == Custom Operator Implementation
78
+
79
+ .Implementing a custom operator
80
+ [example]
81
+ ====
82
+ [source,ruby]
83
+ ----
84
+ module Postsvg
85
+ module Commands
86
+ class CustomRect < Base
87
+ def execute(context)
88
+ # Pop arguments: width height x y
89
+ height = context.pop_number
90
+ width = context.pop_number
91
+ y = context.pop_number
92
+ x = context.pop_number
93
+
94
+ # Draw rectangle using existing operators
95
+ context.graphics_state.newpath
96
+ context.graphics_state.moveto(x, y)
97
+ context.graphics_state.lineto(x + width, y)
98
+ context.graphics_state.lineto(x + width, y + height)
99
+ context.graphics_state.lineto(x, y + height)
100
+ context.graphics_state.closepath
101
+ end
102
+ end
103
+ end
104
+ end
105
+
106
+ # Register custom operator
107
+ Postsvg::Commands::Registry.register('customrect',
108
+ Postsvg::Commands::CustomRect.new)
109
+ ----
110
+
111
+ This implements a `customrect` operator that takes four arguments (x, y, width, height) and constructs a rectangular path.
112
+ ====
113
+
114
+ == BoundingBox Extraction
115
+
116
+ PostScript files may contain BoundingBox comments in different formats:
117
+
118
+ [source,postscript]
119
+ ----
120
+ %%BoundingBox: 0 0 612 792 # Standard
121
+ %%BoundingBox: (atend) # Deferred
122
+ %%HiResBoundingBox: 0 0 612.5 792.5 # High resolution
123
+ ----
124
+
125
+ Postsvg handles BoundingBox extraction:
126
+
127
+ [source,ruby]
128
+ ----
129
+ # Automatic extraction
130
+ converter = Postsvg::Converter.new(ps_content)
131
+ svg = converter.convert # Uses extracted BoundingBox
132
+
133
+ # Manual override
134
+ bbox = { llx: 0, lly: 0, urx: 100, ury: 100,
135
+ width: 100, height: 100 }
136
+ interpreter = Postsvg::Interpreter.new
137
+ result = interpreter.interpret(tokens, bbox)
138
+ ----
139
+
140
+ **Fallback Behavior:**
141
+ If no BoundingBox is found, Postsvg defaults to 1920x1080 (Full HD).
142
+
143
+ == Error Recovery Strategies
144
+
145
+ === Graceful Degradation
146
+
147
+ [source,ruby]
148
+ ----
149
+ def safe_convert(ps_files)
150
+ results = []
151
+
152
+ ps_files.each do |file|
153
+ begin
154
+ # Try strict conversion first
155
+ converter = Postsvg::Converter.new(
156
+ File.read(file),
157
+ strict_mode: true
158
+ )
159
+ svg = converter.convert
160
+ results << { file: file, status: :success, svg: svg }
161
+ rescue Postsvg::Error => e
162
+ # Fall back to lenient mode
163
+ converter = Postsvg::Converter.new(
164
+ File.read(file),
165
+ strict_mode: false
166
+ )
167
+ begin
168
+ svg = converter.convert
169
+ results << {
170
+ file: file,
171
+ status: :partial,
172
+ svg: svg,
173
+ warning: e.message
174
+ }
175
+ rescue StandardError => e2
176
+ results << {
177
+ file: file,
178
+ status: :failed,
179
+ error: e2.message
180
+ }
181
+ end
182
+ end
183
+ end
184
+
185
+ results
186
+ end
187
+ ----
188
+
189
+ === Validation Before Conversion
190
+
191
+ [source,ruby]
192
+ ----
193
+ require 'postsvg'
194
+
195
+ # Validate first
196
+ validation = Postsvg::Services::ValidationService.new(
197
+ ps_content,
198
+ 'file.ps',
199
+ level: :semantic
200
+ )
201
+
202
+ result = validation.validate
203
+
204
+ if result.valid?
205
+ # Safe to convert
206
+ svg = Postsvg.convert(ps_content)
207
+ else
208
+ # Handle errors
209
+ puts "Validation errors:"
210
+ result.errors.each { |e| puts " - #{e}" }
211
+ end
212
+ ----
213
+
214
+ == Memory Optimization
215
+
216
+ For large files or batch processing:
217
+
218
+ === Streaming Approach
219
+
220
+ [source,ruby]
221
+ ----
222
+ # Process files one at a time
223
+ Dir.glob('*.ps').each do |file|
224
+ ps_content = File.read(file)
225
+ svg = Postsvg.convert(ps_content)
226
+ File.write(file.sub('.ps', '.svg'), svg)
227
+
228
+ # Explicitly clear
229
+ ps_content = nil
230
+ svg = nil
231
+ GC.start
232
+ end
233
+ ----
234
+
235
+ === Batch Size Limiting
236
+
237
+ [source,ruby]
238
+ ----
239
+ # Process in batches
240
+ files = Dir.glob('*.ps')
241
+ batch_size = 10
242
+
243
+ files.each_slice(batch_size) do |batch|
244
+ threads = batch.map do |file|
245
+ Thread.new do
246
+ Postsvg.convert_file(file, file.sub('.ps', '.svg'))
247
+ end
248
+ end
249
+
250
+ threads.each(&:join)
251
+ GC.start # Clean up between batches
252
+ end
253
+ ----
254
+
255
+ == Advanced Validation
256
+
257
+ === Custom Validation Rules
258
+
259
+ [source,ruby]
260
+ ----
261
+ # Validate specific features
262
+ class CustomValidator
263
+ def initialize(ps_content)
264
+ @content = ps_content
265
+ end
266
+
267
+ def validate_encoding
268
+ # Check for specific encoding
269
+ @content.match?(/%!PS-Adobe-3\.0/)
270
+ end
271
+
272
+ def validate_fonts
273
+ # Ensure no font operations
274
+ !@content.match?(/\b(findfont|setfont|show)\b/)
275
+ end
276
+
277
+ def validate_images
278
+ # Ensure no image operations
279
+ !@content.match?(/\b(image|imagemask)\b/)
280
+ end
281
+ end
282
+
283
+ validator = CustomValidator.new(ps_content)
284
+ puts "Valid encoding: #{validator.validate_encoding}"
285
+ puts "No fonts: #{validator.validate_fonts}"
286
+ puts "No images: #{validator.validate_images}"
287
+ ----
288
+
289
+ == Performance Profiling
290
+
291
+ [source,ruby]
292
+ ----
293
+ require 'benchmark'
294
+ require 'postsvg'
295
+
296
+ ps_content = File.read('large_file.ps')
297
+
298
+ time = Benchmark.measure do
299
+ svg = Postsvg.convert(ps_content)
300
+ end
301
+
302
+ puts "Conversion time: #{time.real}s"
303
+ puts "Memory used: #{GC.stat[:total_allocated_objects]} objects"
304
+ ----
305
+
306
+ == Integration Patterns
307
+
308
+ === Rails Integration
309
+
310
+ [source,ruby]
311
+ ----
312
+ # app/services/postscript_converter.rb
313
+ class PostscriptConverter
314
+ def self.convert(uploaded_file)
315
+ ps_content = uploaded_file.read
316
+
317
+ svg = Postsvg.convert(ps_content)
318
+
319
+ # Store SVG
320
+ svg_file = Tempfile.new(['converted', '.svg'])
321
+ svg_file.write(svg)
322
+ svg_file.rewind
323
+
324
+ svg_file
325
+ end
326
+ end
327
+
328
+ # In controller
329
+ class DocumentsController < ApplicationController
330
+ def convert
331
+ ps_file = params[:file]
332
+ svg_file = PostscriptConverter.convert(ps_file)
333
+
334
+ send_file svg_file.path,
335
+ filename: 'converted.svg',
336
+ type: 'image/svg+xml'
337
+ end
338
+ end
339
+ ----
340
+
341
+ === Rake Task Integration
342
+
343
+ [source,ruby]
344
+ ----
345
+ # lib/tasks/convert.rake
346
+ namespace :postscript do
347
+ desc "Convert all PS files to SVG"
348
+ task :convert => :environment do
349
+ Dir.glob(Rails.root.join('public', 'ps', '*.ps')).each do |file|
350
+ output = file.sub('.ps', '.svg')
351
+ Postsvg.convert_file(file, output)
352
+ puts "Converted #{File.basename(file)}"
353
+ end
354
+ end
355
+ end
356
+ ----
357
+
358
+ == Next Steps
359
+
360
+ * Explore link:development.adoc[Development Guide] for extending Postsvg
361
+ * Review link:architecture.adoc[Architecture] for implementation details
362
+ * Check link:troubleshooting.adoc[Troubleshooting] for common issues
363
+ * See link:api-reference.adoc[API Reference] for detailed method documentation
364
+
365
+ == Bibliography
366
+
367
+ * link:advanced-topics/custom-operators.adoc[Custom Operators Guide]
368
+ * link:advanced-topics/strict-mode.adoc[Strict Mode Documentation]
369
+ * link:advanced-topics/error-handling.adoc[Error Handling Strategies]
370
+ * link:https://www.adobe.com/products/postscript/pdfs/PLRM.pdf[PostScript Language Reference]