asciidoctor-diagram 1.4.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.adoc +15 -0
  3. data/README.adoc +252 -95
  4. data/README_zh-CN.adoc +333 -0
  5. data/images/asciidoctor-diagram-classes.png +0 -0
  6. data/images/asciidoctor-diagram-process.png +0 -0
  7. data/lib/{asciidoctor-diagram-java-1.3.8.jar → asciidoctor-diagram-java-1.3.10.jar} +0 -0
  8. data/lib/asciidoctor-diagram.rb +9 -9
  9. data/lib/asciidoctor-diagram/blockdiag.rb +1 -2
  10. data/lib/asciidoctor-diagram/blockdiag/extension.rb +27 -12
  11. data/lib/asciidoctor-diagram/ditaa.rb +1 -2
  12. data/lib/asciidoctor-diagram/ditaa/extension.rb +33 -48
  13. data/lib/asciidoctor-diagram/extensions.rb +85 -18
  14. data/lib/asciidoctor-diagram/graphviz.rb +1 -2
  15. data/lib/asciidoctor-diagram/graphviz/extension.rb +14 -4
  16. data/lib/asciidoctor-diagram/meme.rb +1 -2
  17. data/lib/asciidoctor-diagram/meme/extension.rb +82 -79
  18. data/lib/asciidoctor-diagram/mermaid.rb +1 -2
  19. data/lib/asciidoctor-diagram/mermaid/extension.rb +33 -25
  20. data/lib/asciidoctor-diagram/plantuml.rb +1 -2
  21. data/lib/asciidoctor-diagram/plantuml/extension.rb +33 -22
  22. data/lib/asciidoctor-diagram/salt.rb +1 -2
  23. data/lib/asciidoctor-diagram/shaape.rb +1 -2
  24. data/lib/asciidoctor-diagram/shaape/extension.rb +10 -5
  25. data/lib/asciidoctor-diagram/util/cli_generator.rb +7 -5
  26. data/lib/asciidoctor-diagram/util/java.rb +1 -1
  27. data/lib/asciidoctor-diagram/util/platform.rb +12 -1
  28. data/lib/asciidoctor-diagram/util/which.rb +16 -7
  29. data/lib/asciidoctor-diagram/version.rb +1 -1
  30. data/lib/asciidoctor-diagram/wavedrom.rb +1 -2
  31. data/lib/asciidoctor-diagram/wavedrom/extension.rb +24 -20
  32. data/lib/plantuml.jar +0 -0
  33. data/spec/blockdiag_spec.rb +8 -8
  34. data/spec/ditaa_spec.rb +7 -7
  35. data/spec/graphviz_spec.rb +7 -7
  36. data/spec/meme_spec.rb +2 -2
  37. data/spec/mermaid_spec.rb +11 -11
  38. data/spec/plantuml_spec.rb +156 -34
  39. data/spec/shaape_spec.rb +8 -8
  40. data/spec/test_helper.rb +24 -5
  41. data/spec/wavedrom_spec.rb +11 -11
  42. metadata +6 -3
@@ -1,9 +1,9 @@
1
- require 'asciidoctor-diagram/blockdiag'
2
- require 'asciidoctor-diagram/ditaa'
3
- require 'asciidoctor-diagram/graphviz'
4
- require 'asciidoctor-diagram/meme'
5
- require 'asciidoctor-diagram/mermaid'
6
- require 'asciidoctor-diagram/plantuml'
7
- require 'asciidoctor-diagram/salt'
8
- require 'asciidoctor-diagram/shaape'
9
- require 'asciidoctor-diagram/wavedrom'
1
+ require_relative 'asciidoctor-diagram/blockdiag'
2
+ require_relative 'asciidoctor-diagram/ditaa'
3
+ require_relative 'asciidoctor-diagram/graphviz'
4
+ require_relative 'asciidoctor-diagram/meme'
5
+ require_relative 'asciidoctor-diagram/mermaid'
6
+ require_relative 'asciidoctor-diagram/plantuml'
7
+ require_relative 'asciidoctor-diagram/salt'
8
+ require_relative 'asciidoctor-diagram/shaape'
9
+ require_relative 'asciidoctor-diagram/wavedrom'
@@ -1,5 +1,4 @@
1
- require 'asciidoctor/extensions'
2
- require_relative 'version'
1
+ require_relative 'extensions'
3
2
 
4
3
  Asciidoctor::Extensions.register do
5
4
  require_relative 'blockdiag/extension'
@@ -1,5 +1,6 @@
1
1
  require_relative '../extensions'
2
2
  require_relative '../util/cli_generator'
3
+ require_relative '../util/platform'
3
4
  require_relative '../util/which'
4
5
 
5
6
  module Asciidoctor
@@ -72,7 +73,17 @@ module Asciidoctor
72
73
 
73
74
  # @private
74
75
  module BlockDiag
75
- def self.define_processors(name, &init)
76
+ def self.define_processors(name)
77
+ init = Proc.new do
78
+ include ::Asciidoctor::Diagram::BlockDiag
79
+
80
+ [:png, :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
+
76
87
  block = Class.new(Extensions::DiagramBlockProcessor) do
77
88
  self.instance_eval &init
78
89
  end
@@ -84,20 +95,24 @@ module Asciidoctor
84
95
 
85
96
  ::Asciidoctor::Diagram.const_set("#{name}BlockMacroProcessor", block_macro)
86
97
  end
87
- end
88
98
 
89
- ['BlockDiag', 'SeqDiag', 'ActDiag', 'NwDiag', 'RackDiag', 'PacketDiag'].each do |tool|
90
- BlockDiag.define_processors(tool) do
91
- include Which
99
+ include Which
92
100
 
93
- [:png, :svg].each do |f|
94
- register_format(f, :image) do |c, p|
95
- CliGenerator.generate_stdin(which(p, tool.downcase), f.to_s, c.to_s) do |tool_path, output_path|
96
- [tool_path, '-o', output_path, "-T#{f.to_s}", '-']
97
- end
98
- end
101
+ def blockdiag(tool, parent, source, format)
102
+ cmd_name = tool.downcase
103
+
104
+ # On Debian based systems the Python 3.x packages python3-(act|block|nw|seq)diag executables with
105
+ # a '3' suffix.
106
+ alt_cmd_name = "#{tool.downcase}3"
107
+
108
+ CliGenerator.generate_stdin(which(parent, cmd_name, :alt_cmds => [alt_cmd_name]), format.to_s, source.to_s) do |tool_path, output_path|
109
+ [tool_path, '-o', Platform.native_path(output_path), "-T#{format.to_s}", '-']
99
110
  end
100
111
  end
101
112
  end
113
+
114
+ ['BlockDiag', 'SeqDiag', 'ActDiag', 'NwDiag', 'RackDiag', 'PacketDiag'].each do |tool|
115
+ BlockDiag.define_processors(tool)
116
+ end
102
117
  end
103
- end
118
+ end
@@ -1,5 +1,4 @@
1
- require 'asciidoctor/extensions'
2
- require_relative 'version'
1
+ require_relative 'extensions'
3
2
 
4
3
  Asciidoctor::Extensions.register do
5
4
  require_relative 'ditaa/extension'
@@ -7,19 +7,49 @@ module Asciidoctor
7
7
  module Diagram
8
8
  # @private
9
9
  module Ditaa
10
+ OPTIONS = {
11
+ 'scale' => lambda { |o, v| o << '--scale' << v if v },
12
+ 'tabs' => lambda { |o, v| o << '--tabs' << v if v },
13
+ 'background' => lambda { |o, v| o << '--background' << v if v },
14
+ 'antialias' => lambda { |o, v| o << '--no-antialias' if v == 'false' },
15
+ 'separation' => lambda { |o, v| o << '--no-separation' if v == 'false'},
16
+ 'round-corners' => lambda { |o, v| o << '--round-corners' if v == 'true'},
17
+ 'shadows' => lambda { |o, v| o << '--no-shadows' if v == 'false'},
18
+ 'debug' => lambda { |o, v| o << '--debug' if v == 'true'},
19
+ 'fixed-slope' => lambda { |o, v| o << '--fixed-slope' if v == 'true'},
20
+ 'transparent' => lambda { |o, v| o << '--transparent' if v == 'true'}
21
+ }
22
+
10
23
  JARS = ['ditaamini-0.10.jar'].map do |jar|
11
24
  File.expand_path File.join('../..', jar), File.dirname(__FILE__)
12
25
  end
13
26
  Java.classpath.concat JARS
14
27
 
15
- def ditaa(code, source)
28
+ def self.included(mod)
29
+ mod.register_format(:png, :image) do |parent, source|
30
+ ditaa(parent, source)
31
+ end
32
+ end
33
+
34
+ def ditaa(parent, source)
16
35
  Java.load
17
36
 
37
+ global_attributes = parent.document.attributes
38
+
39
+ options = []
40
+
41
+ OPTIONS.keys.each do |key|
42
+ value = source.attributes.delete(key) || global_attributes["ditaa-option-#{key}"]
43
+ OPTIONS[key].call(options, value)
44
+ end
45
+
46
+ options = options.join(' ')
47
+
18
48
  response = Java.send_request(
19
49
  :url => '/ditaa',
20
- :body => code,
50
+ :body => source.to_s,
21
51
  :headers => {
22
- 'X-Options' => source.options
52
+ 'X-Options' => options
23
53
  }
24
54
  )
25
55
 
@@ -29,51 +59,6 @@ module Asciidoctor
29
59
 
30
60
  response[:body]
31
61
  end
32
-
33
- def self.included(mod)
34
- mod.register_format(:png, :image) do |c, _, source|
35
- ditaa(c.to_s, source)
36
- end
37
- end
38
-
39
- def create_source(parent, reader, attributes)
40
- source = super(parent, reader, attributes)
41
- source.extend DitaaSource
42
-
43
- source.init_ditaa_options(parent, attributes)
44
-
45
- source
46
- end
47
-
48
- module DitaaSource
49
- attr_reader :options
50
-
51
- OPTIONS = {
52
- 'scale' => lambda { |o, v| o << '--scale' << v if v },
53
- 'tabs' => lambda { |o, v| o << '--tabs' << v if v },
54
- 'background' => lambda { |o, v| o << '--background' << v if v },
55
- 'antialias' => lambda { |o, v| o << '--no-antialias' if v == 'false' },
56
- 'separation' => lambda { |o, v| o << '--no-separation' if v == 'false'},
57
- 'round-corners' => lambda { |o, v| o << '--round-corners' if v == 'true'},
58
- 'shadows' => lambda { |o, v| o << '--no-shadows' if v == 'false'},
59
- 'debug' => lambda { |o, v| o << '--debug' if v == 'true'},
60
- 'fixed-slope' => lambda { |o, v| o << '--fixed-slope' if v == 'true'},
61
- 'transparent' => lambda { |o, v| o << '--transparent' if v == 'true'}
62
- }
63
-
64
- def init_ditaa_options(parent, attributes)
65
- global_attributes = parent.document.attributes
66
-
67
- options = []
68
-
69
- OPTIONS.keys.each do |key|
70
- value = attributes.delete(key) || global_attributes["ditaa-option-#{key}"]
71
- OPTIONS[key].call(options, value)
72
- end
73
-
74
- @options = options.join(' ')
75
- end
76
- end
77
62
  end
78
63
 
79
64
  class DitaaBlockProcessor < Extensions::DiagramBlockProcessor
@@ -1,7 +1,9 @@
1
+ require 'asciidoctor' unless defined? ::Asciidoctor::VERSION
1
2
  require 'asciidoctor/extensions'
2
3
  require 'digest'
3
4
  require 'json'
4
5
  require 'fileutils'
6
+ require_relative 'version'
5
7
  require_relative 'util/java'
6
8
  require_relative 'util/gif'
7
9
  require_relative 'util/png'
@@ -143,8 +145,9 @@ module Asciidoctor
143
145
  def create_image_block(parent, source, format, generator_info)
144
146
  image_name = "#{source.image_name}.#{format}"
145
147
  image_dir = image_output_dir(parent)
148
+ cache_dir = cache_dir(parent)
146
149
  image_file = parent.normalize_system_path image_name, image_dir
147
- metadata_file = parent.normalize_system_path "#{image_name}.cache", image_dir
150
+ metadata_file = parent.normalize_system_path "#{image_name}.cache", cache_dir
148
151
 
149
152
  if File.exists? metadata_file
150
153
  metadata = File.open(metadata_file, 'r') { |f| JSON.load f }
@@ -157,7 +160,7 @@ module Asciidoctor
157
160
  if !File.exists?(image_file) || source.should_process?(image_file, metadata)
158
161
  params = IMAGE_PARAMS[format]
159
162
 
160
- result = instance_exec(source, parent, source, &generator_info[:generator])
163
+ result = instance_exec(parent, source, &generator_info[:generator])
161
164
 
162
165
  result.force_encoding(params[:encoding])
163
166
 
@@ -166,6 +169,8 @@ module Asciidoctor
166
169
 
167
170
  FileUtils.mkdir_p(File.dirname(image_file)) unless Dir.exist?(File.dirname(image_file))
168
171
  File.open(image_file, 'wb') { |f| f.write result }
172
+
173
+ FileUtils.mkdir_p(File.dirname(metadata_file)) unless Dir.exist?(File.dirname(metadata_file))
169
174
  File.open(metadata_file, 'w') { |f| JSON.dump(metadata, f) }
170
175
  end
171
176
 
@@ -212,23 +217,30 @@ module Asciidoctor
212
217
  def image_output_dir(parent)
213
218
  document = parent.document
214
219
 
215
- images_dir = document.attr('imagesoutdir')
220
+ images_dir = parent.attr('imagesoutdir')
216
221
 
217
222
  if images_dir
218
223
  base_dir = nil
219
224
  else
220
- base_dir = document.attr('outdir') || (document.respond_to?(:options) && document.options[:to_dir])
221
- images_dir = document.attr('imagesdir')
225
+ base_dir = parent.attr('outdir') || (document.respond_to?(:options) && document.options[:to_dir])
226
+ images_dir = parent.attr('imagesdir')
222
227
  end
223
228
 
224
229
  parent.normalize_system_path(images_dir, base_dir)
225
230
  end
226
231
 
232
+ def cache_dir(parent)
233
+ document = parent.document
234
+ cache_dir = '.asciidoctor/diagram'
235
+ base_dir = parent.attr('outdir') || (document.respond_to?(:options) && document.options[:to_dir])
236
+ parent.normalize_system_path(cache_dir, base_dir)
237
+ end
238
+
227
239
  def create_literal_block(parent, source, generator_info)
228
240
  literal_attributes = source.attributes
229
241
  literal_attributes.delete('target')
230
242
 
231
- result = instance_exec(source, parent, &generator_info[:generator])
243
+ result = instance_exec(parent, source, &generator_info[:generator])
232
244
 
233
245
  result.force_encoding(Encoding::UTF_8)
234
246
  Asciidoctor::Block.new parent, :literal, :source => result, :attributes => literal_attributes
@@ -249,7 +261,7 @@ module Asciidoctor
249
261
  #
250
262
  # @return [ReaderSource] a ReaderSource
251
263
  def create_source(parent, reader, attributes)
252
- ReaderSource.new(reader, attributes)
264
+ ReaderSource.new(parent, reader, attributes)
253
265
  end
254
266
  end
255
267
 
@@ -265,7 +277,7 @@ module Asciidoctor
265
277
  #
266
278
  # @return [FileSource] a FileSource
267
279
  def create_source(parent, target, attributes)
268
- FileSource.new(target.empty? ? nil : parent.normalize_system_path(target, parent.document.base_dir), attributes)
280
+ FileSource.new(parent, target.empty? ? nil : parent.normalize_system_path(target, parent.attr('docdir')), attributes)
269
281
  end
270
282
  end
271
283
 
@@ -284,6 +296,28 @@ module Asciidoctor
284
296
  raise NotImplementedError.new
285
297
  end
286
298
 
299
+ # Get the value for the specified attribute. First look in the attributes on
300
+ # this node and return the value of the attribute if found. Otherwise, if
301
+ # this node is a child of the Document node, look in the attributes of the
302
+ # Document node and return the value of the attribute if found. Otherwise,
303
+ # return the default value, which defaults to nil.
304
+ #
305
+ # @param name [String, Symbol] the name of the attribute to lookup
306
+ # @param default_value [Object] the value to return if the attribute is not found
307
+ # @inherit [Boolean] indicates whether to check for the attribute on the AsciiDoctor::Document if not found on this node
308
+ #
309
+ # @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
310
+ # @abstract
311
+ def attr(name, default_value = nil, inherit = true)
312
+ raise NotImplementedError.new
313
+ end
314
+
315
+ # @return [String] the base directory against which relative paths in this diagram should be resolved
316
+ # @abstract
317
+ def base_dir
318
+ raise NotImplementedError.new
319
+ end
320
+
287
321
  # Alias for code
288
322
  def to_s
289
323
  code
@@ -316,12 +350,23 @@ module Asciidoctor
316
350
 
317
351
  attr_reader :attributes
318
352
 
319
- def initialize(attributes)
353
+ def initialize(parent, attributes)
354
+ @parent = parent
320
355
  @attributes = attributes
321
356
  end
322
357
 
323
358
  def image_name
324
- @attributes['target'] || ('diag-' + checksum)
359
+ attr('target', 'diag-' + checksum)
360
+ end
361
+
362
+ def attr(name, default_value=nil, inherit=nil)
363
+ name = name.to_s if ::Symbol === name
364
+
365
+ if inherit
366
+ @attributes[name] || @parent.attr(name, default_value, true)
367
+ else
368
+ @attributes[name] || default_value
369
+ end
325
370
  end
326
371
 
327
372
  def should_process?(image_file, image_metadata)
@@ -336,11 +381,21 @@ module Asciidoctor
336
381
  @checksum ||= compute_checksum(code)
337
382
  end
338
383
 
384
+ protected
385
+ def resolve_diagram_subs
386
+ if @attributes.key? 'subs'
387
+ subs = @parent.resolve_block_subs @attributes['subs'], nil, 'diagram'
388
+ subs.empty? ? nil : subs
389
+ else
390
+ nil
391
+ end
392
+ end
393
+
339
394
  private
340
395
  def compute_checksum(code)
341
396
  md5 = Digest::MD5.new
342
397
  md5 << code
343
- attributes.each do |k, v|
398
+ @attributes.each do |k, v|
344
399
  md5 << k.to_s if k
345
400
  md5 << v.to_s if v
346
401
  end
@@ -352,23 +407,31 @@ module Asciidoctor
352
407
  class ReaderSource < BasicSource
353
408
  include DiagramSource
354
409
 
355
- def initialize(reader, attributes)
356
- super(attributes)
410
+ def initialize(parent, reader, attributes)
411
+ super(parent, attributes)
357
412
  @reader = reader
358
413
  end
359
414
 
415
+ def base_dir
416
+ attr('docdir', nil, true)
417
+ end
418
+
360
419
  def code
361
- @code ||= @reader.lines.join("\n")
420
+ @code ||= @parent.apply_subs(@reader.lines, resolve_diagram_subs).join("\n")
362
421
  end
363
422
  end
364
423
 
365
424
  # A diagram source that retrieves the code for a diagram from an external source file.
366
425
  class FileSource < BasicSource
367
- def initialize(file_name, attributes)
368
- super(attributes)
426
+ def initialize(parent, file_name, attributes)
427
+ super(parent, attributes)
369
428
  @file_name = file_name
370
429
  end
371
430
 
431
+ def base_dir
432
+ File.dirname(@file_name)
433
+ end
434
+
372
435
  def image_name
373
436
  if @attributes['target']
374
437
  super
@@ -384,12 +447,16 @@ module Asciidoctor
384
447
  end
385
448
 
386
449
  def code
450
+ @code ||= read_code
451
+ end
452
+
453
+ def read_code
387
454
  if @file_name
388
455
  lines = File.readlines(@file_name)
389
456
  lines = ::Asciidoctor::Helpers.normalize_lines(lines)
390
- @code ||= lines.join("\n")
457
+ @parent.apply_subs(lines, resolve_diagram_subs).join("\n")
391
458
  else
392
- @code ||= ''
459
+ ''
393
460
  end
394
461
  end
395
462
  end
@@ -1,5 +1,4 @@
1
- require 'asciidoctor/extensions'
2
- require_relative 'version'
1
+ require_relative 'extensions'
3
2
 
4
3
  Asciidoctor::Extensions.register do
5
4
  require_relative 'graphviz/extension'
@@ -1,5 +1,6 @@
1
1
  require_relative '../extensions'
2
2
  require_relative '../util/cli_generator'
3
+ require_relative '../util/platform'
3
4
  require_relative '../util/which'
4
5
 
5
6
  module Asciidoctor
@@ -10,13 +11,22 @@ module Asciidoctor
10
11
 
11
12
  def self.included(mod)
12
13
  [:png, :svg].each do |f|
13
- mod.register_format(f, :image) do |c, p|
14
- CliGenerator.generate_stdin(which(p, 'dot', :attr_names => ['dot', 'graphvizdot']), f.to_s, c.to_s) do |tool_path, output_path|
15
- [tool_path, "-o#{output_path}", "-T#{f.to_s}"]
16
- end
14
+ mod.register_format(f, :image) do |parent, source|
15
+ graphviz(parent, source, f)
17
16
  end
18
17
  end
19
18
  end
19
+
20
+ def graphviz(parent, source, format)
21
+ CliGenerator.generate_stdin(which(parent, 'dot', :alt_attrs => ['graphvizdot']), format.to_s, source.to_s) do |tool_path, output_path|
22
+ args = [tool_path, "-o#{Platform.native_path(output_path)}", "-T#{format.to_s}"]
23
+
24
+ layout = source.attr('layout')
25
+ args << "-K#{layout}" if layout
26
+
27
+ args
28
+ end
29
+ end
20
30
  end
21
31
 
22
32
  class GraphvizBlockProcessor < Extensions::DiagramBlockProcessor