asciidoctor-diagram 1.5.19 → 2.0.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.
- checksums.yaml +5 -5
- data/CHANGELOG.adoc +10 -0
- data/README.adoc +22 -9
- data/examples/features.adoc +2 -2
- data/lib/asciidoctor-diagram.rb +1 -0
- data/lib/asciidoctor-diagram/a2s/converter.rb +55 -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/diagram_converter.rb +19 -0
- data/lib/asciidoctor-diagram/diagram_processor.rb +320 -0
- data/lib/asciidoctor-diagram/diagram_source.rb +275 -0
- data/lib/asciidoctor-diagram/ditaa/converter.rb +86 -0
- data/lib/asciidoctor-diagram/ditaa/extension.rb +6 -71
- data/lib/asciidoctor-diagram/erd/converter.rb +31 -0
- data/lib/asciidoctor-diagram/erd/extension.rb +6 -35
- data/lib/asciidoctor-diagram/gnuplot/converter.rb +63 -0
- data/lib/asciidoctor-diagram/gnuplot/extension.rb +6 -62
- data/lib/asciidoctor-diagram/graphviz/converter.rb +32 -0
- data/lib/asciidoctor-diagram/graphviz/extension.rb +6 -35
- data/lib/asciidoctor-diagram/http/server.rb +127 -0
- data/lib/asciidoctor-diagram/lilypond/converter.rb +54 -0
- data/lib/asciidoctor-diagram/lilypond/extension.rb +6 -53
- 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 +178 -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/plantuml/converter.rb +115 -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/converter.rb +44 -0
- data/lib/asciidoctor-diagram/smcat/extension.rb +6 -42
- data/lib/asciidoctor-diagram/svgbob/converter.rb +25 -0
- data/lib/asciidoctor-diagram/svgbob/extension.rb +6 -28
- data/lib/asciidoctor-diagram/syntrax/converter.rb +55 -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/java.rb +1 -1
- data/lib/asciidoctor-diagram/util/java_socket.rb +7 -9
- 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 -54
- data/lib/ditaa-1.3.14.jar +0 -0
- data/lib/plantuml-1.3.14.jar +0 -0
- data/lib/plantuml.jar +0 -0
- data/lib/server-1.3.14.jar +0 -0
- data/spec/bpmn-example.xml +44 -0
- data/spec/bpmn_spec.rb +96 -0
- data/spec/mermaid_spec.rb +33 -1
- data/spec/plantuml_spec.rb +89 -0
- metadata +37 -8
- data/lib/asciidoctor-diagram/extensions.rb +0 -568
- data/lib/ditaa-1.3.13.jar +0 -0
- data/lib/plantuml-1.3.13.jar +0 -0
- data/lib/server-1.3.13.jar +0 -0
data/spec/plantuml_spec.rb
CHANGED
@@ -314,6 +314,77 @@ User --> (Use the application) : Label
|
|
314
314
|
expect(b.attributes['height']).to_not be_nil
|
315
315
|
end
|
316
316
|
|
317
|
+
it "should respect the svg-type attribute when format is set to 'svg'" do
|
318
|
+
doc = <<-eos
|
319
|
+
= Hello, PlantUML!
|
320
|
+
Doc Writer <doc@example.com>
|
321
|
+
|
322
|
+
== First Section
|
323
|
+
|
324
|
+
[plantuml, format="svg", svg-type="inline"]
|
325
|
+
----
|
326
|
+
User -> (Start)
|
327
|
+
User --> (Use the application) : Label
|
328
|
+
|
329
|
+
:Main Admin: ---> (Use the application) : Another label
|
330
|
+
----
|
331
|
+
eos
|
332
|
+
|
333
|
+
d = load_asciidoc doc
|
334
|
+
expect(d).to_not be_nil
|
335
|
+
|
336
|
+
b = d.find { |bl| bl.context == :image }
|
337
|
+
expect(b).to_not be_nil
|
338
|
+
|
339
|
+
expect(b.content_model).to eq :empty
|
340
|
+
|
341
|
+
target = b.attributes['target']
|
342
|
+
expect(target).to_not be_nil
|
343
|
+
expect(target).to match(/\.svg/)
|
344
|
+
expect(File.exist?(target)).to be true
|
345
|
+
|
346
|
+
expect(b.attributes['opts']).to eq('inline')
|
347
|
+
|
348
|
+
expect(b.attributes['width']).to_not be_nil
|
349
|
+
expect(b.attributes['height']).to_not be_nil
|
350
|
+
end
|
351
|
+
|
352
|
+
it "should respect the diagram-svg-type attribute when format is set to 'svg'" do
|
353
|
+
doc = <<-eos
|
354
|
+
= Hello, PlantUML!
|
355
|
+
:diagram-svg-type: inline
|
356
|
+
Doc Writer <doc@example.com>
|
357
|
+
|
358
|
+
== First Section
|
359
|
+
|
360
|
+
[plantuml, format="svg"]
|
361
|
+
----
|
362
|
+
User -> (Start)
|
363
|
+
User --> (Use the application) : Label
|
364
|
+
|
365
|
+
:Main Admin: ---> (Use the application) : Another label
|
366
|
+
----
|
367
|
+
eos
|
368
|
+
|
369
|
+
d = load_asciidoc doc
|
370
|
+
expect(d).to_not be_nil
|
371
|
+
|
372
|
+
b = d.find { |bl| bl.context == :image }
|
373
|
+
expect(b).to_not be_nil
|
374
|
+
|
375
|
+
expect(b.content_model).to eq :empty
|
376
|
+
|
377
|
+
target = b.attributes['target']
|
378
|
+
expect(target).to_not be_nil
|
379
|
+
expect(target).to match(/\.svg/)
|
380
|
+
expect(File.exist?(target)).to be true
|
381
|
+
|
382
|
+
expect(b.attributes['opts']).to eq('inline')
|
383
|
+
|
384
|
+
expect(b.attributes['width']).to_not be_nil
|
385
|
+
expect(b.attributes['height']).to_not be_nil
|
386
|
+
end
|
387
|
+
|
317
388
|
it "should generate literal blocks when format is set to 'txt'" do
|
318
389
|
doc = <<-eos
|
319
390
|
= Hello, PlantUML!
|
@@ -1074,4 +1145,22 @@ Doc Writer <doc@example.com>
|
|
1074
1145
|
expect(b.attributes['width']).to_not be_nil
|
1075
1146
|
expect(b.attributes['height']).to_not be_nil
|
1076
1147
|
end
|
1148
|
+
|
1149
|
+
it "should report syntax errors" do
|
1150
|
+
doc = <<-eos
|
1151
|
+
= Hello, PlantUML!
|
1152
|
+
Doc Writer <doc@example.com>
|
1153
|
+
|
1154
|
+
== First Section
|
1155
|
+
|
1156
|
+
[plantuml,format="svg"]
|
1157
|
+
----
|
1158
|
+
Bob; Alice; foo
|
1159
|
+
----
|
1160
|
+
eos
|
1161
|
+
|
1162
|
+
expect {
|
1163
|
+
load_asciidoc doc
|
1164
|
+
}.to raise_error(/syntax error/i)
|
1165
|
+
end
|
1077
1166
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: asciidoctor-diagram
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pepijn Van Eeckhoudt
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-12-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -92,42 +92,66 @@ files:
|
|
92
92
|
- images/asciidoctor-diagram-process.png
|
93
93
|
- lib/asciidoctor-diagram.rb
|
94
94
|
- lib/asciidoctor-diagram/a2s.rb
|
95
|
+
- lib/asciidoctor-diagram/a2s/converter.rb
|
95
96
|
- lib/asciidoctor-diagram/a2s/extension.rb
|
96
97
|
- lib/asciidoctor-diagram/blockdiag.rb
|
98
|
+
- lib/asciidoctor-diagram/blockdiag/converter.rb
|
97
99
|
- lib/asciidoctor-diagram/blockdiag/extension.rb
|
100
|
+
- lib/asciidoctor-diagram/bpmn.rb
|
101
|
+
- lib/asciidoctor-diagram/bpmn/converter.rb
|
102
|
+
- lib/asciidoctor-diagram/bpmn/extension.rb
|
103
|
+
- lib/asciidoctor-diagram/diagram_converter.rb
|
104
|
+
- lib/asciidoctor-diagram/diagram_processor.rb
|
105
|
+
- lib/asciidoctor-diagram/diagram_source.rb
|
98
106
|
- lib/asciidoctor-diagram/ditaa.rb
|
107
|
+
- lib/asciidoctor-diagram/ditaa/converter.rb
|
99
108
|
- lib/asciidoctor-diagram/ditaa/extension.rb
|
100
109
|
- lib/asciidoctor-diagram/erd.rb
|
110
|
+
- lib/asciidoctor-diagram/erd/converter.rb
|
101
111
|
- lib/asciidoctor-diagram/erd/extension.rb
|
102
|
-
- lib/asciidoctor-diagram/extensions.rb
|
103
112
|
- lib/asciidoctor-diagram/gnuplot.rb
|
113
|
+
- lib/asciidoctor-diagram/gnuplot/converter.rb
|
104
114
|
- lib/asciidoctor-diagram/gnuplot/extension.rb
|
105
115
|
- lib/asciidoctor-diagram/graphviz.rb
|
116
|
+
- lib/asciidoctor-diagram/graphviz/converter.rb
|
106
117
|
- lib/asciidoctor-diagram/graphviz/extension.rb
|
118
|
+
- lib/asciidoctor-diagram/http/server.rb
|
107
119
|
- lib/asciidoctor-diagram/lilypond.rb
|
120
|
+
- lib/asciidoctor-diagram/lilypond/converter.rb
|
108
121
|
- lib/asciidoctor-diagram/lilypond/extension.rb
|
109
122
|
- lib/asciidoctor-diagram/meme.rb
|
123
|
+
- lib/asciidoctor-diagram/meme/converter.rb
|
110
124
|
- lib/asciidoctor-diagram/meme/extension.rb
|
111
125
|
- lib/asciidoctor-diagram/mermaid.rb
|
126
|
+
- lib/asciidoctor-diagram/mermaid/converter.rb
|
112
127
|
- lib/asciidoctor-diagram/mermaid/extension.rb
|
113
128
|
- lib/asciidoctor-diagram/msc.rb
|
129
|
+
- lib/asciidoctor-diagram/msc/converter.rb
|
114
130
|
- lib/asciidoctor-diagram/msc/extension.rb
|
115
131
|
- lib/asciidoctor-diagram/nomnoml.rb
|
132
|
+
- lib/asciidoctor-diagram/nomnoml/converter.rb
|
116
133
|
- lib/asciidoctor-diagram/nomnoml/extension.rb
|
117
134
|
- lib/asciidoctor-diagram/plantuml.rb
|
135
|
+
- lib/asciidoctor-diagram/plantuml/converter.rb
|
118
136
|
- lib/asciidoctor-diagram/plantuml/extension.rb
|
119
137
|
- lib/asciidoctor-diagram/salt.rb
|
120
138
|
- lib/asciidoctor-diagram/shaape.rb
|
139
|
+
- lib/asciidoctor-diagram/shaape/converter.rb
|
121
140
|
- lib/asciidoctor-diagram/shaape/extension.rb
|
122
141
|
- lib/asciidoctor-diagram/smcat.rb
|
142
|
+
- lib/asciidoctor-diagram/smcat/converter.rb
|
123
143
|
- lib/asciidoctor-diagram/smcat/extension.rb
|
124
144
|
- lib/asciidoctor-diagram/svgbob.rb
|
145
|
+
- lib/asciidoctor-diagram/svgbob/converter.rb
|
125
146
|
- lib/asciidoctor-diagram/svgbob/extension.rb
|
126
147
|
- lib/asciidoctor-diagram/syntrax.rb
|
148
|
+
- lib/asciidoctor-diagram/syntrax/converter.rb
|
127
149
|
- lib/asciidoctor-diagram/syntrax/extension.rb
|
128
150
|
- lib/asciidoctor-diagram/tikz.rb
|
151
|
+
- lib/asciidoctor-diagram/tikz/converter.rb
|
129
152
|
- lib/asciidoctor-diagram/tikz/extension.rb
|
130
153
|
- lib/asciidoctor-diagram/umlet.rb
|
154
|
+
- lib/asciidoctor-diagram/umlet/converter.rb
|
131
155
|
- lib/asciidoctor-diagram/umlet/extension.rb
|
132
156
|
- lib/asciidoctor-diagram/util/binaryio.rb
|
133
157
|
- lib/asciidoctor-diagram/util/cli.rb
|
@@ -142,19 +166,23 @@ files:
|
|
142
166
|
- lib/asciidoctor-diagram/util/svg.rb
|
143
167
|
- lib/asciidoctor-diagram/util/which.rb
|
144
168
|
- lib/asciidoctor-diagram/vega.rb
|
169
|
+
- lib/asciidoctor-diagram/vega/converter.rb
|
145
170
|
- lib/asciidoctor-diagram/vega/extension.rb
|
146
171
|
- lib/asciidoctor-diagram/version.rb
|
147
172
|
- lib/asciidoctor-diagram/wavedrom.rb
|
173
|
+
- lib/asciidoctor-diagram/wavedrom/converter.rb
|
148
174
|
- lib/asciidoctor-diagram/wavedrom/extension.rb
|
149
175
|
- lib/batik-all-1.10.jar
|
150
|
-
- lib/ditaa-1.3.
|
176
|
+
- lib/ditaa-1.3.14.jar
|
151
177
|
- lib/ditaamini-0.12.jar
|
152
178
|
- lib/jlatexmath-minimal-1.0.5.jar
|
153
|
-
- lib/plantuml-1.3.
|
179
|
+
- lib/plantuml-1.3.14.jar
|
154
180
|
- lib/plantuml.jar
|
155
|
-
- lib/server-1.3.
|
181
|
+
- lib/server-1.3.14.jar
|
156
182
|
- spec/a2s_spec.rb
|
157
183
|
- spec/blockdiag_spec.rb
|
184
|
+
- spec/bpmn-example.xml
|
185
|
+
- spec/bpmn_spec.rb
|
158
186
|
- spec/ditaa_spec.rb
|
159
187
|
- spec/erd_spec.rb
|
160
188
|
- spec/gnuplot_spec.rb
|
@@ -194,8 +222,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
194
222
|
- !ruby/object:Gem::Version
|
195
223
|
version: '0'
|
196
224
|
requirements: []
|
197
|
-
|
198
|
-
rubygems_version: 2.5.1
|
225
|
+
rubygems_version: 3.0.3
|
199
226
|
signing_key:
|
200
227
|
specification_version: 4
|
201
228
|
summary: An extension for asciidoctor that adds support for UML diagram generation
|
@@ -203,6 +230,8 @@ summary: An extension for asciidoctor that adds support for UML diagram generati
|
|
203
230
|
test_files:
|
204
231
|
- spec/a2s_spec.rb
|
205
232
|
- spec/blockdiag_spec.rb
|
233
|
+
- spec/bpmn-example.xml
|
234
|
+
- spec/bpmn_spec.rb
|
206
235
|
- spec/ditaa_spec.rb
|
207
236
|
- spec/erd_spec.rb
|
208
237
|
- spec/gnuplot_spec.rb
|
@@ -1,568 +0,0 @@
|
|
1
|
-
require 'asciidoctor' unless defined? ::Asciidoctor::VERSION
|
2
|
-
require 'asciidoctor/extensions'
|
3
|
-
require 'asciidoctor/logging'
|
4
|
-
require 'digest'
|
5
|
-
require 'json'
|
6
|
-
require 'fileutils'
|
7
|
-
require_relative 'version'
|
8
|
-
require_relative 'util/java'
|
9
|
-
require_relative 'util/gif'
|
10
|
-
require_relative 'util/pdf'
|
11
|
-
require_relative 'util/png'
|
12
|
-
require_relative 'util/svg'
|
13
|
-
|
14
|
-
module Asciidoctor
|
15
|
-
module Diagram
|
16
|
-
module Extensions
|
17
|
-
|
18
|
-
# Provides the means for diagram processors to register supported output formats and image
|
19
|
-
# generation routines
|
20
|
-
module FormatRegistry
|
21
|
-
# Registers a supported format. The first registered format becomes the default format for the block
|
22
|
-
# processor.
|
23
|
-
#
|
24
|
-
# @param [Symbol] format the format name
|
25
|
-
# @param [Symbol] type a symbol indicating the type of block that should be generated; either :image or :literal
|
26
|
-
# @yieldparam parent [Asciidoctor::AbstractNode] the asciidoc block that is being processed
|
27
|
-
# @yieldparam source [DiagramSource] the source object
|
28
|
-
# @yieldreturn [String] the generated diagram
|
29
|
-
#
|
30
|
-
# Examples
|
31
|
-
#
|
32
|
-
# register_format(:png, :image ) do |parent_block, source|
|
33
|
-
# File.read(source.to_s)
|
34
|
-
# end
|
35
|
-
def register_format(format, type, &block)
|
36
|
-
raise "Unsupported output type: #{type}" unless type == :image || type == :literal
|
37
|
-
|
38
|
-
unless defined?(@default_format)
|
39
|
-
@default_format = format
|
40
|
-
end
|
41
|
-
|
42
|
-
formats[format] = {
|
43
|
-
:type => type,
|
44
|
-
:generator => block
|
45
|
-
}
|
46
|
-
end
|
47
|
-
|
48
|
-
# Returns the registered formats
|
49
|
-
#
|
50
|
-
# @return [Hash]
|
51
|
-
# @api private
|
52
|
-
def formats
|
53
|
-
@formats ||= {}
|
54
|
-
end
|
55
|
-
|
56
|
-
# Returns the default format
|
57
|
-
#
|
58
|
-
# @return [Symbol] the default format
|
59
|
-
# @api private
|
60
|
-
def default_format
|
61
|
-
@default_format
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
# Mixin that provides the basic machinery for image generation.
|
66
|
-
# When this module is included it will include the FormatRegistry into the singleton class of the target class.
|
67
|
-
module DiagramProcessor
|
68
|
-
include Asciidoctor::Logging
|
69
|
-
|
70
|
-
IMAGE_PARAMS = {
|
71
|
-
:svg => {
|
72
|
-
:encoding => Encoding::UTF_8,
|
73
|
-
:decoder => SVG
|
74
|
-
},
|
75
|
-
:gif => {
|
76
|
-
:encoding => Encoding::ASCII_8BIT,
|
77
|
-
:decoder => GIF
|
78
|
-
},
|
79
|
-
:png => {
|
80
|
-
:encoding => Encoding::ASCII_8BIT,
|
81
|
-
:decoder => PNG
|
82
|
-
},
|
83
|
-
:pdf => {
|
84
|
-
:encoding => Encoding::ASCII_8BIT,
|
85
|
-
:decoder => PDF
|
86
|
-
}
|
87
|
-
}
|
88
|
-
|
89
|
-
def self.included(mod)
|
90
|
-
mod.use_dsl
|
91
|
-
class << mod
|
92
|
-
include FormatRegistry
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
# Processes the diagram block or block macro by converting it into an image or literal block.
|
97
|
-
#
|
98
|
-
# @param parent [Asciidoctor::AbstractBlock] the parent asciidoc block of the block or block macro being processed
|
99
|
-
# @param reader_or_target [Asciidoctor::Reader, String] a reader that provides the contents of a block or the
|
100
|
-
# target value of a block macro
|
101
|
-
# @param attributes [Hash] the attributes of the block or block macro
|
102
|
-
# @return [Asciidoctor::AbstractBlock] a new block that replaces the original block or block macro
|
103
|
-
def process(parent, reader_or_target, attributes)
|
104
|
-
location = parent.document.reader.cursor_at_mark
|
105
|
-
|
106
|
-
source = create_source(parent, reader_or_target, attributes.dup)
|
107
|
-
|
108
|
-
begin
|
109
|
-
format = source.attributes.delete('format') || source.attr('format', self.class.default_format, name)
|
110
|
-
format = format.to_sym if format.respond_to?(:to_sym)
|
111
|
-
|
112
|
-
raise "Format undefined" unless format
|
113
|
-
|
114
|
-
generator_info = self.class.formats[format]
|
115
|
-
|
116
|
-
raise "#{self.class.name} does not support output format #{format}" unless generator_info
|
117
|
-
|
118
|
-
title = source.attributes.delete 'title'
|
119
|
-
caption = source.attributes.delete 'caption'
|
120
|
-
|
121
|
-
case generator_info[:type]
|
122
|
-
when :literal
|
123
|
-
block = create_literal_block(parent, source, generator_info)
|
124
|
-
else
|
125
|
-
block = create_image_block(parent, source, format, generator_info)
|
126
|
-
end
|
127
|
-
|
128
|
-
block.title = title
|
129
|
-
block.assign_caption(caption, 'figure')
|
130
|
-
block
|
131
|
-
rescue => e
|
132
|
-
case source.attr('on-error', 'log', 'diagram')
|
133
|
-
when 'abort'
|
134
|
-
raise e
|
135
|
-
else
|
136
|
-
text = "Failed to generate image: #{e.message}"
|
137
|
-
warn_msg = text.dup
|
138
|
-
if $VERBOSE
|
139
|
-
warn_msg << "\n" << e.backtrace.join("\n")
|
140
|
-
end
|
141
|
-
|
142
|
-
logger.error message_with_context warn_msg, source_location: location
|
143
|
-
|
144
|
-
text << "\n"
|
145
|
-
text << source.code
|
146
|
-
Asciidoctor::Block.new parent, :listing, :source => text, :attributes => attributes
|
147
|
-
end
|
148
|
-
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
protected
|
153
|
-
|
154
|
-
# Creates a DiagramSource object for the block or block macro being processed. Classes using this
|
155
|
-
# mixin must implement this method.
|
156
|
-
#
|
157
|
-
# @param parent_block [Asciidoctor::AbstractBlock] the parent asciidoc block of the block or block macro being processed
|
158
|
-
# @param reader_or_target [Asciidoctor::Reader, String] a reader that provides the contents of a block or the
|
159
|
-
# target value of a block macro
|
160
|
-
# @param attributes [Hash] the attributes of the block or block macro
|
161
|
-
#
|
162
|
-
# @return [DiagramSource] an object that implements the interface described by DiagramSource
|
163
|
-
#
|
164
|
-
# @abstract
|
165
|
-
def create_source(parent_block, reader_or_target, attributes)
|
166
|
-
raise NotImplementedError.new
|
167
|
-
end
|
168
|
-
|
169
|
-
private
|
170
|
-
DIGIT_CHAR_RANGE = ('0'.ord)..('9'.ord)
|
171
|
-
|
172
|
-
def create_image_block(parent, source, format, generator_info)
|
173
|
-
image_name = "#{source.image_name}.#{format}"
|
174
|
-
image_dir = image_output_dir(parent)
|
175
|
-
cache_dir = cache_dir(parent)
|
176
|
-
image_file = parent.normalize_system_path image_name, image_dir
|
177
|
-
metadata_file = parent.normalize_system_path "#{image_name}.cache", cache_dir
|
178
|
-
|
179
|
-
if File.exist? metadata_file
|
180
|
-
metadata = File.open(metadata_file, 'r') { |f| JSON.load f }
|
181
|
-
else
|
182
|
-
metadata = {}
|
183
|
-
end
|
184
|
-
|
185
|
-
image_attributes = source.attributes
|
186
|
-
|
187
|
-
if !File.exist?(image_file) || source.should_process?(image_file, metadata)
|
188
|
-
params = IMAGE_PARAMS[format]
|
189
|
-
|
190
|
-
result = instance_exec(parent, source, &generator_info[:generator])
|
191
|
-
|
192
|
-
result.force_encoding(params[:encoding])
|
193
|
-
|
194
|
-
metadata = source.create_image_metadata
|
195
|
-
metadata['width'], metadata['height'] = params[:decoder].get_image_size(result)
|
196
|
-
|
197
|
-
FileUtils.mkdir_p(File.dirname(image_file)) unless Dir.exist?(File.dirname(image_file))
|
198
|
-
File.open(image_file, 'wb') { |f| f.write result }
|
199
|
-
|
200
|
-
FileUtils.mkdir_p(File.dirname(metadata_file)) unless Dir.exist?(File.dirname(metadata_file))
|
201
|
-
File.open(metadata_file, 'w') { |f| JSON.dump(metadata, f) }
|
202
|
-
end
|
203
|
-
|
204
|
-
image_attributes['target'] = parent.attr('data-uri', nil, true) ? image_file : image_name
|
205
|
-
|
206
|
-
scale = image_attributes['scale']
|
207
|
-
if scalematch = /(\d+(?:\.\d+))/.match(scale)
|
208
|
-
scale_factor = scalematch[1].to_f
|
209
|
-
else
|
210
|
-
scale_factor = 1.0
|
211
|
-
end
|
212
|
-
|
213
|
-
if /html/i =~ parent.document.attributes['backend']
|
214
|
-
image_attributes.delete('scale')
|
215
|
-
if metadata['width'] && !image_attributes['width']
|
216
|
-
image_attributes['width'] = (metadata['width'] * scale_factor).to_i
|
217
|
-
end
|
218
|
-
if metadata['height'] && !image_attributes['height']
|
219
|
-
image_attributes['height'] = (metadata['height'] * scale_factor).to_i
|
220
|
-
end
|
221
|
-
end
|
222
|
-
|
223
|
-
image_attributes['alt'] ||= if title_text = image_attributes['title']
|
224
|
-
title_text
|
225
|
-
elsif target = image_attributes['target']
|
226
|
-
(File.basename(target, File.extname(target)) || '').tr '_-', ' '
|
227
|
-
else
|
228
|
-
'Diagram'
|
229
|
-
end
|
230
|
-
|
231
|
-
image_attributes['alt'] = parent.sub_specialchars image_attributes['alt']
|
232
|
-
|
233
|
-
parent.document.register(:images, image_name)
|
234
|
-
if (scaledwidth = image_attributes['scaledwidth'])
|
235
|
-
# append % to scaledwidth if ends in number (no units present)
|
236
|
-
if DIGIT_CHAR_RANGE.include?((scaledwidth[-1] || 0).ord)
|
237
|
-
image_attributes['scaledwidth'] = %(#{scaledwidth}%)
|
238
|
-
end
|
239
|
-
end
|
240
|
-
|
241
|
-
Asciidoctor::Block.new parent, :image, :content_model => :empty, :attributes => image_attributes
|
242
|
-
end
|
243
|
-
|
244
|
-
def scale(size, factor)
|
245
|
-
if match = /(\d+)(.*)/.match(size)
|
246
|
-
value = match[1].to_i
|
247
|
-
unit = match[2]
|
248
|
-
(value * factor).to_i.to_s + unit
|
249
|
-
else
|
250
|
-
size
|
251
|
-
end
|
252
|
-
end
|
253
|
-
|
254
|
-
def image_output_dir(parent)
|
255
|
-
document = parent.document
|
256
|
-
|
257
|
-
images_dir = parent.attr('imagesoutdir', nil, true)
|
258
|
-
|
259
|
-
if images_dir
|
260
|
-
base_dir = nil
|
261
|
-
else
|
262
|
-
base_dir = parent.attr('outdir', nil, true) || doc_option(document, :to_dir)
|
263
|
-
images_dir = parent.attr('imagesdir', nil, true)
|
264
|
-
end
|
265
|
-
|
266
|
-
parent.normalize_system_path(images_dir, base_dir)
|
267
|
-
end
|
268
|
-
|
269
|
-
def cache_dir(parent)
|
270
|
-
document = parent.document
|
271
|
-
cache_dir = '.asciidoctor/diagram'
|
272
|
-
base_dir = parent.attr('outdir', nil, true) || doc_option(document, :to_dir)
|
273
|
-
parent.normalize_system_path(cache_dir, base_dir)
|
274
|
-
end
|
275
|
-
|
276
|
-
def create_literal_block(parent, source, generator_info)
|
277
|
-
literal_attributes = source.attributes
|
278
|
-
literal_attributes.delete('target')
|
279
|
-
|
280
|
-
result = instance_exec(parent, source, &generator_info[:generator])
|
281
|
-
|
282
|
-
result.force_encoding(Encoding::UTF_8)
|
283
|
-
Asciidoctor::Block.new parent, :literal, :source => result, :attributes => literal_attributes
|
284
|
-
end
|
285
|
-
|
286
|
-
def doc_option(document, key)
|
287
|
-
if document.respond_to?(:options)
|
288
|
-
value = document.options[key]
|
289
|
-
else
|
290
|
-
value = nil
|
291
|
-
end
|
292
|
-
|
293
|
-
if document.nested? && value.nil?
|
294
|
-
doc_option(document.parent_document, key)
|
295
|
-
else
|
296
|
-
value
|
297
|
-
end
|
298
|
-
end
|
299
|
-
end
|
300
|
-
|
301
|
-
# Base class for diagram block processors.
|
302
|
-
class DiagramBlockProcessor < Asciidoctor::Extensions::BlockProcessor
|
303
|
-
include DiagramProcessor
|
304
|
-
|
305
|
-
def self.inherited(subclass)
|
306
|
-
subclass.name_positional_attributes ['target', 'format']
|
307
|
-
subclass.contexts [:listing, :literal, :open]
|
308
|
-
subclass.content_model :simple
|
309
|
-
end
|
310
|
-
|
311
|
-
# Creates a ReaderSource from the given reader.
|
312
|
-
#
|
313
|
-
# @return [ReaderSource] a ReaderSource
|
314
|
-
def create_source(parent_block, reader, attributes)
|
315
|
-
ReaderSource.new(parent_block, reader, attributes)
|
316
|
-
end
|
317
|
-
end
|
318
|
-
|
319
|
-
# Base class for diagram block macro processors.
|
320
|
-
class DiagramBlockMacroProcessor < Asciidoctor::Extensions::BlockMacroProcessor
|
321
|
-
include DiagramProcessor
|
322
|
-
|
323
|
-
def self.inherited(subclass)
|
324
|
-
subclass.name_positional_attributes ['target', 'format']
|
325
|
-
end
|
326
|
-
|
327
|
-
def apply_target_subs(parent, target)
|
328
|
-
if target
|
329
|
-
parent.normalize_system_path(parent.sub_attributes(target, :attribute_missing => 'warn'))
|
330
|
-
else
|
331
|
-
nil
|
332
|
-
end
|
333
|
-
end
|
334
|
-
|
335
|
-
# Creates a FileSource using target as the file name.
|
336
|
-
#
|
337
|
-
# @return [FileSource] a FileSource
|
338
|
-
def create_source(parent, target, attributes)
|
339
|
-
FileSource.new(parent, apply_target_subs(parent, target), attributes)
|
340
|
-
end
|
341
|
-
end
|
342
|
-
|
343
|
-
# This module describes the duck-typed interface that diagram sources must implement. Implementations
|
344
|
-
# may include this module but it is not required.
|
345
|
-
module DiagramSource
|
346
|
-
# @return [String] the base name for the image file that will be produced
|
347
|
-
# @abstract
|
348
|
-
def image_name
|
349
|
-
raise NotImplementedError.new
|
350
|
-
end
|
351
|
-
|
352
|
-
# @return [String] the String representation of the source code for the diagram
|
353
|
-
# @abstract
|
354
|
-
def code
|
355
|
-
raise NotImplementedError.new
|
356
|
-
end
|
357
|
-
|
358
|
-
# Get the value for the specified attribute. First look in the attributes on
|
359
|
-
# this document and return the value of the attribute if found. Otherwise, if
|
360
|
-
# this document is a child of the Document document, look in the attributes of the
|
361
|
-
# Document document and return the value of the attribute if found. Otherwise,
|
362
|
-
# return the default value, which defaults to nil.
|
363
|
-
#
|
364
|
-
# @param name [String, Symbol] the name of the attribute to lookup
|
365
|
-
# @param default_value [Object] the value to return if the attribute is not found
|
366
|
-
# @inherit [Boolean, String] indicates whether to check for the attribute on the AsciiDoctor::Document if not found on this document.
|
367
|
-
# When a non-nil String is given the an attribute name "#{inherit}-#{name}" is looked for on the document.
|
368
|
-
#
|
369
|
-
# @return the value of the attribute or the default value if the attribute is not found in the attributes of this node or the document node
|
370
|
-
# @abstract
|
371
|
-
def attr(name, default_value = nil, inherit = nil)
|
372
|
-
raise NotImplementedError.new
|
373
|
-
end
|
374
|
-
|
375
|
-
# @return [String] the base directory against which relative paths in this diagram should be resolved
|
376
|
-
# @abstract
|
377
|
-
def base_dir
|
378
|
-
attr('docdir', nil, true)
|
379
|
-
end
|
380
|
-
|
381
|
-
# Alias for code
|
382
|
-
def to_s
|
383
|
-
code
|
384
|
-
end
|
385
|
-
|
386
|
-
# Determines if the diagram should be regenerated or not. The default implementation of this method simply
|
387
|
-
# returns true.
|
388
|
-
#
|
389
|
-
# @param image_file [String] the path to the previously generated version of the image
|
390
|
-
# @param image_metadata [Hash] the image metadata Hash that was stored during the previous diagram generation pass
|
391
|
-
# @return [Boolean] true if the diagram should be regenerated; false otherwise
|
392
|
-
def should_process?(image_file, image_metadata)
|
393
|
-
true
|
394
|
-
end
|
395
|
-
|
396
|
-
# Creates an image metadata Hash that will be stored to disk alongside the generated image file. The contents
|
397
|
-
# of this Hash are reread during subsequent document processing and then passed to the should_process? method
|
398
|
-
# where it can be used to determine if the diagram should be regenerated or not.
|
399
|
-
# The default implementation returns an empty Hash.
|
400
|
-
# @return [Hash] a Hash containing metadata
|
401
|
-
def create_image_metadata
|
402
|
-
{}
|
403
|
-
end
|
404
|
-
end
|
405
|
-
|
406
|
-
# Base class for diagram source implementations that uses an md5 checksum of the source code of a diagram to
|
407
|
-
# determine if it has been updated or not.
|
408
|
-
class BasicSource
|
409
|
-
include DiagramSource
|
410
|
-
|
411
|
-
attr_reader :attributes
|
412
|
-
|
413
|
-
def initialize(parent_block, attributes)
|
414
|
-
@parent_block = parent_block
|
415
|
-
@attributes = attributes
|
416
|
-
end
|
417
|
-
|
418
|
-
def image_name
|
419
|
-
attr('target', 'diag-' + checksum)
|
420
|
-
end
|
421
|
-
|
422
|
-
def attr(name, default_value=nil, inherit=nil)
|
423
|
-
name = name.to_s if ::Symbol === name
|
424
|
-
|
425
|
-
value = @attributes[name]
|
426
|
-
|
427
|
-
if value.nil? && inherit
|
428
|
-
case inherit
|
429
|
-
when String, Symbol
|
430
|
-
value = @parent_block.attr("#{inherit.to_s}-#{name}", default_value, true)
|
431
|
-
else
|
432
|
-
value = @parent_block.attr(name, default_value, true)
|
433
|
-
end
|
434
|
-
end
|
435
|
-
|
436
|
-
value || default_value
|
437
|
-
end
|
438
|
-
|
439
|
-
def should_process?(image_file, image_metadata)
|
440
|
-
image_metadata['checksum'] != checksum
|
441
|
-
end
|
442
|
-
|
443
|
-
def create_image_metadata
|
444
|
-
{'checksum' => checksum}
|
445
|
-
end
|
446
|
-
|
447
|
-
def checksum
|
448
|
-
@checksum ||= compute_checksum(code)
|
449
|
-
end
|
450
|
-
|
451
|
-
protected
|
452
|
-
def resolve_diagram_subs
|
453
|
-
if @attributes.key? 'subs'
|
454
|
-
@parent_block.resolve_block_subs @attributes['subs'], nil, 'diagram'
|
455
|
-
else
|
456
|
-
[]
|
457
|
-
end
|
458
|
-
end
|
459
|
-
|
460
|
-
private
|
461
|
-
def compute_checksum(code)
|
462
|
-
md5 = Digest::MD5.new
|
463
|
-
md5 << code
|
464
|
-
@attributes.each do |k, v|
|
465
|
-
md5 << k.to_s if k
|
466
|
-
md5 << v.to_s if v
|
467
|
-
end
|
468
|
-
md5.hexdigest
|
469
|
-
end
|
470
|
-
end
|
471
|
-
|
472
|
-
# A diagram source that retrieves the code for the diagram from the contents of a block.
|
473
|
-
class ReaderSource < BasicSource
|
474
|
-
include DiagramSource
|
475
|
-
|
476
|
-
def initialize(parent_block, reader, attributes)
|
477
|
-
super(parent_block, attributes)
|
478
|
-
@reader = reader
|
479
|
-
end
|
480
|
-
|
481
|
-
def code
|
482
|
-
@code ||= @parent_block.apply_subs(@reader.lines, resolve_diagram_subs).join("\n")
|
483
|
-
end
|
484
|
-
end
|
485
|
-
|
486
|
-
# A diagram source that retrieves the code for a diagram from an external source file.
|
487
|
-
class FileSource < BasicSource
|
488
|
-
def initialize(parent_block, file_name, attributes)
|
489
|
-
super(parent_block, attributes)
|
490
|
-
@file_name = file_name
|
491
|
-
end
|
492
|
-
|
493
|
-
def base_dir
|
494
|
-
if @file_name
|
495
|
-
File.dirname(@file_name)
|
496
|
-
else
|
497
|
-
super
|
498
|
-
end
|
499
|
-
end
|
500
|
-
|
501
|
-
def image_name
|
502
|
-
if @attributes['target']
|
503
|
-
super
|
504
|
-
elsif @file_name
|
505
|
-
File.basename(@file_name, File.extname(@file_name))
|
506
|
-
else
|
507
|
-
checksum
|
508
|
-
end
|
509
|
-
end
|
510
|
-
|
511
|
-
def should_process?(image_file, image_metadata)
|
512
|
-
(@file_name && File.mtime(@file_name) > File.mtime(image_file)) || super
|
513
|
-
end
|
514
|
-
|
515
|
-
def code
|
516
|
-
@code ||= read_code
|
517
|
-
end
|
518
|
-
|
519
|
-
def read_code
|
520
|
-
if @file_name
|
521
|
-
lines = File.readlines(@file_name)
|
522
|
-
lines = prepare_source_array(lines)
|
523
|
-
@parent_block.apply_subs(lines, resolve_diagram_subs).join("\n")
|
524
|
-
else
|
525
|
-
''
|
526
|
-
end
|
527
|
-
end
|
528
|
-
|
529
|
-
private
|
530
|
-
|
531
|
-
# Byte arrays for UTF-* Byte Order Marks
|
532
|
-
BOM_BYTES_UTF_8 = [0xef, 0xbb, 0xbf]
|
533
|
-
BOM_BYTES_UTF_16LE = [0xff, 0xfe]
|
534
|
-
BOM_BYTES_UTF_16BE = [0xfe, 0xff]
|
535
|
-
|
536
|
-
# Prepare the source data Array for parsing.
|
537
|
-
#
|
538
|
-
# Encodes the data to UTF-8, if necessary, and removes any trailing
|
539
|
-
# whitespace from every line.
|
540
|
-
#
|
541
|
-
# If a BOM is found at the beginning of the data, a best attempt is made to
|
542
|
-
# encode it to UTF-8 from the specified source encoding.
|
543
|
-
#
|
544
|
-
# data - the source data Array to prepare (no nil entries allowed)
|
545
|
-
#
|
546
|
-
# returns a String Array of prepared lines
|
547
|
-
def prepare_source_array data
|
548
|
-
return [] if data.empty?
|
549
|
-
if (leading_2_bytes = (leading_bytes = (first = data[0]).unpack 'C3').slice 0, 2) == BOM_BYTES_UTF_16LE
|
550
|
-
data[0] = first.byteslice 2, first.bytesize
|
551
|
-
# NOTE you can't split a UTF-16LE string using .lines when encoding is UTF-8; doing so will cause this line to fail
|
552
|
-
return data.map {|line| (line.encode ::Encoding::UTF_8, ::Encoding::UTF_16LE).rstrip }
|
553
|
-
elsif leading_2_bytes == BOM_BYTES_UTF_16BE
|
554
|
-
data[0] = first.byteslice 2, first.bytesize
|
555
|
-
return data.map {|line| (line.encode ::Encoding::UTF_8, ::Encoding::UTF_16BE).rstrip }
|
556
|
-
elsif leading_bytes == BOM_BYTES_UTF_8
|
557
|
-
data[0] = first.byteslice 3, first.bytesize
|
558
|
-
end
|
559
|
-
if first.encoding == ::Encoding::UTF_8
|
560
|
-
data.map {|line| line.rstrip }
|
561
|
-
else
|
562
|
-
data.map {|line| (line.encode ::Encoding::UTF_8).rstrip }
|
563
|
-
end
|
564
|
-
end
|
565
|
-
end
|
566
|
-
end
|
567
|
-
end
|
568
|
-
end
|