asciidoctor-diagram 1.5.18 → 2.0.4
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/CHANGELOG.adoc +75 -0
- data/README.adoc +98 -23
- data/examples/features.adoc +2 -2
- data/lib/asciidoctor-diagram.rb +8 -0
- data/lib/asciidoctor-diagram/a2s/converter.rb +59 -0
- data/lib/asciidoctor-diagram/a2s/extension.rb +6 -52
- data/lib/asciidoctor-diagram/blockdiag/converter.rb +37 -0
- data/lib/asciidoctor-diagram/blockdiag/extension.rb +9 -116
- data/lib/asciidoctor-diagram/bpmn.rb +7 -0
- data/lib/asciidoctor-diagram/bpmn/converter.rb +62 -0
- data/lib/asciidoctor-diagram/bpmn/extension.rb +14 -0
- data/lib/asciidoctor-diagram/bytefield.rb +7 -0
- data/lib/asciidoctor-diagram/bytefield/converter.rb +26 -0
- data/lib/asciidoctor-diagram/bytefield/extension.rb +14 -0
- data/lib/asciidoctor-diagram/diagram_converter.rb +23 -0
- data/lib/asciidoctor-diagram/diagram_processor.rb +357 -0
- data/lib/asciidoctor-diagram/diagram_source.rb +322 -0
- data/lib/asciidoctor-diagram/ditaa/converter.rb +90 -0
- data/lib/asciidoctor-diagram/ditaa/extension.rb +6 -71
- data/lib/asciidoctor-diagram/dpic.rb +7 -0
- data/lib/asciidoctor-diagram/dpic/converter.rb +30 -0
- data/lib/asciidoctor-diagram/dpic/extension.rb +14 -0
- data/lib/asciidoctor-diagram/erd/converter.rb +31 -0
- data/lib/asciidoctor-diagram/erd/extension.rb +6 -35
- data/lib/asciidoctor-diagram/gnuplot.rb +7 -0
- data/lib/asciidoctor-diagram/gnuplot/converter.rb +63 -0
- data/lib/asciidoctor-diagram/gnuplot/extension.rb +14 -0
- data/lib/asciidoctor-diagram/graphviz/converter.rb +32 -0
- data/lib/asciidoctor-diagram/graphviz/extension.rb +6 -35
- data/lib/asciidoctor-diagram/http/converter.rb +99 -0
- data/lib/asciidoctor-diagram/http/server.rb +132 -0
- data/lib/asciidoctor-diagram/lilypond.rb +7 -0
- data/lib/asciidoctor-diagram/lilypond/converter.rb +54 -0
- data/lib/asciidoctor-diagram/lilypond/extension.rb +14 -0
- data/lib/asciidoctor-diagram/meme/converter.rb +122 -0
- data/lib/asciidoctor-diagram/meme/extension.rb +5 -107
- data/lib/asciidoctor-diagram/mermaid/converter.rb +179 -0
- data/lib/asciidoctor-diagram/mermaid/extension.rb +6 -159
- data/lib/asciidoctor-diagram/msc/converter.rb +35 -0
- data/lib/asciidoctor-diagram/msc/extension.rb +6 -36
- data/lib/asciidoctor-diagram/nomnoml/converter.rb +25 -0
- data/lib/asciidoctor-diagram/nomnoml/extension.rb +6 -28
- data/lib/asciidoctor-diagram/pikchr.rb +7 -0
- data/lib/asciidoctor-diagram/pikchr/converter.rb +26 -0
- data/lib/asciidoctor-diagram/pikchr/extension.rb +14 -0
- data/lib/asciidoctor-diagram/plantuml/converter.rb +117 -0
- data/lib/asciidoctor-diagram/plantuml/extension.rb +10 -119
- data/lib/asciidoctor-diagram/shaape/converter.rb +25 -0
- data/lib/asciidoctor-diagram/shaape/extension.rb +6 -28
- data/lib/asciidoctor-diagram/smcat.rb +7 -0
- data/lib/asciidoctor-diagram/smcat/converter.rb +44 -0
- data/lib/asciidoctor-diagram/smcat/extension.rb +14 -0
- data/lib/asciidoctor-diagram/svgbob/converter.rb +49 -0
- data/lib/asciidoctor-diagram/svgbob/extension.rb +6 -28
- data/lib/asciidoctor-diagram/symbolator.rb +7 -0
- data/lib/asciidoctor-diagram/symbolator/converter.rb +23 -0
- data/lib/asciidoctor-diagram/symbolator/extension.rb +14 -0
- data/lib/asciidoctor-diagram/syntrax/converter.rb +58 -0
- data/lib/asciidoctor-diagram/syntrax/extension.rb +6 -51
- data/lib/asciidoctor-diagram/tikz/converter.rb +56 -0
- data/lib/asciidoctor-diagram/tikz/extension.rb +6 -60
- data/lib/asciidoctor-diagram/umlet/converter.rb +24 -0
- data/lib/asciidoctor-diagram/umlet/extension.rb +6 -28
- data/lib/asciidoctor-diagram/util/cli.rb +14 -3
- data/lib/asciidoctor-diagram/util/cli_generator.rb +19 -1
- data/lib/asciidoctor-diagram/util/gif.rb +2 -2
- data/lib/asciidoctor-diagram/util/java.rb +1 -1
- data/lib/asciidoctor-diagram/util/java_socket.rb +7 -9
- data/lib/asciidoctor-diagram/util/pdf.rb +2 -2
- data/lib/asciidoctor-diagram/util/png.rb +2 -2
- data/lib/asciidoctor-diagram/util/svg.rb +46 -19
- data/lib/asciidoctor-diagram/util/which.rb +0 -29
- data/lib/asciidoctor-diagram/vega/converter.rb +47 -0
- data/lib/asciidoctor-diagram/vega/extension.rb +6 -44
- data/lib/asciidoctor-diagram/version.rb +1 -1
- data/lib/asciidoctor-diagram/wavedrom/converter.rb +50 -0
- data/lib/asciidoctor-diagram/wavedrom/extension.rb +6 -46
- data/lib/ditaa-1.3.15.jar +0 -0
- data/lib/ditaamini-0.12.jar +0 -0
- data/lib/plantuml-1.3.15.jar +0 -0
- data/lib/plantuml.jar +0 -0
- data/lib/server-1.3.15.jar +0 -0
- data/spec/a2s_spec.rb +2 -140
- data/spec/blockdiag_spec.rb +2 -200
- data/spec/bpmn_spec.rb +56 -0
- data/spec/bytefield_spec.rb +92 -0
- data/spec/ditaa_spec.rb +37 -143
- data/spec/dpic_spec.rb +19 -0
- data/spec/erd_spec.rb +2 -199
- data/spec/gnuplot_spec.rb +225 -0
- data/spec/graphviz_spec.rb +6 -145
- data/spec/lilypond_spec.rb +13 -0
- data/spec/mermaid_spec.rb +35 -200
- data/spec/msc_spec.rb +2 -199
- data/spec/nomnoml_spec.rb +4 -142
- data/spec/pikchr_spec.rb +51 -0
- data/spec/plantuml_spec.rb +24 -507
- data/spec/shaape_spec.rb +9 -221
- data/spec/shared_examples.rb +552 -0
- data/spec/smcat_spec.rb +26 -0
- data/spec/svgbob_spec.rb +2 -140
- data/spec/symbolator_spec.rb +23 -0
- data/spec/syntrax_spec.rb +5 -215
- data/spec/test_helper.rb +1 -18
- data/spec/tikz_spec.rb +4 -24
- data/spec/umlet_spec.rb +2 -58
- data/spec/vega_spec.rb +4 -117
- data/spec/wavedrom_spec.rb +2 -199
- metadata +73 -11
- data/lib/asciidoctor-diagram/extensions.rb +0 -568
- data/lib/ditaa-1.3.13.jar +0 -0
- data/lib/ditaamini-0.11.jar +0 -0
- data/lib/plantuml-1.3.13.jar +0 -0
- data/lib/server-1.3.13.jar +0 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
require_relative '../diagram_converter'
|
2
|
+
require_relative '../util/cli_generator'
|
3
|
+
require_relative '../util/platform'
|
4
|
+
|
5
|
+
module Asciidoctor
|
6
|
+
module Diagram
|
7
|
+
['BlockDiag', 'SeqDiag', 'ActDiag', 'NwDiag', 'RackDiag', 'PacketDiag'].each do |name|
|
8
|
+
converter = Class.new do
|
9
|
+
include DiagramConverter
|
10
|
+
include CliGenerator
|
11
|
+
|
12
|
+
def supported_formats
|
13
|
+
[:png, :pdf, :svg]
|
14
|
+
end
|
15
|
+
|
16
|
+
def convert(source, format, options)
|
17
|
+
# On Debian based systems the Python 3.x packages python3-(act|block|nw|seq)diag executables with
|
18
|
+
# a '3' suffix.
|
19
|
+
cmd_name = self.class.const_get(:TOOL)
|
20
|
+
alt_cmd_name = "#{cmd_name}3"
|
21
|
+
|
22
|
+
font_path = source.attr('fontpath')
|
23
|
+
|
24
|
+
generate_stdin(source.find_command(cmd_name, :alt_cmds => [alt_cmd_name]), format.to_s, source.to_s) do |tool_path, output_path|
|
25
|
+
args = [tool_path, '-a', '-o', Platform.native_path(output_path), "-T#{format.to_s}"]
|
26
|
+
args << "-f#{Platform.native_path(font_path)}" if font_path
|
27
|
+
args << '-'
|
28
|
+
args
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
converter.const_set(:TOOL, name.downcase)
|
33
|
+
|
34
|
+
::Asciidoctor::Diagram.const_set("#{name}Converter", converter)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -1,125 +1,18 @@
|
|
1
|
-
require_relative '../
|
2
|
-
require_relative '
|
3
|
-
require_relative '../util/platform'
|
4
|
-
require_relative '../util/which'
|
1
|
+
require_relative '../diagram_processor'
|
2
|
+
require_relative 'converter'
|
5
3
|
|
6
4
|
module Asciidoctor
|
7
5
|
module Diagram
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
# # Supports PNG and SVG output.
|
12
|
-
# class BlockDiagBlockProcessor < API::DiagramBlockProcessor; end
|
13
|
-
#
|
14
|
-
# # Block macro processor converts blockdiag source files into images.
|
15
|
-
# #
|
16
|
-
# # Supports PNG and SVG output.
|
17
|
-
# class BlockDiagBlockMacroProcessor < DiagramBlockMacroProcessor; end
|
18
|
-
|
19
|
-
# @!parse
|
20
|
-
# # Block processor converts seqdiag code into images.
|
21
|
-
# #
|
22
|
-
# # Supports PNG and SVG output.
|
23
|
-
# class SeqDiagBlockProcessor < API::DiagramBlockProcessor; end
|
24
|
-
#
|
25
|
-
# # Block macro processor converts seqdiag source files into images.
|
26
|
-
# #
|
27
|
-
# # Supports PNG and SVG output.
|
28
|
-
# class SeqDiagBlockMacroProcessor < API::DiagramBlockMacroProcessor; end
|
29
|
-
|
30
|
-
# @!parse
|
31
|
-
# # Block processor converts actdiag code into images.
|
32
|
-
# #
|
33
|
-
# # Supports PNG and SVG output.
|
34
|
-
# class ActDiagBlockProcessor < API::DiagramBlockProcessor; end
|
35
|
-
#
|
36
|
-
# # Block macro processor converts actdiag source files into images.
|
37
|
-
# #
|
38
|
-
# # Supports PNG and SVG output.
|
39
|
-
# class ActDiagBlockMacroProcessor < API::DiagramBlockMacroProcessor; end
|
40
|
-
|
41
|
-
# @!parse
|
42
|
-
# # Block processor converts nwdiag code into images.
|
43
|
-
# #
|
44
|
-
# # Supports PNG and SVG output.
|
45
|
-
# class NwDiagBlockProcessor < API::DiagramBlockProcessor; end
|
46
|
-
#
|
47
|
-
# # Block macro processor converts nwdiag source files into images.
|
48
|
-
# #
|
49
|
-
# # Supports PNG and SVG output.
|
50
|
-
# class NwDiagBlockMacroProcessor < API::DiagramBlockMacroProcessor; end
|
51
|
-
|
52
|
-
# @!parse
|
53
|
-
# # Block processor converts rackdiag code into images.
|
54
|
-
# #
|
55
|
-
# # Supports PNG and SVG output.
|
56
|
-
# class RackDiagBlockProcessor < API::DiagramBlockProcessor; end
|
57
|
-
#
|
58
|
-
# # Block macro processor converts rackdiag source files into images.
|
59
|
-
# #
|
60
|
-
# # Supports PNG and SVG output.
|
61
|
-
# class RackDiagBlockMacroProcessor < API::DiagramBlockMacroProcessor; end
|
62
|
-
|
63
|
-
# @!parse
|
64
|
-
# # Block processor converts packetdiag code into images.
|
65
|
-
# #
|
66
|
-
# # Supports PNG and SVG output.
|
67
|
-
# class PacketDiagBlockProcessor < API::DiagramBlockProcessor; end
|
68
|
-
#
|
69
|
-
# # Block macro processor converts packetdiag source files into images.
|
70
|
-
# #
|
71
|
-
# # Supports PNG and SVG output.
|
72
|
-
# class PacketDiagBlockMacroProcessor < API::DiagramBlockMacroProcessor; end
|
73
|
-
|
74
|
-
# @private
|
75
|
-
module BlockDiag
|
76
|
-
def self.define_processors(name)
|
77
|
-
init = Proc.new do
|
78
|
-
include ::Asciidoctor::Diagram::BlockDiag
|
79
|
-
|
80
|
-
[:png, :pdf, :svg].each do |f|
|
81
|
-
register_format(f, :image) do |p, c|
|
82
|
-
blockdiag(name, p, c, f)
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
block = Class.new(Extensions::DiagramBlockProcessor) do
|
88
|
-
self.instance_eval(&init)
|
89
|
-
end
|
90
|
-
::Asciidoctor::Diagram.const_set("#{name}BlockProcessor", block)
|
91
|
-
|
92
|
-
block_macro = Class.new(Extensions::DiagramBlockMacroProcessor) do
|
93
|
-
self.instance_eval(&init)
|
94
|
-
end
|
95
|
-
|
96
|
-
::Asciidoctor::Diagram.const_set("#{name}BlockMacroProcessor", block_macro)
|
6
|
+
['BlockDiag', 'SeqDiag', 'ActDiag', 'NwDiag', 'RackDiag', 'PacketDiag'].each do |tool|
|
7
|
+
block = Class.new(DiagramBlockProcessor) do
|
8
|
+
use_converter ::Asciidoctor::Diagram.const_get("#{tool}Converter")
|
97
9
|
end
|
10
|
+
::Asciidoctor::Diagram.const_set("#{tool}BlockProcessor", block)
|
98
11
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
def blockdiag(tool, parent, source, format)
|
103
|
-
inherit_prefix = name
|
104
|
-
cmd_name = tool.downcase
|
105
|
-
|
106
|
-
# On Debian based systems the Python 3.x packages python3-(act|block|nw|seq)diag executables with
|
107
|
-
# a '3' suffix.
|
108
|
-
alt_cmd_name = "#{tool.downcase}3"
|
109
|
-
|
110
|
-
font_path = source.attr('fontpath', nil, inherit_prefix)
|
111
|
-
|
112
|
-
generate_stdin(which(parent, cmd_name, :alt_cmds => [alt_cmd_name]), format.to_s, source.to_s) do |tool_path, output_path|
|
113
|
-
args = [tool_path, '-a', '-o', Platform.native_path(output_path), "-T#{format.to_s}"]
|
114
|
-
args << "-f#{Platform.native_path(font_path)}" if font_path
|
115
|
-
args << '-'
|
116
|
-
args
|
117
|
-
end
|
12
|
+
block_macro = Class.new(DiagramBlockMacroProcessor) do
|
13
|
+
use_converter ::Asciidoctor::Diagram.const_get("#{tool}Converter")
|
118
14
|
end
|
119
|
-
|
120
|
-
|
121
|
-
['BlockDiag', 'SeqDiag', 'ActDiag', 'NwDiag', 'RackDiag', 'PacketDiag'].each do |tool|
|
122
|
-
BlockDiag.define_processors(tool)
|
15
|
+
::Asciidoctor::Diagram.const_set("#{tool}BlockMacroProcessor", block_macro)
|
123
16
|
end
|
124
17
|
end
|
125
18
|
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require_relative '../diagram_converter'
|
2
|
+
require_relative '../util/cli'
|
3
|
+
require_relative '../util/cli_generator'
|
4
|
+
require_relative '../util/platform'
|
5
|
+
|
6
|
+
module Asciidoctor
|
7
|
+
module Diagram
|
8
|
+
# @private
|
9
|
+
class BpmnConverter
|
10
|
+
include DiagramConverter
|
11
|
+
include CliGenerator
|
12
|
+
|
13
|
+
|
14
|
+
def supported_formats
|
15
|
+
[:png, :svg, :pdf, :jpeg]
|
16
|
+
end
|
17
|
+
|
18
|
+
def collect_options(source)
|
19
|
+
options = {}
|
20
|
+
|
21
|
+
options[:width] = source.attr('width')
|
22
|
+
options[:height] = source.attr('height')
|
23
|
+
|
24
|
+
options
|
25
|
+
end
|
26
|
+
|
27
|
+
def convert(source, format, options)
|
28
|
+
opts = {}
|
29
|
+
|
30
|
+
opts[:width] = options[:width]
|
31
|
+
|
32
|
+
bpmnjs = source.find_command('bpmn-js')
|
33
|
+
opts[:height] = options[:height]
|
34
|
+
opts[:theme] = options[:theme]
|
35
|
+
config = options[:config]
|
36
|
+
if config
|
37
|
+
opts[:config] = source.resolve_path(config)
|
38
|
+
end
|
39
|
+
run_bpmnjs(bpmnjs, source, format, opts)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def run_bpmnjs(bpmnjs, source, format, options = {})
|
45
|
+
generate_file(bpmnjs, 'bpmn', format.to_s, source.to_s) do |tool_path, input_path, output_path|
|
46
|
+
args = [tool_path, Platform.native_path(input_path), '-o', Platform.native_path(output_path), '-t', format.to_s]
|
47
|
+
|
48
|
+
|
49
|
+
if options[:width]
|
50
|
+
args << '--width' << options[:width]
|
51
|
+
end
|
52
|
+
|
53
|
+
if options[:height]
|
54
|
+
args << '--height' << options[:height]
|
55
|
+
end
|
56
|
+
|
57
|
+
args
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require_relative 'converter'
|
2
|
+
require_relative '../diagram_processor'
|
3
|
+
|
4
|
+
module Asciidoctor
|
5
|
+
module Diagram
|
6
|
+
class BpmnBlockProcessor < DiagramBlockProcessor
|
7
|
+
use_converter BpmnConverter
|
8
|
+
end
|
9
|
+
|
10
|
+
class BpmnBlockMacroProcessor < DiagramBlockMacroProcessor
|
11
|
+
use_converter BpmnConverter
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require_relative '../diagram_converter'
|
2
|
+
require_relative '../util/cli_generator'
|
3
|
+
require_relative '../util/platform'
|
4
|
+
|
5
|
+
module Asciidoctor
|
6
|
+
module Diagram
|
7
|
+
# @private
|
8
|
+
class BytefieldConverter
|
9
|
+
include DiagramConverter
|
10
|
+
include CliGenerator
|
11
|
+
|
12
|
+
|
13
|
+
def supported_formats
|
14
|
+
[:svg]
|
15
|
+
end
|
16
|
+
|
17
|
+
def convert(source, format, options)
|
18
|
+
bytefield_path = source.find_command('bytefield-svg')
|
19
|
+
|
20
|
+
generate_stdin(bytefield_path, format.to_s, source.to_s) do |tool_path, output_path|
|
21
|
+
[tool_path, "--output", Platform.native_path(output_path)]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require_relative 'converter'
|
2
|
+
require_relative '../diagram_processor'
|
3
|
+
|
4
|
+
module Asciidoctor
|
5
|
+
module Diagram
|
6
|
+
class BytefieldBlockProcessor < DiagramBlockProcessor
|
7
|
+
use_converter BytefieldConverter
|
8
|
+
end
|
9
|
+
|
10
|
+
class BytefieldBlockMacroProcessor < DiagramBlockMacroProcessor
|
11
|
+
use_converter BytefieldConverter
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Asciidoctor
|
2
|
+
module Diagram
|
3
|
+
# This module describes the duck-typed interface that diagram converters must implement. Implementations
|
4
|
+
# may include this module but it is not required.
|
5
|
+
module DiagramConverter
|
6
|
+
def supported_formats
|
7
|
+
raise NotImplementedError.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def collect_options(source)
|
11
|
+
{}
|
12
|
+
end
|
13
|
+
|
14
|
+
def convert(source, format, options)
|
15
|
+
raise NotImplementedError.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def native_scaling?
|
19
|
+
false
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,357 @@
|
|
1
|
+
require 'asciidoctor' unless defined? ::Asciidoctor::VERSION
|
2
|
+
require 'asciidoctor/extensions'
|
3
|
+
require 'digest'
|
4
|
+
require 'json'
|
5
|
+
require 'fileutils'
|
6
|
+
require 'pathname'
|
7
|
+
require_relative 'diagram_source.rb'
|
8
|
+
require_relative 'http/converter'
|
9
|
+
require_relative 'version'
|
10
|
+
require_relative 'util/java'
|
11
|
+
require_relative 'util/gif'
|
12
|
+
require_relative 'util/pdf'
|
13
|
+
require_relative 'util/png'
|
14
|
+
require_relative 'util/svg'
|
15
|
+
|
16
|
+
module Asciidoctor
|
17
|
+
module Diagram
|
18
|
+
# Mixin that provides the basic machinery for image generation.
|
19
|
+
# When this module is included it will include the FormatRegistry into the singleton class of the target class.
|
20
|
+
module DiagramProcessor
|
21
|
+
include Asciidoctor::Logging
|
22
|
+
|
23
|
+
module ClassMethods
|
24
|
+
def use_converter(converter_type)
|
25
|
+
config[:converter] = converter_type
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.included(host_class)
|
30
|
+
host_class.use_dsl
|
31
|
+
host_class.extend(ClassMethods)
|
32
|
+
end
|
33
|
+
|
34
|
+
IMAGE_PARAMS = {
|
35
|
+
:svg => {
|
36
|
+
:encoding => Encoding::UTF_8,
|
37
|
+
:decoder => SVG
|
38
|
+
},
|
39
|
+
:gif => {
|
40
|
+
:encoding => Encoding::ASCII_8BIT,
|
41
|
+
:decoder => GIF
|
42
|
+
},
|
43
|
+
:png => {
|
44
|
+
:encoding => Encoding::ASCII_8BIT,
|
45
|
+
:decoder => PNG
|
46
|
+
},
|
47
|
+
:pdf => {
|
48
|
+
:encoding => Encoding::ASCII_8BIT,
|
49
|
+
:decoder => PDF
|
50
|
+
}
|
51
|
+
}
|
52
|
+
|
53
|
+
# Processes the diagram block or block macro by converting it into an image or literal block.
|
54
|
+
#
|
55
|
+
# @param parent [Asciidoctor::AbstractBlock] the parent asciidoc block of the block or block macro being processed
|
56
|
+
# @param reader_or_target [Asciidoctor::Reader, String] a reader that provides the contents of a block or the
|
57
|
+
# target value of a block macro
|
58
|
+
# @param attributes [Hash] the attributes of the block or block macro
|
59
|
+
# @return [Asciidoctor::AbstractBlock] a new block that replaces the original block or block macro
|
60
|
+
def process(parent, reader_or_target, attributes)
|
61
|
+
location = parent.document.reader.cursor_at_mark
|
62
|
+
|
63
|
+
normalised_attributes = attributes.inject({}) { |h, (k, v)| h[normalise_attribute_name(k)] = v; h }
|
64
|
+
source = create_source(parent, reader_or_target, normalised_attributes)
|
65
|
+
|
66
|
+
converter = config[:converter].new
|
67
|
+
|
68
|
+
supported_formats = converter.supported_formats
|
69
|
+
|
70
|
+
begin
|
71
|
+
format = source.attributes.delete('format') || source.global_attr('format', supported_formats[0])
|
72
|
+
format = format.to_sym if format.respond_to?(:to_sym)
|
73
|
+
|
74
|
+
raise "Format undefined" unless format
|
75
|
+
|
76
|
+
raise "#{self.class.name} does not support output format #{format}" unless supported_formats.include?(format)
|
77
|
+
|
78
|
+
|
79
|
+
title = source.attributes.delete 'title'
|
80
|
+
caption = source.attributes.delete 'caption'
|
81
|
+
|
82
|
+
case format
|
83
|
+
when :txt, :atxt, :utxt
|
84
|
+
block = create_literal_block(parent, source, format, converter)
|
85
|
+
else
|
86
|
+
block = create_image_block(parent, source, format, converter)
|
87
|
+
end
|
88
|
+
|
89
|
+
block.title = title
|
90
|
+
block.assign_caption(caption, 'figure')
|
91
|
+
block
|
92
|
+
rescue => e
|
93
|
+
case source.global_attr('on-error', 'log')
|
94
|
+
when 'abort'
|
95
|
+
raise e
|
96
|
+
else
|
97
|
+
text = "Failed to generate image: #{e.message}"
|
98
|
+
warn_msg = text.dup
|
99
|
+
if $VERBOSE
|
100
|
+
warn_msg << "\n" << e.backtrace.join("\n")
|
101
|
+
end
|
102
|
+
|
103
|
+
logger.error message_with_context warn_msg, source_location: location
|
104
|
+
|
105
|
+
text << "\n"
|
106
|
+
text << source.code
|
107
|
+
Asciidoctor::Block.new parent, :listing, :source => text, :attributes => attributes
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
protected
|
114
|
+
|
115
|
+
# Creates a DiagramSource object for the block or block macro being processed. Classes using this
|
116
|
+
# mixin must implement this method.
|
117
|
+
#
|
118
|
+
# @param parent_block [Asciidoctor::AbstractBlock] the parent asciidoc block of the block or block macro being processed
|
119
|
+
# @param reader_or_target [Asciidoctor::Reader, String] a reader that provides the contents of a block or the
|
120
|
+
# target value of a block macro
|
121
|
+
# @param attributes [Hash] the attributes of the block or block macro
|
122
|
+
#
|
123
|
+
# @return [DiagramSource] an object that implements the interface described by DiagramSource
|
124
|
+
#
|
125
|
+
# @abstract
|
126
|
+
def create_source(parent_block, reader_or_target, attributes)
|
127
|
+
raise NotImplementedError.new
|
128
|
+
end
|
129
|
+
|
130
|
+
private
|
131
|
+
|
132
|
+
def normalise_attribute_name(k)
|
133
|
+
case k
|
134
|
+
when String
|
135
|
+
k.downcase
|
136
|
+
when Symbol
|
137
|
+
k.to_s.downcase.to_sym
|
138
|
+
else
|
139
|
+
k
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
DIGIT_CHAR_RANGE = ('0'.ord)..('9'.ord)
|
144
|
+
|
145
|
+
def create_image_block(parent, source, format, converter)
|
146
|
+
image_name = "#{source.image_name}.#{format}"
|
147
|
+
image_dir = image_output_dir(parent)
|
148
|
+
cache_dir = cache_dir(source, parent)
|
149
|
+
image_file = parent.normalize_system_path image_name, image_dir
|
150
|
+
metadata_file = parent.normalize_system_path "#{image_name}.cache", cache_dir
|
151
|
+
|
152
|
+
if File.exist? metadata_file
|
153
|
+
metadata = File.open(metadata_file, 'r') {|f| JSON.load(f, nil, :symbolize_names => true, :create_additions => false) }
|
154
|
+
else
|
155
|
+
metadata = {}
|
156
|
+
end
|
157
|
+
|
158
|
+
image_attributes = source.attributes
|
159
|
+
options = converter.collect_options(source)
|
160
|
+
|
161
|
+
if !File.exist?(image_file) || source.should_process?(image_file, metadata) || options != metadata[:options]
|
162
|
+
params = IMAGE_PARAMS[format]
|
163
|
+
|
164
|
+
server_url = source.global_attr('server-url')
|
165
|
+
if server_url
|
166
|
+
server_type = source.global_attr('server-type')
|
167
|
+
converter = HttpConverter.new(server_url, server_type.to_sym, converter)
|
168
|
+
end
|
169
|
+
|
170
|
+
options = converter.collect_options(source)
|
171
|
+
result = converter.convert(source, format, options)
|
172
|
+
|
173
|
+
result.force_encoding(params[:encoding])
|
174
|
+
|
175
|
+
metadata = source.create_image_metadata
|
176
|
+
metadata[:options] = options
|
177
|
+
|
178
|
+
result, metadata[:width], metadata[:height] = params[:decoder].post_process_image(result)
|
179
|
+
|
180
|
+
FileUtils.mkdir_p(File.dirname(image_file)) unless Dir.exist?(File.dirname(image_file))
|
181
|
+
File.open(image_file, 'wb') {|f| f.write result}
|
182
|
+
|
183
|
+
FileUtils.mkdir_p(File.dirname(metadata_file)) unless Dir.exist?(File.dirname(metadata_file))
|
184
|
+
File.open(metadata_file, 'w') {|f| JSON.dump(metadata, f)}
|
185
|
+
end
|
186
|
+
|
187
|
+
scale = image_attributes['scale']
|
188
|
+
if !converter.native_scaling? && scalematch = /(\d+(?:\.\d+))/.match(scale)
|
189
|
+
scale_factor = scalematch[1].to_f
|
190
|
+
else
|
191
|
+
scale_factor = 1.0
|
192
|
+
end
|
193
|
+
|
194
|
+
if /html/i =~ parent.document.attributes['backend']
|
195
|
+
image_attributes.delete('scale')
|
196
|
+
if metadata[:width] && !image_attributes['width']
|
197
|
+
image_attributes['width'] = (metadata[:width] * scale_factor).to_i
|
198
|
+
end
|
199
|
+
if metadata[:height] && !image_attributes['height']
|
200
|
+
image_attributes['height'] = (metadata[:height] * scale_factor).to_i
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
parent.document.register(:images, image_name)
|
205
|
+
|
206
|
+
node = Asciidoctor::Block.new parent, :image, :content_model => :empty, :attributes => image_attributes
|
207
|
+
|
208
|
+
alt_text = node.attr('alt')
|
209
|
+
alt_text ||= if title_text = image_attributes['title']
|
210
|
+
title_text
|
211
|
+
elsif target = image_attributes['target']
|
212
|
+
(File.basename(target, File.extname(target)) || '').tr '_-', ' '
|
213
|
+
else
|
214
|
+
'Diagram'
|
215
|
+
end
|
216
|
+
alt_text = parent.sub_specialchars(alt_text)
|
217
|
+
|
218
|
+
node.set_attr('alt', alt_text)
|
219
|
+
|
220
|
+
if (scaledwidth = node.attr('scaledwidth'))
|
221
|
+
# append % to scaledwidth if ends in number (no units present)
|
222
|
+
if DIGIT_CHAR_RANGE.include?((scaledwidth[-1] || 0).ord)
|
223
|
+
node.set_attr('scaledwidth', %(#{scaledwidth}%))
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
use_absolute_path = source.attr('data-uri', nil, true)
|
228
|
+
|
229
|
+
if format == :svg
|
230
|
+
svg_type = source.global_attr('svg-type')
|
231
|
+
case svg_type
|
232
|
+
when nil, 'static'
|
233
|
+
when 'inline', 'interactive'
|
234
|
+
node.set_option(svg_type)
|
235
|
+
use_absolute_path = true
|
236
|
+
else
|
237
|
+
raise "Unsupported SVG type: #{svg_type}"
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
if use_absolute_path
|
242
|
+
node.set_attr('target', image_file)
|
243
|
+
else
|
244
|
+
node.set_attr('target', image_name)
|
245
|
+
|
246
|
+
if source.global_attr('autoimagesdir')
|
247
|
+
output_base_dir = output_base_dir(parent)
|
248
|
+
if output_base_dir
|
249
|
+
imagesdir = Pathname.new(image_file).relative_path_from(output_base_dir).dirname.to_s
|
250
|
+
node.set_attr('imagesdir', imagesdir)
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
node
|
256
|
+
end
|
257
|
+
|
258
|
+
def scale(size, factor)
|
259
|
+
if match = /(\d+)(.*)/.match(size)
|
260
|
+
value = match[1].to_i
|
261
|
+
unit = match[2]
|
262
|
+
(value * factor).to_i.to_s + unit
|
263
|
+
else
|
264
|
+
size
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
def image_output_dir(parent)
|
269
|
+
images_dir = parent.attr('imagesoutdir', nil, true)
|
270
|
+
|
271
|
+
if images_dir
|
272
|
+
base_dir = nil
|
273
|
+
else
|
274
|
+
base_dir = output_base_dir(parent)
|
275
|
+
images_dir = parent.attr('imagesdir', nil, true)
|
276
|
+
end
|
277
|
+
|
278
|
+
parent.normalize_system_path(images_dir, base_dir)
|
279
|
+
end
|
280
|
+
|
281
|
+
def output_base_dir(parent)
|
282
|
+
parent.normalize_system_path(parent.attr('outdir', nil, true) || doc_option(parent.document, :to_dir))
|
283
|
+
end
|
284
|
+
|
285
|
+
def cache_dir(source, parent)
|
286
|
+
source.global_attr('cachedir') || parent.normalize_system_path('.asciidoctor/diagram', output_base_dir(parent))
|
287
|
+
end
|
288
|
+
|
289
|
+
def create_literal_block(parent, source, format, converter)
|
290
|
+
literal_attributes = source.attributes
|
291
|
+
literal_attributes.delete('target')
|
292
|
+
|
293
|
+
options = converter.collect_options(source)
|
294
|
+
result = converter.convert(source, format, options)
|
295
|
+
|
296
|
+
result.force_encoding(Encoding::UTF_8)
|
297
|
+
Asciidoctor::Block.new parent, :literal, :source => result, :attributes => literal_attributes
|
298
|
+
end
|
299
|
+
|
300
|
+
def doc_option(document, key)
|
301
|
+
if document.respond_to?(:options)
|
302
|
+
value = document.options[key]
|
303
|
+
else
|
304
|
+
value = nil
|
305
|
+
end
|
306
|
+
|
307
|
+
if document.nested? && value.nil?
|
308
|
+
doc_option(document.parent_document, key)
|
309
|
+
else
|
310
|
+
value
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
# Base class for diagram block processors.
|
316
|
+
class DiagramBlockProcessor < Asciidoctor::Extensions::BlockProcessor
|
317
|
+
include DiagramProcessor
|
318
|
+
|
319
|
+
def self.inherited(subclass)
|
320
|
+
subclass.name_positional_attributes ['target', 'format']
|
321
|
+
subclass.contexts [:listing, :literal, :open]
|
322
|
+
subclass.content_model :simple
|
323
|
+
end
|
324
|
+
|
325
|
+
# Creates a ReaderSource from the given reader.
|
326
|
+
#
|
327
|
+
# @return [ReaderSource] a ReaderSource
|
328
|
+
def create_source(parent_block, reader, attributes)
|
329
|
+
ReaderSource.new(self, parent_block, reader, attributes)
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
# Base class for diagram block macro processors.
|
334
|
+
class DiagramBlockMacroProcessor < Asciidoctor::Extensions::BlockMacroProcessor
|
335
|
+
include DiagramProcessor
|
336
|
+
|
337
|
+
def self.inherited(subclass)
|
338
|
+
subclass.name_positional_attributes ['target', 'format']
|
339
|
+
end
|
340
|
+
|
341
|
+
def apply_target_subs(parent, target)
|
342
|
+
if target
|
343
|
+
parent.normalize_system_path(parent.sub_attributes(target, :attribute_missing => 'warn'))
|
344
|
+
else
|
345
|
+
nil
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
# Creates a FileSource using target as the file name.
|
350
|
+
#
|
351
|
+
# @return [FileSource] a FileSource
|
352
|
+
def create_source(parent, target, attributes)
|
353
|
+
FileSource.new(self, parent, apply_target_subs(parent, target), attributes)
|
354
|
+
end
|
355
|
+
end
|
356
|
+
end
|
357
|
+
end
|