metanorma-plugin-plantuml 1.0.6 → 1.0.8
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 +4 -4
- data/.rubocop.yml +27 -0
- data/.rubocop_todo.yml +53 -0
- data/Gemfile +3 -0
- data/README.adoc +40 -1
- data/Rakefile +30 -25
- data/bin/console +1 -0
- data/lib/metanorma/plugin/plantuml/backend.rb +12 -21
- data/lib/metanorma/plugin/plantuml/block_processor.rb +5 -3
- data/lib/metanorma/plugin/plantuml/block_processor_base.rb +1 -1
- data/lib/metanorma/plugin/plantuml/config.rb +3 -3
- data/lib/metanorma/plugin/plantuml/errors.rb +2 -0
- data/lib/metanorma/plugin/plantuml/image_block_macro_processor.rb +8 -4
- data/lib/metanorma/plugin/plantuml/version.rb +4 -2
- data/lib/metanorma/plugin/plantuml/wrapper.rb +48 -47
- data/lib/metanorma-plugin-plantuml.rb +2 -0
- data/metanorma-plugin-plantuml.gemspec +3 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f630e977bc4ffc712b558d93838862f20d33a3c321d170035f236b28f263caf9
|
4
|
+
data.tar.gz: 7767222a7655f56628928d69cf0990d38b5667c6cc74a009af2c53d1232ade2a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 65d274ab21262faf3ffb1909f25b5e99c8eaad34c9f3df675b73aa7c727ca0d2e8f0a03ebd6e73c71e5a595dbf529d1b2e902c68ba635d7d866f8c417c8bc5e9
|
7
|
+
data.tar.gz: 9ddc2697ab8d6eb43a488aa8c3b30e8d7d0c0c2a6dcf7abbb72501f28b89aff1aae8f36108c65fed41d714c5c627833fa660e26f19d9d76d49d712b84a7826bd
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# Auto-generated by Cimas: Do not edit it manually!
|
2
|
+
# See https://github.com/metanorma/cimas
|
3
|
+
inherit_from:
|
4
|
+
- .rubocop_todo.yml
|
5
|
+
- https://raw.githubusercontent.com/riboseinc/oss-guides/main/ci/rubocop.yml
|
6
|
+
|
7
|
+
# local repo-specific modifications
|
8
|
+
# ...
|
9
|
+
|
10
|
+
Metrics/CyclomaticComplexity:
|
11
|
+
Max: 10
|
12
|
+
|
13
|
+
Metrics/BlockLength:
|
14
|
+
Exclude:
|
15
|
+
- 'Rakefile'
|
16
|
+
- 'spec/**/*'
|
17
|
+
|
18
|
+
Metrics/MethodLength:
|
19
|
+
Exclude:
|
20
|
+
- 'Rakefile'
|
21
|
+
- 'lib/metanorma/plugin/plantuml/block_processor.rb'
|
22
|
+
- 'lib/metanorma/plugin/plantuml/image_block_macro_processor.rb'
|
23
|
+
- 'lib/metanorma/plugin/plantuml/wrapper.rb'
|
24
|
+
- 'spec/**/*'
|
25
|
+
|
26
|
+
AllCops:
|
27
|
+
TargetRubyVersion: 3.1
|
data/.rubocop_todo.yml
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# This configuration was generated by
|
2
|
+
# `rubocop --auto-gen-config`
|
3
|
+
# on 2025-10-03 01:36:37 UTC using RuboCop version 1.81.1.
|
4
|
+
# The point is for the user to remove these configuration records
|
5
|
+
# one by one as the offenses are removed from the code base.
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
8
|
+
|
9
|
+
# Offense count: 1
|
10
|
+
# Configuration parameters: Severity.
|
11
|
+
Gemspec/RequiredRubyVersion:
|
12
|
+
Exclude:
|
13
|
+
- 'metanorma-plugin-plantuml.gemspec'
|
14
|
+
|
15
|
+
# Offense count: 11
|
16
|
+
# This cop supports safe autocorrection (--autocorrect).
|
17
|
+
# Configuration parameters: Max, AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, IgnoreCopDirectives, AllowedPatterns, SplitStrings.
|
18
|
+
# URISchemes: http, https
|
19
|
+
Layout/LineLength:
|
20
|
+
Exclude:
|
21
|
+
- 'Rakefile'
|
22
|
+
- 'lib/metanorma/plugin/plantuml/backend.rb'
|
23
|
+
- 'lib/metanorma/plugin/plantuml/config.rb'
|
24
|
+
- 'lib/metanorma/plugin/plantuml/wrapper.rb'
|
25
|
+
- 'spec/metanorma/plugin/plantuml/plantuml_integration_spec.rb'
|
26
|
+
|
27
|
+
# Offense count: 3
|
28
|
+
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
|
29
|
+
Metrics/AbcSize:
|
30
|
+
Exclude:
|
31
|
+
- 'Rakefile'
|
32
|
+
|
33
|
+
# Offense count: 1
|
34
|
+
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
|
35
|
+
# AllowedMethods: refine
|
36
|
+
Metrics/BlockLength:
|
37
|
+
Exclude:
|
38
|
+
- 'Rakefile'
|
39
|
+
|
40
|
+
# Offense count: 8
|
41
|
+
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
|
42
|
+
Metrics/MethodLength:
|
43
|
+
Exclude:
|
44
|
+
- 'Rakefile'
|
45
|
+
- 'lib/metanorma/plugin/plantuml/block_processor.rb'
|
46
|
+
- 'lib/metanorma/plugin/plantuml/image_block_macro_processor.rb'
|
47
|
+
- 'lib/metanorma/plugin/plantuml/wrapper.rb'
|
48
|
+
|
49
|
+
# Offense count: 1
|
50
|
+
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
|
51
|
+
Metrics/PerceivedComplexity:
|
52
|
+
Exclude:
|
53
|
+
- 'Rakefile'
|
data/Gemfile
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
Encoding.default_external = Encoding::UTF_8
|
2
4
|
Encoding.default_internal = Encoding::UTF_8
|
3
5
|
|
@@ -24,6 +26,7 @@ gem "rspec"
|
|
24
26
|
gem "rspec-html-matchers"
|
25
27
|
gem "rubocop"
|
26
28
|
gem "rubocop-performance"
|
29
|
+
gem "rubocop-rake"
|
27
30
|
gem "simplecov"
|
28
31
|
gem "timecop"
|
29
32
|
gem "vcr"
|
data/README.adoc
CHANGED
@@ -89,6 +89,7 @@ Generally, the command syntax is more suitable for referencing external PlantUML
|
|
89
89
|
files.
|
90
90
|
|
91
91
|
|
92
|
+
[[command-syntax]]
|
92
93
|
=== Command syntax for external diagrams
|
93
94
|
|
94
95
|
PlantUML diagrams can be directly referenced from external files using the
|
@@ -104,7 +105,7 @@ plantuml_image::{plantuml-source.puml}[{options}]
|
|
104
105
|
Where,
|
105
106
|
|
106
107
|
`{plantuml-source.puml}`:: Path to the PlantUML source file, relative to the
|
107
|
-
path of the
|
108
|
+
path of the document root file.
|
108
109
|
|
109
110
|
`{options}`:: (Optional) Comma-separated list of options to customize diagram
|
110
111
|
generation.
|
@@ -140,6 +141,35 @@ The file `foo/bar.puml` is the same as above.
|
|
140
141
|
The `format=svg` option specifies the output format as SVG.
|
141
142
|
====
|
142
143
|
|
144
|
+
The path to the PlantUML source file is relative to the document root file,
|
145
|
+
which is illustrated in the following example.
|
146
|
+
|
147
|
+
.PlantUML source file path is relative to document root
|
148
|
+
[example]
|
149
|
+
====
|
150
|
+
Given the following directory structure:
|
151
|
+
|
152
|
+
[source]
|
153
|
+
----
|
154
|
+
dir/
|
155
|
+
dir/sources/document.adoc
|
156
|
+
dir/sources/sections/section_1.adoc
|
157
|
+
dir/sources/plantuml/my_diagram.puml
|
158
|
+
----
|
159
|
+
|
160
|
+
Where:
|
161
|
+
|
162
|
+
* `document.adoc` includes `sections/section_1.adoc`
|
163
|
+
* `section_1.adoc` contains the `plantuml_image` command.
|
164
|
+
|
165
|
+
The path to the PlantUML source file in `section_1.adoc` is specified relative
|
166
|
+
to `document.adoc`, the document root, which is `plantuml/my_diagram.puml`:
|
167
|
+
|
168
|
+
[source,asciidoc]
|
169
|
+
----
|
170
|
+
plantuml_image::plantuml/my_diagram.puml[]
|
171
|
+
----
|
172
|
+
====
|
143
173
|
|
144
174
|
|
145
175
|
=== Block syntax for inline diagrams
|
@@ -452,6 +482,15 @@ Syntax:
|
|
452
482
|
:plantuml-includedirs: {path1};{path2};...
|
453
483
|
----
|
454
484
|
|
485
|
+
Where,
|
486
|
+
|
487
|
+
`{path1}`, `{path2}`, etc.:: paths to directories (relative to document root)
|
488
|
+
containing PlantUML files to be included, delimited by semicolons.
|
489
|
+
+
|
490
|
+
NOTE: All paths passed to `includedirs` must be relative to the document root
|
491
|
+
file, see <<command-syntax>> on how to determine the document root.
|
492
|
+
|
493
|
+
|
455
494
|
.Resolving PlantUML includes with document-level `includedirs` attribute
|
456
495
|
[example]
|
457
496
|
====
|
data/Rakefile
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "English"
|
4
|
+
|
1
5
|
require "bundler/gem_tasks"
|
2
6
|
require "rspec/core/rake_task"
|
3
7
|
require_relative "lib/metanorma/plugin/plantuml/version"
|
@@ -17,7 +21,7 @@ end
|
|
17
21
|
def github_client
|
18
22
|
require "octokit"
|
19
23
|
@github_client ||= begin
|
20
|
-
token = ENV[
|
24
|
+
token = ENV["GITHUB_TOKEN"] || `gh auth token 2>/dev/null`.strip
|
21
25
|
token = nil if token.empty?
|
22
26
|
if token
|
23
27
|
Octokit::Client.new(access_token: token)
|
@@ -31,32 +35,32 @@ def find_latest_valid_plantuml_release
|
|
31
35
|
puts "Searching for latest valid PlantUML release..."
|
32
36
|
|
33
37
|
client = github_client
|
34
|
-
releases = client.releases(
|
38
|
+
releases = client.releases("plantuml/plantuml")
|
35
39
|
|
36
40
|
# Filter for valid JAR releases
|
37
41
|
valid_releases = releases.reject(&:prerelease).select do |release|
|
38
42
|
tag_name = release.tag_name
|
39
|
-
version = tag_name.sub(/^v/,
|
43
|
+
version = tag_name.sub(/^v/, "")
|
40
44
|
# Must match pattern v\d+\.\d{4}\.\d+ and not contain -native or other suffixes
|
41
45
|
tag_name.match?(/^v\d+\.\d{4}\.\d+$/) &&
|
42
|
-
|
43
|
-
|
44
|
-
|
46
|
+
!tag_name.include?("-native") &&
|
47
|
+
!tag_name.include?("-snapshot") &&
|
48
|
+
release.assets.any? { |asset| asset.name == "plantuml-#{version}.jar" }
|
45
49
|
end
|
46
50
|
|
47
|
-
if valid_releases.empty?
|
48
|
-
raise "No valid PlantUML JAR releases found"
|
49
|
-
end
|
51
|
+
raise "No valid PlantUML JAR releases found" if valid_releases.empty?
|
50
52
|
|
51
53
|
latest = valid_releases.first
|
52
|
-
version = latest.tag_name.sub(/^v/,
|
54
|
+
version = latest.tag_name.sub(/^v/, "")
|
53
55
|
|
54
56
|
puts "Found latest valid release: #{latest.tag_name} (#{version})"
|
55
57
|
{
|
56
58
|
version: version,
|
57
59
|
tag_name: latest.tag_name,
|
58
60
|
html_url: latest.html_url,
|
59
|
-
jar_asset: latest.assets.find
|
61
|
+
jar_asset: latest.assets.find do |asset|
|
62
|
+
asset.name == "plantuml-#{version}.jar"
|
63
|
+
end,
|
60
64
|
}
|
61
65
|
rescue Octokit::Error => e
|
62
66
|
puts "GitHub API error: #{e.message}"
|
@@ -80,8 +84,10 @@ def update_version_file(new_plantuml_version, new_gem_version)
|
|
80
84
|
|
81
85
|
# Update PlantUML version (handle .freeze suffix)
|
82
86
|
original_content = content.dup
|
83
|
-
content.gsub!(/VERSION = ["']([^"']+)["']\.freeze/,
|
84
|
-
|
87
|
+
content.gsub!(/VERSION = ["']([^"']+)["']\.freeze/,
|
88
|
+
%(VERSION = "#{new_gem_version}".freeze))
|
89
|
+
content.gsub!(/PLANTUML_JAR_VERSION = ["']([^"']+)["']\.freeze/,
|
90
|
+
%(PLANTUML_JAR_VERSION = "#{new_plantuml_version}".freeze))
|
85
91
|
|
86
92
|
if content == original_content
|
87
93
|
puts "⚠️ No changes made to version file. Current content:"
|
@@ -93,7 +99,7 @@ def update_version_file(new_plantuml_version, new_gem_version)
|
|
93
99
|
|
94
100
|
# Verify the file was written correctly
|
95
101
|
updated_content = File.read(version_file)
|
96
|
-
unless updated_content.include?(%
|
102
|
+
unless updated_content.include?(%("#{new_plantuml_version}")) && updated_content.include?(%("#{new_gem_version}"))
|
97
103
|
puts "❌ File content after update:"
|
98
104
|
puts updated_content
|
99
105
|
raise "Version file update verification failed"
|
@@ -105,32 +111,31 @@ def update_version_file(new_plantuml_version, new_gem_version)
|
|
105
111
|
end
|
106
112
|
|
107
113
|
def increment_gem_version(current_version)
|
108
|
-
require
|
114
|
+
require "rubygems"
|
109
115
|
version = Gem::Version.new(current_version)
|
110
116
|
segments = version.segments.dup
|
111
117
|
segments[2] = (segments[2] || 0) + 1
|
112
|
-
segments.join(
|
118
|
+
segments.join(".")
|
113
119
|
end
|
114
120
|
|
115
121
|
def test_plantuml_jar
|
116
122
|
jar_file = "data/plantuml.jar"
|
117
123
|
|
118
|
-
unless File.exist?(jar_file)
|
119
|
-
raise "PlantUML JAR file not found: #{jar_file}"
|
120
|
-
end
|
124
|
+
raise "PlantUML JAR file not found: #{jar_file}" unless File.exist?(jar_file)
|
121
125
|
|
122
126
|
puts "Testing PlantUML JAR functionality..."
|
123
127
|
|
124
128
|
# Test version command
|
125
129
|
version_output = `java -jar #{jar_file} -version 2>&1`
|
126
|
-
unless
|
130
|
+
unless $CHILD_STATUS.success? && version_output.include?("PlantUML")
|
127
131
|
raise "PlantUML version test failed. Output: #{version_output}"
|
128
132
|
end
|
133
|
+
|
129
134
|
puts "✅ Version test passed"
|
130
135
|
|
131
136
|
# Test diagram generation
|
132
137
|
test_diagram = "test_diagram_#{Time.now.to_i}.puml"
|
133
|
-
test_svg = test_diagram.sub(
|
138
|
+
test_svg = test_diagram.sub(".puml", ".svg")
|
134
139
|
|
135
140
|
File.write(test_diagram, <<~PUML)
|
136
141
|
@startuml
|
@@ -141,9 +146,10 @@ def test_plantuml_jar
|
|
141
146
|
|
142
147
|
begin
|
143
148
|
generation_output = `java -jar #{jar_file} -tsvg #{test_diagram} 2>&1`
|
144
|
-
unless
|
149
|
+
unless $CHILD_STATUS.success? && File.exist?(test_svg)
|
145
150
|
raise "PlantUML diagram generation test failed. Output: #{generation_output}"
|
146
151
|
end
|
152
|
+
|
147
153
|
puts "✅ Diagram generation test passed"
|
148
154
|
ensure
|
149
155
|
FileUtils.rm_f([test_diagram, test_svg])
|
@@ -214,7 +220,7 @@ task :update_plantuml do
|
|
214
220
|
end
|
215
221
|
|
216
222
|
# Check if update is actually newer
|
217
|
-
require
|
223
|
+
require "rubygems"
|
218
224
|
if Gem::Version.new(latest_version) <= Gem::Version.new(current_version)
|
219
225
|
puts "⚠️ Latest version (#{latest_version}) is not newer than current (#{current_version})"
|
220
226
|
exit 0
|
@@ -239,7 +245,6 @@ task :update_plantuml do
|
|
239
245
|
puts " Release: #{release_info[:html_url]}"
|
240
246
|
|
241
247
|
exit 1 # Exit with code 1 to indicate changes were made
|
242
|
-
|
243
248
|
rescue StandardError => e
|
244
249
|
puts "❌ Failed to update PlantUML: #{e.message}"
|
245
250
|
exit 2 # Exit with code 2 to indicate error
|
@@ -247,7 +252,7 @@ task :update_plantuml do
|
|
247
252
|
end
|
248
253
|
|
249
254
|
desc "Update PlantUML version in version.rb (manual)"
|
250
|
-
task :update_plantuml_version, [:plantuml_version] do |
|
255
|
+
task :update_plantuml_version, [:plantuml_version] do |_t, args|
|
251
256
|
plantuml_version = args[:plantuml_version]
|
252
257
|
|
253
258
|
unless plantuml_version
|
data/bin/console
CHANGED
@@ -34,9 +34,7 @@ module Metanorma
|
|
34
34
|
filename = generate_unique_filename(fmt)
|
35
35
|
extracted_filename = extract_plantuml_filename(plantuml_content)
|
36
36
|
|
37
|
-
if extracted_filename
|
38
|
-
filename = "#{extracted_filename}.#{fmt}"
|
39
|
-
end
|
37
|
+
filename = "#{extracted_filename}.#{fmt}" if extracted_filename
|
40
38
|
|
41
39
|
absolute_path, relative_path = path_prep(ldir, imagesdir)
|
42
40
|
output_file = File.join(absolute_path, filename)
|
@@ -48,9 +46,7 @@ module Metanorma
|
|
48
46
|
includedirs: options[:includedirs],
|
49
47
|
)
|
50
48
|
|
51
|
-
unless result[:success]
|
52
|
-
raise "No image output from PlantUML: #{result[:error].message}"
|
53
|
-
end
|
49
|
+
raise "No image output from PlantUML: #{result[:error].message}" unless result[:success]
|
54
50
|
|
55
51
|
File.join(relative_path, filename)
|
56
52
|
end
|
@@ -95,9 +91,7 @@ module Metanorma
|
|
95
91
|
sourcepath = imagesdir ? File.join(localdir, imagesdir) : localdir
|
96
92
|
path.mkpath
|
97
93
|
|
98
|
-
unless File.writable?(path)
|
99
|
-
raise "Destination path #{path} not writable for PlantUML!"
|
100
|
-
end
|
94
|
+
raise "Destination path #{path} not writable for PlantUML!" unless File.writable?(path)
|
101
95
|
|
102
96
|
[
|
103
97
|
path,
|
@@ -129,31 +123,28 @@ module Metanorma
|
|
129
123
|
end
|
130
124
|
|
131
125
|
def generate_attrs(attrs)
|
132
|
-
%w
|
133
|
-
.
|
134
|
-
memo[key] = attrs[key] if attrs.
|
135
|
-
memo
|
126
|
+
%w[id align float title role width height alt]
|
127
|
+
.each_with_object({}) do |key, memo|
|
128
|
+
memo[key] = attrs[key] if attrs.key?(key)
|
136
129
|
end
|
137
130
|
end
|
138
131
|
|
139
132
|
private
|
140
133
|
|
141
|
-
def validate_plantuml_delimiters(src)
|
134
|
+
def validate_plantuml_delimiters(src)
|
142
135
|
# Find @start... pattern
|
143
136
|
# (case insensitive, support all PlantUML diagram types)
|
144
137
|
start_match = src.match(/^@start(\w+)/i)
|
145
|
-
unless start_match
|
146
|
-
raise "PlantUML content must start with @start... directive!"
|
147
|
-
end
|
138
|
+
raise "PlantUML content must start with @start... directive!" unless start_match
|
148
139
|
|
149
140
|
diagram_type = start_match[1].downcase
|
150
141
|
end_pattern = "@end#{diagram_type}"
|
151
142
|
|
152
143
|
# Look for matching @end... directive (case insensitive)
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
144
|
+
return if /#{Regexp.escape(end_pattern)}\s*$/mi.match?(src)
|
145
|
+
|
146
|
+
raise "@start#{diagram_type} without matching #{end_pattern} " \
|
147
|
+
"in PlantUML!"
|
157
148
|
end
|
158
149
|
|
159
150
|
def extract_plantuml_filename(plantuml_content)
|
@@ -11,15 +11,17 @@ module Metanorma
|
|
11
11
|
on_context :literal
|
12
12
|
parse_content_as :raw
|
13
13
|
|
14
|
-
def process(parent, reader, attrs)
|
14
|
+
def process(parent, reader, attrs)
|
15
15
|
# Check for document-level disable flag
|
16
16
|
if parent.document.attr("plantuml-disabled")
|
17
|
-
return abort(parent, reader, attrs,
|
17
|
+
return abort(parent, reader, attrs,
|
18
|
+
"PlantUML processing disabled")
|
18
19
|
end
|
19
20
|
|
20
21
|
# Check PlantUML availability explicitly
|
21
22
|
unless Backend.plantuml_available?
|
22
|
-
return abort(parent, reader, attrs,
|
23
|
+
return abort(parent, reader, attrs,
|
24
|
+
"PlantUML not installed")
|
23
25
|
end
|
24
26
|
|
25
27
|
# Parse format specifications
|
@@ -75,7 +75,7 @@ module Metanorma
|
|
75
75
|
includedirs.compact.uniq
|
76
76
|
end
|
77
77
|
|
78
|
-
def process_image_block(parent, reader, attrs, formats, options) # rubocop:disable Metrics/
|
78
|
+
def process_image_block(parent, reader, attrs, formats, options) # rubocop:disable Metrics/MethodLength
|
79
79
|
if formats.length == 1
|
80
80
|
# Single format - original behavior
|
81
81
|
filename = Backend.generate_file(
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "rbconfig"
|
2
4
|
|
3
5
|
module Metanorma
|
@@ -20,9 +22,7 @@ module Metanorma
|
|
20
22
|
"-Djava.awt.headless=true",
|
21
23
|
]
|
22
24
|
|
23
|
-
if RbConfig::CONFIG["host_os"].match?(/darwin|mac os/)
|
24
|
-
options << "-Dapple.awt.UIElement=true"
|
25
|
-
end
|
25
|
+
options << "-Dapple.awt.UIElement=true" if RbConfig::CONFIG["host_os"].match?(/darwin|mac os/)
|
26
26
|
|
27
27
|
options
|
28
28
|
end
|
@@ -9,15 +9,17 @@ module Metanorma
|
|
9
9
|
use_dsl
|
10
10
|
named :plantuml_image
|
11
11
|
|
12
|
-
def process(parent, reader, attrs)
|
12
|
+
def process(parent, reader, attrs)
|
13
13
|
# Check for document-level disable flag
|
14
14
|
if parent.document.attr("plantuml-disabled")
|
15
|
-
return abort(parent, reader, attrs,
|
15
|
+
return abort(parent, reader, attrs,
|
16
|
+
"PlantUML processing disabled")
|
16
17
|
end
|
17
18
|
|
18
19
|
# Check PlantUML availability explicitly
|
19
20
|
unless Backend.plantuml_available?
|
20
|
-
return abort(parent, reader, attrs,
|
21
|
+
return abort(parent, reader, attrs,
|
22
|
+
"PlantUML not installed")
|
21
23
|
end
|
22
24
|
|
23
25
|
# Parse format specifications
|
@@ -33,7 +35,9 @@ module Metanorma
|
|
33
35
|
|
34
36
|
def add_image_path_to_includedirs(document, image_path, includedirs)
|
35
37
|
docdir = document.attributes["docdir"]
|
36
|
-
includedirs << File.dirname(
|
38
|
+
includedirs << File.dirname(
|
39
|
+
document.path_resolver.system_path(image_path, docdir),
|
40
|
+
)
|
37
41
|
includedirs.compact.uniq
|
38
42
|
end
|
39
43
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "open3"
|
2
4
|
require "base64"
|
3
5
|
require "tempfile"
|
@@ -12,27 +14,25 @@ module Metanorma
|
|
12
14
|
module Plugin
|
13
15
|
module Plantuml
|
14
16
|
class Wrapper
|
15
|
-
PLANTUML_JAR_NAME = "plantuml.jar"
|
17
|
+
PLANTUML_JAR_NAME = "plantuml.jar"
|
16
18
|
PLANTUML_JAR_PATH = File.join(
|
17
|
-
|
18
|
-
"
|
19
|
+
Gem::Specification.find_by_name("metanorma-plugin-plantuml").gem_dir,
|
20
|
+
"data", PLANTUML_JAR_NAME
|
19
21
|
)
|
20
22
|
|
21
23
|
SUPPORTED_FORMATS = %w[png svg pdf txt eps].freeze
|
22
|
-
DEFAULT_FORMAT = "png"
|
24
|
+
DEFAULT_FORMAT = "png"
|
23
25
|
|
24
26
|
class << self
|
25
27
|
def jvm_options
|
26
28
|
options = ["-Xss5m", "-Xmx1024m"]
|
27
29
|
|
28
|
-
if RbConfig::CONFIG["host_os"].match?(/darwin|mac os/)
|
29
|
-
options << "-Dapple.awt.UIElement=true"
|
30
|
-
end
|
30
|
+
options << "-Dapple.awt.UIElement=true" if RbConfig::CONFIG["host_os"].match?(/darwin|mac os/)
|
31
31
|
|
32
32
|
options
|
33
33
|
end
|
34
34
|
|
35
|
-
def generate( # rubocop:disable Metrics/MethodLength
|
35
|
+
def generate( # rubocop:disable Metrics/MethodLength
|
36
36
|
content,
|
37
37
|
format: DEFAULT_FORMAT,
|
38
38
|
output_file: nil,
|
@@ -58,17 +58,15 @@ module Metanorma
|
|
58
58
|
{ success: false, error: e }
|
59
59
|
end
|
60
60
|
|
61
|
-
def get_include_files(content, _options)
|
61
|
+
def get_include_files(content, _options)
|
62
62
|
include_files = []
|
63
63
|
content.each_line do |line|
|
64
64
|
case line
|
65
65
|
when /(!include|!includesub)\s(.+){1}/
|
66
|
-
found_file =
|
66
|
+
found_file = ::Regexp.last_match(2).split("!").first
|
67
67
|
|
68
68
|
# skip web links and standard libraries
|
69
|
-
if found_file.start_with?("<", "http")
|
70
|
-
found_file = nil
|
71
|
-
end
|
69
|
+
found_file = nil if found_file.start_with?("<", "http")
|
72
70
|
|
73
71
|
include_files << found_file
|
74
72
|
end
|
@@ -81,7 +79,8 @@ module Metanorma
|
|
81
79
|
output_file: nil, base64: false, **options
|
82
80
|
)
|
83
81
|
unless File.exist?(input_file)
|
84
|
-
raise GenerationError
|
82
|
+
raise GenerationError,
|
83
|
+
"Input file not found: #{input_file}"
|
85
84
|
end
|
86
85
|
|
87
86
|
content = File.read(input_file)
|
@@ -123,21 +122,21 @@ module Metanorma
|
|
123
122
|
|
124
123
|
def validate_format!(format)
|
125
124
|
format_str = format.to_s.downcase
|
126
|
-
|
127
|
-
|
128
|
-
|
125
|
+
return if SUPPORTED_FORMATS.include?(format_str)
|
126
|
+
|
127
|
+
raise InvalidFormatError.new(format, SUPPORTED_FORMATS)
|
129
128
|
end
|
130
129
|
|
131
130
|
def ensure_jar_available!
|
132
|
-
|
133
|
-
|
134
|
-
|
131
|
+
return if File.exist?(PLANTUML_JAR_PATH)
|
132
|
+
|
133
|
+
raise JarNotFoundError, PLANTUML_JAR_PATH
|
135
134
|
end
|
136
135
|
|
137
136
|
def ensure_java_available!
|
138
|
-
|
139
|
-
|
140
|
-
|
137
|
+
return if java_available?
|
138
|
+
|
139
|
+
raise JavaNotFoundError
|
141
140
|
end
|
142
141
|
|
143
142
|
def java_available?
|
@@ -155,24 +154,22 @@ module Metanorma
|
|
155
154
|
execute_plantuml(content, format, output_file, options)
|
156
155
|
|
157
156
|
unless File.exist?(output_file)
|
158
|
-
raise GenerationError
|
159
|
-
|
160
|
-
)
|
157
|
+
raise GenerationError,
|
158
|
+
"Output file was not created: #{output_file}"
|
161
159
|
end
|
162
160
|
|
163
161
|
{ output_path: File.expand_path(output_file) }
|
164
162
|
end
|
165
163
|
|
166
|
-
def generate_to_base64(content, format, options)
|
164
|
+
def generate_to_base64(content, format, options)
|
167
165
|
Tempfile.create(["plantuml_output", ".#{format}"]) do |temp_file|
|
168
166
|
temp_file.close
|
169
167
|
|
170
168
|
execute_plantuml(content, format, temp_file.path, options)
|
171
169
|
|
172
170
|
unless File.exist?(temp_file.path)
|
173
|
-
raise GenerationError
|
174
|
-
|
175
|
-
)
|
171
|
+
raise GenerationError,
|
172
|
+
"Temporary output file was not created"
|
176
173
|
end
|
177
174
|
|
178
175
|
encoded_content = Base64
|
@@ -204,30 +201,33 @@ module Metanorma
|
|
204
201
|
if options[:includedirs].empty?
|
205
202
|
# raise error when include files are found but includedirs
|
206
203
|
# is nil
|
207
|
-
raise PlantumlError
|
208
|
-
|
209
|
-
)
|
204
|
+
raise PlantumlError,
|
205
|
+
"includedirs is required when include files are specified"
|
210
206
|
end
|
211
207
|
|
212
208
|
options[:include_files].each do |include_file|
|
213
209
|
# find local include file in includedirs
|
214
210
|
found_include_file = nil
|
215
211
|
options[:includedirs].each do |includedir|
|
216
|
-
include_file_path =
|
212
|
+
include_file_path = Pathname.new(includedir)
|
213
|
+
.join(include_file).to_s
|
214
|
+
|
217
215
|
if File.exist?(include_file_path)
|
218
216
|
found_include_file = include_file_path
|
219
217
|
break
|
220
218
|
end
|
221
219
|
end
|
222
220
|
|
223
|
-
|
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))
|
221
|
+
next unless found_include_file
|
227
222
|
|
228
|
-
|
229
|
-
|
230
|
-
|
223
|
+
# create include file in temp directory
|
224
|
+
temp_include_file = Pathname.new(temp_dir)
|
225
|
+
.join(include_file).to_s
|
226
|
+
|
227
|
+
FileUtils.mkdir_p(File.dirname(temp_include_file))
|
228
|
+
|
229
|
+
File.open(temp_include_file, "w") do |f|
|
230
|
+
f.write(File.read(found_include_file))
|
231
231
|
end
|
232
232
|
end
|
233
233
|
end
|
@@ -264,7 +264,7 @@ module Metanorma
|
|
264
264
|
error_msg += "Found files: #{generated_files.map do |f|
|
265
265
|
File.basename(f)
|
266
266
|
end.join(', ')}"
|
267
|
-
raise GenerationError
|
267
|
+
raise GenerationError, error_msg
|
268
268
|
end
|
269
269
|
end
|
270
270
|
|
@@ -272,7 +272,7 @@ module Metanorma
|
|
272
272
|
end
|
273
273
|
end
|
274
274
|
|
275
|
-
def find_generated_file(temp_dir, content, format)
|
275
|
+
def find_generated_file(temp_dir, content, format)
|
276
276
|
# PlantUML generates files based on the filename specified in
|
277
277
|
# @start... line
|
278
278
|
extension = format.to_s.downcase
|
@@ -304,7 +304,7 @@ module Metanorma
|
|
304
304
|
filename.gsub(/^["']|["']$/, "")
|
305
305
|
end
|
306
306
|
|
307
|
-
def build_command(input_file, format, output_dir, _options) # rubocop:disable Metrics/
|
307
|
+
def build_command(input_file, format, output_dir, _options) # rubocop:disable Metrics/MethodLength
|
308
308
|
cmd = [
|
309
309
|
configuration.java_path,
|
310
310
|
*jvm_options,
|
@@ -313,9 +313,10 @@ module Metanorma
|
|
313
313
|
|
314
314
|
# Add format-specific options
|
315
315
|
format_str = format.to_s.downcase
|
316
|
-
if SUPPORTED_FORMATS.include?(format_str)
|
317
|
-
|
318
|
-
|
316
|
+
cmd << "-t#{format_str}" if SUPPORTED_FORMATS.include?(format_str)
|
317
|
+
|
318
|
+
# Use 'smetana' layout engine for pragma
|
319
|
+
cmd << "-Playout=smetana"
|
319
320
|
|
320
321
|
# Add output directory option
|
321
322
|
cmd << "-o" << output_dir
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
lib = File.expand_path("lib", __dir__)
|
2
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
5
|
require "metanorma/plugin/plantuml/version"
|
@@ -26,7 +28,7 @@ Gem::Specification.new do |spec|
|
|
26
28
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
27
29
|
spec.require_paths = ["lib"]
|
28
30
|
|
29
|
-
spec.required_ruby_version = ">= 2.7.0"
|
31
|
+
spec.required_ruby_version = ">= 2.7.0"
|
30
32
|
|
31
33
|
spec.add_dependency "asciidoctor"
|
32
34
|
spec.add_dependency "isodoc"
|
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.
|
4
|
+
version: 1.0.8
|
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-
|
11
|
+
date: 2025-10-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: asciidoctor
|
@@ -49,6 +49,8 @@ files:
|
|
49
49
|
- ".github/workflows/rake.yml"
|
50
50
|
- ".github/workflows/release.yml"
|
51
51
|
- ".gitignore"
|
52
|
+
- ".rubocop.yml"
|
53
|
+
- ".rubocop_todo.yml"
|
52
54
|
- Gemfile
|
53
55
|
- LICENSE
|
54
56
|
- README.adoc
|