metanorma-plugin-plantuml 1.0.1 → 1.0.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 07e9ee8fdf5e99900198be1e8ea51dd948957c62475694b0b40660fd25bff4d2
4
- data.tar.gz: c6b49a7ec9b20d96e45c6600f2a368c3b5df542e6ee3bcc3f75ed17dd7d929bc
3
+ metadata.gz: 3b3797ddb4db236753261836d74b360e635c58ea3b0eeaa09dfc1c7192dacf78
4
+ data.tar.gz: 0aba3ecbbc90f15570887ea206fa0a0c19b6d3179a7d9481438fb480df305873
5
5
  SHA512:
6
- metadata.gz: f9903747e63488c1af15f954441acbdaaa17c715935b1d0d390d515173f5e052df6defc0828de335e6491e019c69b9fa915365850a91a91155e5d68e3ee60376
7
- data.tar.gz: 73e6bac1cfc02b057d52eb39913bfb833f0b70237fb8d00323424ef17a6b5ea302baf57faae486dda1779f0254035a4b449e0abb9648c21ceb18e30a39234778
6
+ metadata.gz: ed86eced1c2c434f17ce4f3f5307c88f349c30275ad2051ea7c6063feb1d13ca6c64480ea406951221a75ceececd035ffed82519d9dfe169205f55a160996c9b
7
+ data.tar.gz: 2e1488a69e6c3ff71a88c17778fead0b264ed2b6c8d2a7d8803e04441d0d7f1b4b2cebdd102050e6428500a477a876d6f3cc8cdf9882da007a7bc6900a19cffa
data/Gemfile CHANGED
@@ -17,7 +17,7 @@ gem "canon"
17
17
  gem "debug"
18
18
  gem "metanorma"
19
19
  gem "metanorma-standoc", github: "metanorma/metanorma-standoc",
20
- branch: "feature/extract-plantuml"
20
+ branch: "main"
21
21
  gem "rake"
22
22
  gem "rspec"
23
23
  gem "rspec-html-matchers"
data/README.adoc CHANGED
@@ -65,6 +65,8 @@ the `plantuml` block directive.
65
65
 
66
66
  === Basic syntax
67
67
 
68
+ ==== Block style
69
+
68
70
  [source,asciidoc]
69
71
  ----
70
72
  [plantuml]
@@ -76,6 +78,25 @@ Bob -> Alice: Hi there
76
78
  ....
77
79
  ----
78
80
 
81
+ ==== Block macro style
82
+
83
+ [source,asciidoc]
84
+ ----
85
+ plantuml_image::path/to/my-plantuml.puml[]
86
+ ----
87
+
88
+ The file `path/to/my-plantuml.puml` looks like:
89
+ [source,plantuml]
90
+ ----
91
+ @startuml
92
+ Alice -> Bob: Hello
93
+ Bob -> Alice: Hi there
94
+ @enduml
95
+ ----
96
+
97
+ `plantuml_image` block macro performs the same function as the `plantuml` block,
98
+ but the PlantUML diagram is defined in a separate file instead of a block.
99
+
79
100
  === Supported diagram types
80
101
 
81
102
  PlantUML supports various diagram types, each with its own `@start` and `@end` directives:
@@ -183,6 +204,132 @@ Alice -> Bob: Hello
183
204
  ....
184
205
  ----
185
206
 
207
+ ==== Document-level includedirs configuration
208
+
209
+ When using `!include` or `!includesub` in your PlantUML diagrams, you can set
210
+ the default include directories (separated by semicolons) by
211
+ `plantuml-includedirs` to search for files for all PlantUML diagrams in your
212
+ document:
213
+
214
+ [source,asciidoc]
215
+ ----
216
+ :plantuml-includedirs: path/to/plantuml/include-1;path/to/plantuml/include-2
217
+
218
+ [plantuml]
219
+ ....
220
+ @startuml
221
+ !include sequences.puml!1
222
+ @enduml
223
+ ....
224
+
225
+ [plantuml]
226
+ ....
227
+ @startuml
228
+ !include components.puml!FRONTEND
229
+ !include components.puml!BACKEND
230
+
231
+ WebApp --> APIGateway
232
+ MobileApp --> APIGateway
233
+ APIGateway --> DB
234
+ @enduml
235
+ ....
236
+
237
+ [plantuml]
238
+ ....
239
+ @startuml
240
+ title this contains only B and D
241
+ !includesub subpart.puml!BASIC
242
+ @enduml
243
+ ....
244
+ ----
245
+
246
+ This plugin will search the include directories specified by
247
+ `includedirs` options (i.e. `path/to/plantuml/include-1` and
248
+ `path/to/plantuml/include-2`) for the files referenced in `!include` or
249
+ `!includesub` directives (i.e. `sequences.puml`, `components.puml` and
250
+ `subpart.puml`).
251
+
252
+ You can also use `plantuml_image` to include external PlantUML files as images:
253
+
254
+ [source,asciidoc]
255
+ ----
256
+ :plantuml-includedirs: path/to/plantuml/include-1;path/to/plantuml/include-2
257
+
258
+ plantuml_image::path/to/my-plantuml-1.puml[]
259
+
260
+ plantuml_image::path/to/my-plantuml-2.puml[]
261
+ ----
262
+
263
+ The file `path/to/my-plantuml-1.puml` looks like:
264
+ [source,plantuml]
265
+ ----
266
+ @startuml
267
+ !include sequences.puml!1
268
+ @enduml
269
+ ----
270
+
271
+ The file `path/to/my-plantuml-2.puml` looks like:
272
+ [source,plantuml]
273
+ ----
274
+ @startuml
275
+ !include components.puml!FRONTEND
276
+ !include components.puml!BACKEND
277
+
278
+ WebApp --> APIGateway
279
+ MobileApp --> APIGateway
280
+ APIGateway --> DB
281
+ @enduml
282
+ ----
283
+
284
+ When using `plantuml_image`, the path of the directory of the PlantUML file will
285
+ also be added into the `includedirs`. (i.e. `path/to` will be added to
286
+ `includedirs`)
287
+
288
+ ==== Block-level includedirs configuration
289
+
290
+ When using `!include` or `!includesub` in your PlantUML diagrams, you can set
291
+ the default include directories (separated by semicolons) by `includedirs` in
292
+ block-level to search for files for the PlantUML diagram defined in your block:
293
+
294
+ [source,asciidoc]
295
+ ----
296
+ [plantuml,includedirs="path/to/plantuml/include-1"]
297
+ ....
298
+ @startuml
299
+ !include sequences.puml!1
300
+ @enduml
301
+ ....
302
+
303
+ [plantuml,includedirs="path/to/plantuml/include-2"]
304
+ ....
305
+ @startuml
306
+ !include components.puml!FRONTEND
307
+ !include components.puml!BACKEND
308
+
309
+ WebApp --> APIGateway
310
+ MobileApp --> APIGateway
311
+ APIGateway --> DB
312
+ @enduml
313
+ ....
314
+ ----
315
+
316
+ This plugin will search `sequences.puml` in `path/to/plantuml/include-1` and
317
+ `components.puml` in `path/to/plantuml/include-2`.
318
+
319
+ The block-level `includedirs` configuration can be used together with the
320
+ document-level configuration to provide more granular control over include
321
+ paths. You can set multiple paths by separating them with semicolons.
322
+
323
+ You can also use `plantuml_image` to set `includedirs` option to include
324
+ external PlantUML files:
325
+
326
+ [source,asciidoc]
327
+ ----
328
+ plantuml_image::path/to/my-plantuml-1.puml[includedirs=path/to/plantuml/include-1]
329
+
330
+ plantuml_image::path/to/my-plantuml-2.puml[includedirs=path/to/plantuml/include-2]
331
+ ----
332
+
186
333
  === Image attributes
187
334
 
188
335
  Standard AsciiDoc image attributes are supported:
@@ -272,7 +419,7 @@ Metanorma integration and PlantUML execution:
272
419
  ----
273
420
  Metanorma Document
274
421
 
275
- BlockProcessor ← (processes [plantuml] blocks)
422
+ BlockProcessor ← (processes [plantuml] blocks) or ImageBlockMacroProcessor ← (processes plantuml_image::{path}[{options}] macros)
276
423
 
277
424
  Backend ← (Metanorma integration, paths, validation)
278
425
 
@@ -284,6 +431,9 @@ PlantUML JAR ← (diagram generation)
284
431
  `BlockProcessor`:: Processes `[plantuml]` blocks in Metanorma documents and
285
432
  integrates with the Metanorma rendering pipeline.
286
433
 
434
+ `ImageBlockMacroProcessor`:: Processes `plantuml_image::{path}[{options}]` macros
435
+ in Metanorma documents and integrates with the Metanorma rendering pipeline.
436
+
287
437
  `Backend`:: Handles Metanorma-specific logic including document paths, PlantUML
288
438
  source validation, filename extraction, and attribute mapping.
289
439
 
@@ -14,19 +14,21 @@ module Metanorma
14
14
  class Backend
15
15
  class << self
16
16
  def plantuml_installed?
17
- unless Wrapper.available?
18
- raise "PlantUML not installed"
19
- end
17
+ return true if plantuml_available?
18
+
19
+ raise "PlantUML not installed"
20
20
  end
21
21
 
22
22
  def plantuml_available?
23
23
  Wrapper.available?
24
24
  end
25
25
 
26
- def generate_file(parent, reader, format_override = nil) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
26
+ def generate_file( # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
27
+ parent, reader, format_override: nil, options: {}
28
+ )
27
29
  ldir, imagesdir, fmt = generate_file_prep(parent)
28
30
  fmt = format_override if format_override
29
- plantuml_content = prep_source(reader)
31
+ plantuml_content = prep_source(parent, reader)
30
32
 
31
33
  # Extract filename from PlantUML source if specified
32
34
  filename = generate_unique_filename(fmt)
@@ -43,6 +45,7 @@ module Metanorma
43
45
  plantuml_content,
44
46
  format: fmt,
45
47
  output_file: output_file,
48
+ includedirs: options[:includedirs],
46
49
  )
47
50
 
48
51
  unless result[:success]
@@ -52,10 +55,12 @@ module Metanorma
52
55
  File.join(relative_path, filename)
53
56
  end
54
57
 
55
- def generate_multiple_files(parent, reader, formats, attrs)
58
+ def generate_multiple_files(
59
+ parent, reader, formats, attrs, options: {}
60
+ )
56
61
  # Generate files for each format
57
62
  filenames = formats.map do |format|
58
- generate_file(parent, reader, format)
63
+ generate_file(parent, reader, format, options: options)
59
64
  end
60
65
 
61
66
  # Return data for BlockProcessor to create image block
@@ -72,8 +77,9 @@ module Metanorma
72
77
  def generate_file_prep(parent)
73
78
  ldir = localdir(parent)
74
79
  imagesdir = parent.document.attr("imagesdir")
75
- fmt = parent
76
- .document.attr("plantuml-image-format")&.strip&.downcase || "png"
80
+ fmt = parent.document
81
+ .attr("plantuml-image-format")&.strip&.downcase ||
82
+ Wrapper::DEFAULT_FORMAT
77
83
  [ldir, imagesdir, fmt]
78
84
  end
79
85
 
@@ -100,8 +106,15 @@ module Metanorma
100
106
  ]
101
107
  end
102
108
 
103
- def prep_source(reader)
104
- src = reader.source
109
+ def prep_source(parent, reader) # rubocop:disable Metrics/MethodLength
110
+ src = if reader.respond_to?(:source)
111
+ # get content from BlockProcessor
112
+ reader.source
113
+ else
114
+ # get content from ImageBlockMacroProcessor
115
+ docdir = parent.document.attributes["docdir"]
116
+ File.read(File.join(docdir, reader))
117
+ end
105
118
 
106
119
  # Validate that we have matching start/end pairs
107
120
  validate_plantuml_delimiters(src)
@@ -1,29 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "asciidoctor"
4
- require "asciidoctor/extensions"
5
- require_relative "backend"
6
-
7
3
  module Metanorma
8
4
  module Plugin
9
5
  module Plantuml
10
6
  # PlantUML block processor for Asciidoctor
11
7
  class BlockProcessor < ::Asciidoctor::Extensions::BlockProcessor
8
+ include ::Metanorma::Plugin::Plantuml::BlockProcessorBase
12
9
  use_dsl
13
10
  named :plantuml
14
11
  on_context :literal
15
12
  parse_content_as :raw
16
13
 
17
- def abort(parent, reader, attrs, msg)
18
- warn msg
19
- attrs["language"] = "plantuml"
20
- create_listing_block(
21
- parent,
22
- reader.source,
23
- attrs.reject { |k, _v| k.to_s.match?(/^\d+$/) },
24
- )
25
- end
26
-
27
14
  def process(parent, reader, attrs) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
28
15
  # Check for document-level disable flag
29
16
  if parent.document.attr("plantuml-disabled")
@@ -37,45 +24,25 @@ module Metanorma
37
24
 
38
25
  # Parse format specifications
39
26
  formats = parse_formats(attrs, parent.document)
27
+ options = parse_options(parent, reader, attrs)
40
28
 
41
- if formats.length == 1
42
- # Single format - original behavior
43
- filename = Backend.generate_file(parent, reader, formats.first)
44
- through_attrs = Backend.generate_attrs(attrs)
45
- through_attrs["target"] = filename
46
- else
47
- # Multiple formats - generate multiple files
48
- through_attrs = Backend
49
- .generate_multiple_files(parent, reader, formats, attrs)
50
- end
51
- create_image_block parent, through_attrs
29
+ process_image_block(parent, reader, attrs, formats, options)
52
30
  rescue StandardError => e
53
31
  abort(parent, reader, attrs, e.message)
54
32
  end
55
33
 
56
34
  private
57
35
 
58
- def parse_formats(attrs, document) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize, Metrics/MethodLength
59
- # Check for formats attribute (multiple formats)
60
- if attrs["formats"]
61
- formats = attrs["formats"].split(",").map(&:strip).map(&:downcase)
62
- return formats.select { |f| valid_format?(f) }
63
- end
64
-
65
- # Check for format attribute (single format override)
66
- if attrs["format"]
67
- format = attrs["format"].strip.downcase
68
- return [format] if valid_format?(format)
69
- end
36
+ def parse_options(parent, _reader, attrs)
37
+ options = {}
70
38
 
71
- # Fall back to document attribute or default
72
- default_format = document
73
- .attr("plantuml-image-format")&.strip&.downcase || "png"
74
- [default_format]
75
- end
39
+ # Parse include directory
40
+ options[:includedirs] = parse_doc_includedirs(parent.document)
41
+ options[:includedirs] = add_attrs_to_includedirs(
42
+ parent.document, attrs, options[:includedirs]
43
+ )
76
44
 
77
- def valid_format?(format)
78
- %w[png svg pdf txt eps].include?(format)
45
+ options
79
46
  end
80
47
  end
81
48
  end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "asciidoctor"
4
+ require "asciidoctor/extensions"
5
+ require_relative "backend"
6
+
7
+ module Metanorma
8
+ module Plugin
9
+ module Plantuml
10
+ module BlockProcessorBase
11
+ def abort(parent, reader, attrs, msg)
12
+ warn msg
13
+ attrs["language"] = "plantuml"
14
+ create_listing_block(
15
+ parent,
16
+ reader.respond_to?(:source) ? reader.source : reader,
17
+ attrs.reject { |k, _v| k.to_s.match?(/^\d+$/) },
18
+ )
19
+ end
20
+
21
+ private
22
+
23
+ def parse_doc_includedirs(document)
24
+ docdir = document.attributes["docdir"]
25
+ includedirs = document.attr("plantuml-includedirs")&.split(";") || []
26
+
27
+ includedirs.map! do |includedir|
28
+ if Pathname.new(includedir).relative?
29
+ Pathname.new(docdir).join(includedir).to_s
30
+ else
31
+ includedir
32
+ end
33
+ end
34
+
35
+ includedirs.compact.uniq
36
+ end
37
+
38
+ def parse_formats(attrs, document) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize, Metrics/MethodLength
39
+ # Check for formats attribute (multiple formats)
40
+ if attrs["formats"]
41
+ formats = attrs["formats"].split(",").map(&:strip).map(&:downcase)
42
+ return formats.select { |f| valid_format?(f) }
43
+ end
44
+
45
+ # Check for format attribute (single format override)
46
+ if attrs["format"]
47
+ format = attrs["format"].strip.downcase
48
+ return [format] if valid_format?(format)
49
+ end
50
+
51
+ # Fall back to document attribute or default
52
+ default_format = document
53
+ .attr("plantuml-image-format")&.strip&.downcase ||
54
+ Wrapper::DEFAULT_FORMAT
55
+
56
+ [default_format]
57
+ end
58
+
59
+ def valid_format?(format)
60
+ Wrapper::SUPPORTED_FORMATS.include?(format)
61
+ end
62
+
63
+ def add_attrs_to_includedirs(document, attrs, includedirs)
64
+ docdir = document.attributes["docdir"]
65
+ attrs_includedirs = attrs["includedirs"]&.split(";") || []
66
+
67
+ attrs_includedirs.each do |attrs_includedir|
68
+ includedirs << if Pathname.new(attrs_includedir).relative?
69
+ Pathname.new(docdir).join(attrs_includedir).to_s
70
+ else
71
+ attrs_includedir
72
+ end
73
+ end
74
+
75
+ includedirs.compact.uniq
76
+ end
77
+
78
+ def process_image_block(parent, reader, attrs, formats, options) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
79
+ if formats.length == 1
80
+ # Single format - original behavior
81
+ filename = Backend.generate_file(
82
+ parent, reader, format_override: formats.first, options: options
83
+ )
84
+ through_attrs = Backend.generate_attrs(attrs)
85
+ through_attrs["target"] = filename
86
+ else
87
+ # Multiple formats - generate multiple files
88
+ through_attrs = Backend
89
+ .generate_multiple_files(
90
+ parent, reader, formats, attrs, options: options
91
+ )
92
+ end
93
+
94
+ create_image_block parent, through_attrs
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Metanorma
4
+ module Plugin
5
+ module Plantuml
6
+ # PlantUML block processor for Asciidoctor
7
+ class ImageBlockMacroProcessor < ::Asciidoctor::Extensions::BlockMacroProcessor
8
+ include ::Metanorma::Plugin::Plantuml::BlockProcessorBase
9
+ use_dsl
10
+ named :plantuml_image
11
+
12
+ def process(parent, reader, attrs) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
13
+ # Check for document-level disable flag
14
+ if parent.document.attr("plantuml-disabled")
15
+ return abort(parent, reader, attrs, "PlantUML processing disabled")
16
+ end
17
+
18
+ # Check PlantUML availability explicitly
19
+ unless Backend.plantuml_available?
20
+ return abort(parent, reader, attrs, "PlantUML not installed")
21
+ end
22
+
23
+ # Parse format specifications
24
+ formats = parse_formats(attrs, parent.document)
25
+ options = parse_options(parent, reader, attrs)
26
+
27
+ process_image_block(parent, reader, attrs, formats, options)
28
+ rescue StandardError => e
29
+ abort(parent, reader, attrs, e.message)
30
+ end
31
+
32
+ private
33
+
34
+ def add_image_path_to_includedirs(document, image_path, includedirs)
35
+ docdir = document.attributes["docdir"]
36
+ includedirs << File.dirname(File.join(docdir, image_path))
37
+ includedirs.compact.uniq
38
+ end
39
+
40
+ def parse_options(parent, reader, attrs)
41
+ options = {}
42
+
43
+ # Parse include directory
44
+ options[:includedirs] = parse_doc_includedirs(parent.document)
45
+ options[:includedirs] = add_attrs_to_includedirs(
46
+ parent.document, attrs, options[:includedirs]
47
+ )
48
+ options[:includedirs] = add_image_path_to_includedirs(
49
+ parent.document, reader, options[:includedirs]
50
+ )
51
+
52
+ options
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -1,7 +1,7 @@
1
1
  module Metanorma
2
2
  module Plugin
3
3
  module Plantuml
4
- VERSION = "1.0.1".freeze
4
+ VERSION = "1.0.2".freeze
5
5
  PLANTUML_JAR_VERSION = "1.2025.4".freeze
6
6
  end
7
7
  end
@@ -32,7 +32,7 @@ module Metanorma
32
32
  options
33
33
  end
34
34
 
35
- def generate( # rubocop:disable Metrics/MethodLength
35
+ def generate( # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
36
36
  content,
37
37
  format: DEFAULT_FORMAT,
38
38
  output_file: nil,
@@ -42,6 +42,9 @@ module Metanorma
42
42
  ensure_jar_available!
43
43
  ensure_java_available!
44
44
 
45
+ include_files = get_include_files(content, options)
46
+ options[:include_files] = include_files unless include_files.empty?
47
+
45
48
  result = if output_file
46
49
  generate_to_file(content, format, output_file, options)
47
50
  elsif base64
@@ -55,6 +58,24 @@ module Metanorma
55
58
  { success: false, error: e }
56
59
  end
57
60
 
61
+ def get_include_files(content, _options) # rubocop:disable Metrics/MethodLength
62
+ include_files = []
63
+ content.each_line do |line|
64
+ case line
65
+ when /(!include|!includesub)\s(.+){1}/
66
+ found_file = $2.split("!").first
67
+
68
+ # skip web links and standard libraries
69
+ if found_file.start_with?("<", "http")
70
+ found_file = nil
71
+ end
72
+
73
+ include_files << found_file
74
+ end
75
+ end
76
+ include_files.compact.uniq
77
+ end
78
+
58
79
  def generate_from_file(
59
80
  input_file, format: DEFAULT_FORMAT,
60
81
  output_file: nil, base64: false, **options
@@ -169,47 +190,85 @@ module Metanorma
169
190
  end
170
191
 
171
192
  def execute_plantuml(content, format, output_file, options) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize, Metrics/MethodLength
172
- Tempfile.create(["plantuml_input", ".puml"]) do |input_file| # rubocop:disable Metrics/BlockLength
173
- input_file.write(content)
174
- input_file.close
175
-
176
- # PlantUML generates output files based on filename specified in
177
- # @start... line
178
- # We need to use a temp directory and then move the file
179
- Dir.mktmpdir do |temp_dir| # rubocop:disable Metrics/BlockLength
180
- cmd = build_command(input_file.path, format, temp_dir, options)
181
-
182
- output, error, status = Open3.capture3(*cmd)
183
-
184
- unless status.success?
185
- error_message = if error.empty?
186
- "Unknown PlantUML error"
187
- else
188
- error.strip
189
- end
190
- raise GenerationError.new(error_message, error)
193
+ # PlantUML generates output files based on filename specified in
194
+ # @start... line
195
+ # We need to use a temp directory and then move the file
196
+ Dir.mktmpdir do |temp_dir| # rubocop:disable Metrics/BlockLength
197
+ # create input file
198
+ File.open("#{temp_dir}/plantuml_input.puml", "w") do |f|
199
+ f.write(content)
200
+ end
201
+
202
+ # Handle include files
203
+ if options[:include_files] && !options[:include_files].empty?
204
+ if options[:includedirs].empty?
205
+ # raise error when include files are found but includedirs
206
+ # is nil
207
+ raise PlantumlError.new(
208
+ "includedirs is required when include files are specified",
209
+ )
191
210
  end
192
211
 
193
- # Find the generated file and move it to the desired location
194
- if output_file
195
- generated_file = find_generated_file(temp_dir, content,
196
- format)
197
- if generated_file && File.exist?(generated_file)
198
- FileUtils.mv(generated_file, output_file)
199
- else
200
- # Debug: List what files were actually generated
201
- generated_files = Dir.glob(File.join(temp_dir, "*"))
202
- error_msg = "Generated file not found in temp directory. "
203
- error_msg += "Expected: #{generated_file}. "
204
- error_msg += "Found files: #{generated_files.map do |f|
205
- File.basename(f)
206
- end.join(', ')}"
207
- raise GenerationError.new(error_msg)
212
+ options[:include_files].each do |include_file|
213
+ # find local include file in includedirs
214
+ found_include_file = nil
215
+ options[:includedirs].each do |includedir|
216
+ include_file_path = File.join(includedir, include_file)
217
+ if File.exist?(include_file_path)
218
+ found_include_file = include_file_path
219
+ break
220
+ end
221
+ end
222
+
223
+ if found_include_file
224
+ # create include file in temp directory
225
+ temp_include_file = File.join(temp_dir, include_file)
226
+ FileUtils.mkdir_p(File.dirname(temp_include_file))
227
+
228
+ File.open(temp_include_file, "w") do |f|
229
+ f.write(File.read(found_include_file))
230
+ end
208
231
  end
209
232
  end
233
+ end
234
+
235
+ cmd = build_command(
236
+ "#{temp_dir}/plantuml_input.puml",
237
+ format,
238
+ temp_dir,
239
+ options,
240
+ )
210
241
 
211
- output
242
+ output, error, status = Open3.capture3(*cmd)
243
+
244
+ unless status.success?
245
+ error_message = if error.empty?
246
+ "Unknown PlantUML error"
247
+ else
248
+ error.strip
249
+ end
250
+ raise GenerationError.new(error_message, error)
212
251
  end
252
+
253
+ # Find the generated file and move it to the desired location
254
+ if output_file
255
+ generated_file = find_generated_file(temp_dir, content,
256
+ format)
257
+ if generated_file && File.exist?(generated_file)
258
+ FileUtils.mv(generated_file, output_file)
259
+ else
260
+ # Debug: List what files were actually generated
261
+ generated_files = Dir.glob(File.join(temp_dir, "*"))
262
+ error_msg = "Generated file not found in temp directory. "
263
+ error_msg += "Expected: #{generated_file}. "
264
+ error_msg += "Found files: #{generated_files.map do |f|
265
+ File.basename(f)
266
+ end.join(', ')}"
267
+ raise GenerationError.new(error_msg)
268
+ end
269
+ end
270
+
271
+ output
213
272
  end
214
273
  end
215
274
 
@@ -11,4 +11,6 @@ require "metanorma/plugin/plantuml/config"
11
11
  require "metanorma/plugin/plantuml/wrapper"
12
12
  require "metanorma/plugin/plantuml/utils"
13
13
  require "metanorma/plugin/plantuml/backend"
14
+ require "metanorma/plugin/plantuml/block_processor_base"
14
15
  require "metanorma/plugin/plantuml/block_processor"
16
+ require "metanorma/plugin/plantuml/image_block_macro_processor"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: metanorma-plugin-plantuml
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-08-28 00:00:00.000000000 Z
11
+ date: 2025-09-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: asciidoctor
@@ -58,8 +58,10 @@ files:
58
58
  - lib/metanorma-plugin-plantuml.rb
59
59
  - lib/metanorma/plugin/plantuml/backend.rb
60
60
  - lib/metanorma/plugin/plantuml/block_processor.rb
61
+ - lib/metanorma/plugin/plantuml/block_processor_base.rb
61
62
  - lib/metanorma/plugin/plantuml/config.rb
62
63
  - lib/metanorma/plugin/plantuml/errors.rb
64
+ - lib/metanorma/plugin/plantuml/image_block_macro_processor.rb
63
65
  - lib/metanorma/plugin/plantuml/utils.rb
64
66
  - lib/metanorma/plugin/plantuml/version.rb
65
67
  - lib/metanorma/plugin/plantuml/wrapper.rb