asciidoctor-diagram 2.0.2 → 2.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.adoc +78 -1
  3. data/README.adoc +25 -507
  4. data/Rakefile +1 -1
  5. data/docs/antora.yml +3 -0
  6. data/{images → docs/modules/ROOT/images}/asciidoctor-diagram-classes.png +0 -0
  7. data/docs/modules/ROOT/images/asciidoctor-diagram-process.png +0 -0
  8. data/docs/modules/ROOT/pages/index.adoc +21 -0
  9. data/docs/modules/ROOT/partials/advanced.adoc +319 -0
  10. data/docs/modules/ROOT/partials/create_diagram.adoc +132 -0
  11. data/docs/modules/ROOT/partials/generate.adoc +15 -0
  12. data/docs/modules/ROOT/partials/installation.adoc +19 -0
  13. data/docs/modules/ROOT/partials/uris.adoc +40 -0
  14. data/examples/features.adoc +1 -1
  15. data/lib/asciidoctor-diagram.rb +4 -0
  16. data/lib/asciidoctor-diagram/a2s/converter.rb +10 -6
  17. data/lib/asciidoctor-diagram/blockdiag/converter.rb +1 -1
  18. data/lib/asciidoctor-diagram/bpmn/converter.rb +3 -3
  19. data/lib/asciidoctor-diagram/diagram_converter.rb +9 -1
  20. data/lib/asciidoctor-diagram/diagram_processor.rb +92 -48
  21. data/lib/asciidoctor-diagram/diagram_source.rb +71 -24
  22. data/lib/asciidoctor-diagram/diagrams.rb +7 -0
  23. data/lib/asciidoctor-diagram/diagrams/converter.rb +49 -0
  24. data/lib/asciidoctor-diagram/diagrams/extension.rb +14 -0
  25. data/lib/asciidoctor-diagram/ditaa/converter.rb +20 -7
  26. data/lib/asciidoctor-diagram/ditaa/ditaa-1.3.20.jar +0 -0
  27. data/lib/asciidoctor-diagram/dpic.rb +7 -0
  28. data/lib/asciidoctor-diagram/dpic/converter.rb +30 -0
  29. data/lib/asciidoctor-diagram/dpic/extension.rb +14 -0
  30. data/lib/asciidoctor-diagram/gnuplot/converter.rb +8 -8
  31. data/lib/asciidoctor-diagram/graphviz/converter.rb +2 -2
  32. data/lib/asciidoctor-diagram/http/converter.rb +52 -14
  33. data/lib/asciidoctor-diagram/http/server.rb +11 -6
  34. data/lib/asciidoctor-diagram/lilypond/converter.rb +13 -3
  35. data/lib/asciidoctor-diagram/meme/converter.rb +22 -16
  36. data/lib/asciidoctor-diagram/mermaid/converter.rb +45 -14
  37. data/lib/asciidoctor-diagram/msc/converter.rb +2 -2
  38. data/lib/asciidoctor-diagram/pikchr.rb +7 -0
  39. data/lib/asciidoctor-diagram/pikchr/converter.rb +33 -0
  40. data/lib/asciidoctor-diagram/pikchr/extension.rb +14 -0
  41. data/lib/asciidoctor-diagram/plantuml/converter.rb +68 -43
  42. data/lib/asciidoctor-diagram/plantuml/plantuml-1.3.20.jar +0 -0
  43. data/lib/asciidoctor-diagram/smcat/converter.rb +3 -3
  44. data/lib/asciidoctor-diagram/svgbob/converter.rb +6 -2
  45. data/lib/asciidoctor-diagram/symbolator.rb +7 -0
  46. data/lib/asciidoctor-diagram/symbolator/converter.rb +23 -0
  47. data/lib/asciidoctor-diagram/symbolator/extension.rb +14 -0
  48. data/lib/asciidoctor-diagram/syntrax/converter.rb +9 -6
  49. data/lib/asciidoctor-diagram/tikz/converter.rb +20 -1
  50. data/lib/asciidoctor-diagram/umlet/converter.rb +11 -2
  51. data/lib/asciidoctor-diagram/util/cli.rb +16 -1
  52. data/lib/asciidoctor-diagram/util/cli_generator.rb +30 -8
  53. data/lib/asciidoctor-diagram/util/gif.rb +2 -2
  54. data/lib/asciidoctor-diagram/util/java.rb +118 -3
  55. data/lib/asciidoctor-diagram/util/java_jruby.rb +4 -1
  56. data/lib/asciidoctor-diagram/util/java_socket.rb +8 -109
  57. data/lib/asciidoctor-diagram/util/pdf.rb +2 -2
  58. data/lib/asciidoctor-diagram/util/png.rb +2 -2
  59. data/lib/{server-1.3.15.jar → asciidoctor-diagram/util/server-1.3.20.jar} +0 -0
  60. data/lib/asciidoctor-diagram/util/svg.rb +66 -18
  61. data/lib/asciidoctor-diagram/vega/converter.rb +2 -2
  62. data/lib/asciidoctor-diagram/version.rb +1 -1
  63. data/spec/a2s_spec.rb +6 -144
  64. data/spec/blockdiag_spec.rb +6 -204
  65. data/spec/bpmn_spec.rb +52 -92
  66. data/spec/bytefield_spec.rb +6 -144
  67. data/spec/diagrams_spec.rb +23 -0
  68. data/spec/ditaa_spec.rb +6 -144
  69. data/spec/dpic_spec.rb +19 -0
  70. data/spec/erd_spec.rb +6 -203
  71. data/spec/gnuplot_spec.rb +10 -263
  72. data/spec/graphviz_spec.rb +6 -145
  73. data/spec/lilypond_spec.rb +6 -144
  74. data/spec/mermaid_spec.rb +69 -211
  75. data/spec/msc_spec.rb +6 -203
  76. data/spec/nomnoml_spec.rb +7 -145
  77. data/spec/pikchr_spec.rb +69 -0
  78. data/spec/plantuml_spec.rb +63 -553
  79. data/spec/shaape_spec.rb +12 -224
  80. data/spec/shared_examples.rb +603 -0
  81. data/spec/smcat_spec.rb +6 -144
  82. data/spec/svgbob_spec.rb +6 -144
  83. data/spec/symbolator_spec.rb +23 -0
  84. data/spec/syntrax_spec.rb +7 -217
  85. data/spec/test_helper.rb +4 -29
  86. data/spec/tikz_spec.rb +68 -18
  87. data/spec/umlet_spec.rb +3 -59
  88. data/spec/vega_spec.rb +6 -119
  89. data/spec/wavedrom_spec.rb +3 -200
  90. metadata +82 -18
  91. data/README_zh-CN.adoc +0 -336
  92. data/images/asciidoctor-diagram-process.png +0 -0
  93. data/lib/batik-all-1.10.jar +0 -0
  94. data/lib/ditaa-1.3.15.jar +0 -0
  95. data/lib/ditaamini-0.12.jar +0 -0
  96. data/lib/jlatexmath-minimal-1.0.5.jar +0 -0
  97. data/lib/plantuml-1.3.15.jar +0 -0
  98. data/lib/plantuml.jar +0 -0
  99. data/spec/bpmn-example.xml +0 -44
@@ -0,0 +1,15 @@
1
+ == Generating a Diagram from a Terminal
2
+
3
+ You can load Asciidoctor diagram in a terminal using the `-r` flag.
4
+
5
+ $ asciidoctor -r asciidoctor-diagram sample.adoc
6
+
7
+ You can also use Asciidoctor diagram with other converters, such as Asciidoctor EPUB.
8
+ Asciidoctor-epub3 is also loaded with the `-r` flag.
9
+
10
+ $ asciidoctor -r asciidoctor-diagram -r asciidoctor-epub3 -b epub3 sample.adoc
11
+
12
+ Or, you can invoke Asciidoctor and the EPUB converter with the `asciidoctor-epub3` command.
13
+ The command implicitly sets the `-r` and `-b` flags for EPUB3 output.
14
+
15
+ $ asciidoctor-epub3 -r asciidoctor-diagram sample.adoc
@@ -0,0 +1,19 @@
1
+ == Installation
2
+
3
+ Asciidoctor Diagram is a RubyGem, which can be installed using the `gem` or `bundle` commands.
4
+
5
+ You can install the Asciidoctor Diagram gem by typing `gem install` in the CLI.
6
+
7
+ $ gem install asciidoctor-diagram
8
+
9
+ by first adding the following entry to your project's [.path]_Gemfile_.
10
+
11
+ .Gemfile
12
+ [source,ruby]
13
+ ----
14
+ gem 'asciidoctor-diagram'
15
+ ----
16
+
17
+ Then execute `bundle` in the CLI.
18
+
19
+ $ bundle
@@ -0,0 +1,40 @@
1
+ :uri-a2s: https://github.com/dhobsd/asciitosvg
2
+ :uri-actdiag: http://blockdiag.com/en/actdiag/index.html
3
+ :uri-asciidoctor-api: http://asciidoctor.org/docs/user-manual/#api
4
+ :uri-asciidoctor-extensions: http://asciidoctor.org/docs/user-manual/#extension-points
5
+ :uri-blockdiag: http://blockdiag.com
6
+ :uri-bpmn: https://github.com/gtudan/bpmn-js-cmd
7
+ :uri-bytefield: https://github.com/Deep-Symmetry/bytefield-svg
8
+ :uri-diagrams: https://diagrams.mingrammer.com
9
+ :uri-ditaa: http://ditaa.sourceforge.net/
10
+ :uri-dpic: https://gitlab.com/aplevich/dpic
11
+ :uri-dot: https://graphviz.gitlab.io/_pages/doc/info/lang.html
12
+ :uri-erd: https://github.com/BurntSushi/erd
13
+ :uri-gnuplot: http://gnuplot.info
14
+ :uri-graphviz: https://graphviz.gitlab.io
15
+ :uri-imagemagick: http://www.imagemagick.org
16
+ :uri-java: http://java.sun.com
17
+ :uri-mermaid: https://github.com/mermaid-js/mermaid-cli
18
+ :uri-mscgen: http://www.mcternan.me.uk/mscgen/
19
+ :uri-nomnoml: http://nomnoml.com
20
+ :uri-nwdiag: http://blockdiag.com/en/nwdiag/index.html
21
+ :uri-packetdiag: http://blockdiag.com/en/nwdiag/index.html
22
+ :uri-phantomjs: http://phantomjs.org
23
+ :uri-pikchr: https://pikchr.org
24
+ :uri-plantuml: http://plantuml.sourceforge.net
25
+ :uri-py-plantuml: https://code.google.com/p/asciidoc-plantuml/
26
+ :uri-python: https://www.python.org
27
+ :uri-rackdiag: http://blockdiag.com/en/nwdiag/index.html
28
+ :uri-seqdiag: http://blockdiag.com/en/seqdiag/index.html
29
+ :uri-shaape: https://github.com/christiangoltz/shaape
30
+ :uri-smcat: https://github.com/sverweij/state-machine-cat
31
+ :uri-svgbob: https://github.com/ivanceras/svgbobrus
32
+ :uri-symbolator: https://github.com/kevinpt/symbolator
33
+ :uri-syntrax: https://kevinpt.github.io/syntrax/
34
+ :uri-tikz: https://github.com/pgf-tikz/pgf
35
+ :uri-umlet: http://www.umlet.com/
36
+ :uri-vega: https://vega.github.io/vega/
37
+ :uri-vegalite: https://vega.github.io/vega-lite/
38
+ :uri-wavedrom: http://wavedrom.com
39
+ :uri-wavedromeditor: https://github.com/wavedrom/wavedrom.github.io/releases
40
+ :uri-wavedromcli: https://github.com/wavedrom/cli
@@ -150,7 +150,7 @@ results in a block with the correct caption and id applied to it.
150
150
  Asciidoctor-diagram also supports the various diagram block in block macro form.
151
151
  These are macros of the form `<name>::<target>[<attrlist>]`.
152
152
 
153
- In asciidoctor-diagram the macro names are identical to the block styles: `ditaa`, `graphivz` and `plantuml`
153
+ In asciidoctor-diagram the macro names are identical to the block styles: `ditaa`, `graphviz` and `plantuml`
154
154
  The target is the path to the file containing the diagram source code.
155
155
  When the target is a relative path it is resolved with respect to the location of the document being processed.
156
156
  The attribute list behaves mostly the same as with the block styles.
@@ -2,7 +2,9 @@ require_relative 'asciidoctor-diagram/a2s'
2
2
  require_relative 'asciidoctor-diagram/blockdiag'
3
3
  require_relative 'asciidoctor-diagram/bpmn'
4
4
  require_relative 'asciidoctor-diagram/bytefield'
5
+ require_relative 'asciidoctor-diagram/diagrams'
5
6
  require_relative 'asciidoctor-diagram/ditaa'
7
+ require_relative 'asciidoctor-diagram/dpic'
6
8
  require_relative 'asciidoctor-diagram/erd'
7
9
  require_relative 'asciidoctor-diagram/gnuplot'
8
10
  require_relative 'asciidoctor-diagram/graphviz'
@@ -11,11 +13,13 @@ require_relative 'asciidoctor-diagram/meme'
11
13
  require_relative 'asciidoctor-diagram/mermaid'
12
14
  require_relative 'asciidoctor-diagram/msc'
13
15
  require_relative 'asciidoctor-diagram/nomnoml'
16
+ require_relative 'asciidoctor-diagram/pikchr'
14
17
  require_relative 'asciidoctor-diagram/plantuml'
15
18
  require_relative 'asciidoctor-diagram/salt'
16
19
  require_relative 'asciidoctor-diagram/shaape'
17
20
  require_relative 'asciidoctor-diagram/smcat'
18
21
  require_relative 'asciidoctor-diagram/svgbob'
22
+ require_relative 'asciidoctor-diagram/symbolator'
19
23
  require_relative 'asciidoctor-diagram/syntrax'
20
24
  require_relative 'asciidoctor-diagram/tikz'
21
25
  require_relative 'asciidoctor-diagram/umlet'
@@ -13,13 +13,13 @@ module Asciidoctor
13
13
  [:svg]
14
14
  end
15
15
 
16
- def collect_options(source, name)
16
+ def collect_options(source)
17
17
  options = {}
18
- options[:sx] = source.attr('scalex', nil, name)
19
- options[:sy] = source.attr('scaley', nil, name)
20
- options[:scale] = source.attr('scale', nil, name)
21
- options[:noblur] = source.attr('noblur', nil, name) == 'true'
22
- options[:font] = source.attr('fontfamily', nil, name)
18
+ options[:sx] = source.attr('scalex')
19
+ options[:sy] = source.attr('scaley')
20
+ options[:scale] = source.attr('scale')
21
+ options[:noblur] = source.attr('noblur') == 'true'
22
+ options[:font] = source.attr('fontfamily')
23
23
  options
24
24
  end
25
25
 
@@ -50,6 +50,10 @@ module Asciidoctor
50
50
  args
51
51
  end
52
52
  end
53
+
54
+ def native_scaling?
55
+ true
56
+ end
53
57
  end
54
58
  end
55
59
  end
@@ -19,7 +19,7 @@ module Asciidoctor
19
19
  cmd_name = self.class.const_get(:TOOL)
20
20
  alt_cmd_name = "#{cmd_name}3"
21
21
 
22
- font_path = source.attr('fontpath', nil, cmd_name)
22
+ font_path = source.attr('fontpath')
23
23
 
24
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
25
  args = [tool_path, '-a', '-o', Platform.native_path(output_path), "-T#{format.to_s}"]
@@ -15,11 +15,11 @@ module Asciidoctor
15
15
  [:png, :svg, :pdf, :jpeg]
16
16
  end
17
17
 
18
- def collect_options(source, name)
18
+ def collect_options(source)
19
19
  options = {}
20
20
 
21
- options[:width] = source.attr('width', nil, name)
22
- options[:height] = source.attr('height', nil, name)
21
+ options[:width] = source.attr('width')
22
+ options[:height] = source.attr('height')
23
23
 
24
24
  options
25
25
  end
@@ -7,13 +7,21 @@ module Asciidoctor
7
7
  raise NotImplementedError.new
8
8
  end
9
9
 
10
- def collect_options(source, name)
10
+ def wrap_source(source)
11
+ source
12
+ end
13
+
14
+ def collect_options(source)
11
15
  {}
12
16
  end
13
17
 
14
18
  def convert(source, format, options)
15
19
  raise NotImplementedError.new
16
20
  end
21
+
22
+ def native_scaling?
23
+ false
24
+ end
17
25
  end
18
26
  end
19
27
  end
@@ -3,6 +3,7 @@ require 'asciidoctor/extensions'
3
3
  require 'digest'
4
4
  require 'json'
5
5
  require 'fileutils'
6
+ require 'pathname'
6
7
  require_relative 'diagram_source.rb'
7
8
  require_relative 'http/converter'
8
9
  require_relative 'version'
@@ -30,8 +31,6 @@ module Asciidoctor
30
31
  host_class.extend(ClassMethods)
31
32
  end
32
33
 
33
- DIAGRAM_PREFIX = 'diagram'
34
-
35
34
  IMAGE_PARAMS = {
36
35
  :svg => {
37
36
  :encoding => Encoding::UTF_8,
@@ -62,14 +61,14 @@ module Asciidoctor
62
61
  location = parent.document.reader.cursor_at_mark
63
62
 
64
63
  normalised_attributes = attributes.inject({}) { |h, (k, v)| h[normalise_attribute_name(k)] = v; h }
65
- source = create_source(parent, reader_or_target, normalised_attributes)
66
-
67
64
  converter = config[:converter].new
68
65
 
66
+ source = converter.wrap_source(create_source(parent, reader_or_target, normalised_attributes))
67
+
69
68
  supported_formats = converter.supported_formats
70
69
 
71
70
  begin
72
- format = source.attributes.delete('format') || source.attr('format', nil, name) || source.attr('format', supported_formats[0], DIAGRAM_PREFIX)
71
+ format = source.attributes.delete('format') || source.global_attr('format', supported_formats[0])
73
72
  format = format.to_sym if format.respond_to?(:to_sym)
74
73
 
75
74
  raise "Format undefined" unless format
@@ -91,7 +90,7 @@ module Asciidoctor
91
90
  block.assign_caption(caption, 'figure')
92
91
  block
93
92
  rescue => e
94
- case source.attr('on-error', 'log', DIAGRAM_PREFIX)
93
+ case source.global_attr('on-error', 'log')
95
94
  when 'abort'
96
95
  raise e
97
96
  else
@@ -145,10 +144,9 @@ module Asciidoctor
145
144
 
146
145
  def create_image_block(parent, source, format, converter)
147
146
  image_name = "#{source.image_name}.#{format}"
148
- image_dir = image_output_dir(parent)
149
- cache_dir = cache_dir(parent)
150
- image_file = parent.normalize_system_path image_name, image_dir
151
- metadata_file = parent.normalize_system_path "#{image_name}.cache", cache_dir
147
+
148
+ image_file = parent.normalize_system_path(image_name, image_output_dir(parent))
149
+ metadata_file = parent.normalize_system_path("#{image_name}.cache", cache_dir(source, parent))
152
150
 
153
151
  if File.exist? metadata_file
154
152
  metadata = File.open(metadata_file, 'r') {|f| JSON.load(f, nil, :symbolize_names => true, :create_additions => false) }
@@ -157,25 +155,27 @@ module Asciidoctor
157
155
  end
158
156
 
159
157
  image_attributes = source.attributes
160
- options = converter.collect_options(source, name)
158
+ options = converter.collect_options(source)
161
159
 
162
160
  if !File.exist?(image_file) || source.should_process?(image_file, metadata) || options != metadata[:options]
163
161
  params = IMAGE_PARAMS[format]
164
162
 
165
- server_url = source.attr('server-url', nil, name) || source.attr('server-url', nil, DIAGRAM_PREFIX)
163
+ server_url = source.global_attr('server-url')
166
164
  if server_url
167
- server_type = source.attr('server-type', nil, name) || source.attr('server-type', 'plantuml', DIAGRAM_PREFIX)
165
+ server_type = source.global_attr('server-type')
168
166
  converter = HttpConverter.new(server_url, server_type.to_sym, converter)
169
167
  end
170
168
 
171
- options = converter.collect_options(source, name)
169
+ options = converter.collect_options(source)
172
170
  result = converter.convert(source, format, options)
173
171
 
174
172
  result.force_encoding(params[:encoding])
175
173
 
176
174
  metadata = source.create_image_metadata
177
175
  metadata[:options] = options
178
- metadata[:width], metadata[:height] = params[:decoder].get_image_size(result)
176
+
177
+ allow_image_optimisation = source.attr('optimise', 'true') == 'true'
178
+ result, metadata[:width], metadata[:height] = params[:decoder].post_process_image(result, allow_image_optimisation)
179
179
 
180
180
  FileUtils.mkdir_p(File.dirname(image_file)) unless Dir.exist?(File.dirname(image_file))
181
181
  File.open(image_file, 'wb') {|f| f.write result}
@@ -184,14 +184,8 @@ module Asciidoctor
184
184
  File.open(metadata_file, 'w') {|f| JSON.dump(metadata, f)}
185
185
  end
186
186
 
187
- image_attributes['target'] = source.attr('data-uri', nil, true) ? image_file : image_name
188
- if format == :svg
189
- svg_type = source.attr('svg-type', nil, name) || source.attr('svg-type', nil, DIAGRAM_PREFIX)
190
- image_attributes['opts'] = svg_type if svg_type && svg_type != 'static'
191
- end
192
-
193
187
  scale = image_attributes['scale']
194
- if scalematch = /(\d+(?:\.\d+))/.match(scale)
188
+ if !converter.native_scaling? && scalematch = /([0-9]+(?:\.[0-9]+)?)/.match(scale)
195
189
  scale_factor = scalematch[1].to_f
196
190
  else
197
191
  scale_factor = 1.0
@@ -207,25 +201,58 @@ module Asciidoctor
207
201
  end
208
202
  end
209
203
 
210
- image_attributes['alt'] ||= if title_text = image_attributes['title']
211
- title_text
212
- elsif target = image_attributes['target']
213
- (File.basename(target, File.extname(target)) || '').tr '_-', ' '
214
- else
215
- 'Diagram'
216
- end
204
+ parent.document.register(:images, image_name)
217
205
 
218
- image_attributes['alt'] = parent.sub_specialchars image_attributes['alt']
206
+ node = Asciidoctor::Block.new parent, :image, :content_model => :empty, :attributes => image_attributes
219
207
 
220
- parent.document.register(:images, image_name)
221
- if (scaledwidth = image_attributes['scaledwidth'])
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'))
222
221
  # append % to scaledwidth if ends in number (no units present)
223
222
  if DIGIT_CHAR_RANGE.include?((scaledwidth[-1] || 0).ord)
224
- image_attributes['scaledwidth'] = %(#{scaledwidth}%)
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
+ image_path = Pathname.new(image_file)
248
+ output_path = Pathname.new(parent.normalize_system_path(output_dir(parent)))
249
+
250
+ imagesdir = image_path.relative_path_from(output_path).dirname.to_s
251
+ node.set_attr('imagesdir', imagesdir)
225
252
  end
226
253
  end
227
254
 
228
- Asciidoctor::Block.new parent, :image, :content_model => :empty, :attributes => image_attributes
255
+ node
229
256
  end
230
257
 
231
258
  def scale(size, factor)
@@ -238,33 +265,50 @@ module Asciidoctor
238
265
  end
239
266
  end
240
267
 
268
+ # Returns the image output directory as an absolute path
241
269
  def image_output_dir(parent)
242
- document = parent.document
243
-
244
- images_dir = parent.attr('imagesoutdir', nil, true)
270
+ images_out_dir = parent.attr('imagesoutdir', nil, true)
245
271
 
246
- if images_dir
247
- base_dir = nil
272
+ if images_out_dir
273
+ resolve_path(parent, images_out_dir)
248
274
  else
249
- base_dir = parent.attr('outdir', nil, true) || doc_option(document, :to_dir)
250
275
  images_dir = parent.attr('imagesdir', nil, true)
276
+ output_dir = output_dir(parent)
277
+ resolve_path(parent, images_dir, output_dir)
251
278
  end
279
+ end
280
+
281
+ # Returns the cache directory as an absolute path
282
+ def cache_dir(source, parent)
283
+ cache_dir = source.global_attr('cachedir')
284
+ if cache_dir
285
+ resolve_path(parent, cache_dir)
286
+ else
287
+ output_dir = output_dir(parent)
288
+ resolve_path(parent, '.asciidoctor/diagram', output_dir)
289
+ end
290
+ end
252
291
 
253
- parent.normalize_system_path(images_dir, base_dir)
292
+ # Returns the general output directory for Asciidoctor as an absolute path
293
+ def output_dir(parent)
294
+ resolve_path(parent, parent.attr('outdir', nil, true) || doc_option(parent.document, :to_dir))
254
295
  end
255
296
 
256
- def cache_dir(parent)
257
- document = parent.document
258
- cache_dir = '.asciidoctor/diagram'
259
- base_dir = parent.attr('outdir', nil, true) || doc_option(document, :to_dir)
260
- parent.normalize_system_path(cache_dir, base_dir)
297
+ def resolve_path(parent, path, base_dir = nil)
298
+ if path.nil?
299
+ # Resolve the base dir itself
300
+ parent.document.path_resolver.system_path(base_dir)
301
+ else
302
+ # Resolve the path with respect to the base dir
303
+ parent.document.path_resolver.system_path(path, base_dir)
304
+ end
261
305
  end
262
306
 
263
307
  def create_literal_block(parent, source, format, converter)
264
308
  literal_attributes = source.attributes
265
309
  literal_attributes.delete('target')
266
310
 
267
- options = converter.collect_options(source, name)
311
+ options = converter.collect_options(source)
268
312
  result = converter.convert(source, format, options)
269
313
 
270
314
  result.force_encoding(Encoding::UTF_8)
@@ -309,7 +353,7 @@ module Asciidoctor
309
353
  include DiagramProcessor
310
354
 
311
355
  def self.inherited(subclass)
312
- subclass.name_positional_attributes ['target', 'format']
356
+ subclass.name_positional_attributes ['format']
313
357
  end
314
358
 
315
359
  def apply_target_subs(parent, target)
@@ -1,3 +1,4 @@
1
+ require 'asciidoctor/logging'
1
2
  require_relative 'util/which'
2
3
 
3
4
  module Asciidoctor
@@ -5,6 +6,12 @@ module Asciidoctor
5
6
  # This module describes the duck-typed interface that diagram sources must implement. Implementations
6
7
  # may include this module but it is not required.
7
8
  module DiagramSource
9
+ include Asciidoctor::Logging
10
+
11
+ def diagram_type
12
+ raise NotImplementedError.new
13
+ end
14
+
8
15
  def image_name
9
16
  raise NotImplementedError.new
10
17
  end
@@ -12,23 +19,31 @@ module Asciidoctor
12
19
  # @return [String] the String representation of the source code for the diagram
13
20
  # @abstract
14
21
  def code
22
+ @code ||= load_code
23
+ end
24
+
25
+ def load_code
15
26
  raise NotImplementedError.new
16
27
  end
17
28
 
29
+ def global_attr(name, default_value = nil)
30
+ attr(name) || attr(name, default_value, 'diagram')
31
+ end
32
+
18
33
  # Get the value for the specified attribute. First look in the attributes on
19
34
  # this document and return the value of the attribute if found. Otherwise, if
20
35
  # this document is a child of the Document document, look in the attributes of the
21
36
  # Document document and return the value of the attribute if found. Otherwise,
22
37
  # return the default value, which defaults to nil.
23
38
  #
24
- # @param name [String, Symbol] the name of the attribute to lookup
39
+ # @param name [String, Symbol, Array] the name(s) of the attribute to lookup
25
40
  # @param default_value [Object] the value to return if the attribute is not found
26
41
  # @inherit [Boolean, String] indicates whether to check for the attribute on the AsciiDoctor::Document if not found on this document.
27
42
  # When a non-nil String is given the an attribute name "#{inherit}-#{name}" is looked for on the document.
28
43
  #
29
44
  # @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
30
45
  # @abstract
31
- def attr(name, default_value = nil, inherit = nil)
46
+ def attr(name, default_value = nil, inherit = diagram_type)
32
47
  raise NotImplementedError.new
33
48
  end
34
49
 
@@ -75,14 +90,42 @@ module Asciidoctor
75
90
  if config.key? cmd_var
76
91
  cmd_path = config[cmd_var]
77
92
  else
78
- cmd_path = attr_names.map { |attr_name| attr(attr_name, nil, true) }.find { |attr| !attr.nil? }
79
-
80
- unless cmd_path && File.executable?(cmd_path)
81
- cmd_paths = cmd_names.map do |c|
82
- ::Asciidoctor::Diagram::Which.which(c, :path => options[:path])
83
- end
84
-
85
- cmd_path = cmd_paths.reject { |c| c.nil? }.first
93
+ logger.debug "Finding '#{cmd}' in attributes"
94
+ cmd_path = attr_names.map { |attr_name|
95
+ attr = attr(attr_name, nil, true)
96
+ if logger.debug? && attr
97
+ logger.debug "Found value '#{attr}' in attribute '#{attr_name}'" if attr
98
+ end
99
+ attr
100
+ }
101
+ .reject { |attr| attr.nil? }
102
+ .map { |attr|
103
+ expanded = File.expand_path(attr)
104
+ if logger.debug? && attr != expanded
105
+ logger.debug "Expanded '#{attr}' to '#{expanded}'"
106
+ end
107
+ expanded
108
+ }
109
+ .select { |path|
110
+ executable = File.executable?(path)
111
+ if logger.debug?
112
+ logger.debug "Is '#{path}' executable? #{executable}"
113
+ end
114
+ executable
115
+ }
116
+ .first
117
+
118
+ unless cmd_path
119
+ logger.debug "Finding '#{cmd}' in environment"
120
+ cmd_path = cmd_names.map { |c|
121
+ path = ::Asciidoctor::Diagram::Which.which(c, :path => options[:path])
122
+ if logger.debug? && path
123
+ logger.debug "Found '#{path}' in environment"
124
+ end
125
+ path
126
+ }
127
+ .reject { |path| path.nil? }
128
+ .first
86
129
  end
87
130
 
88
131
  config[cmd_var] = cmd_path
@@ -113,6 +156,10 @@ module Asciidoctor
113
156
  @attributes = attributes
114
157
  end
115
158
 
159
+ def diagram_type
160
+ @block_processor.name.downcase
161
+ end
162
+
116
163
  def resolve_path target, start = base_dir
117
164
  @parent_block.normalize_system_path(target, start)
118
165
  end
@@ -125,18 +172,22 @@ module Asciidoctor
125
172
  attr('target', 'diag-' + checksum)
126
173
  end
127
174
 
128
- def attr(name, default_value = nil, inherit = nil)
175
+ def attr(name, default_value = nil, inherit = diagram_type)
129
176
  name = name.to_s if ::Symbol === name
177
+ name = [name] unless name.is_a?(Enumerable)
130
178
 
131
- value = @attributes[name]
179
+ value = name.lazy.map { |n| @attributes[n] }.reject { |v| v.nil? }.first
132
180
 
133
181
  if value.nil? && inherit
134
- case inherit
135
- when String, Symbol
136
- value = @parent_block.attr("#{inherit.to_s}-#{name}", default_value, true)
137
- else
138
- value = @parent_block.attr(name, default_value, inherit)
182
+ inherited_values = name.lazy.map do |n|
183
+ case inherit
184
+ when String, Symbol
185
+ @parent_block.attr("#{inherit.to_s}-#{n}", default_value, true)
186
+ else
187
+ @parent_block.attr(n, default_value, inherit)
188
+ end
139
189
  end
190
+ value = inherited_values.reject { |v| v.nil? }.first
140
191
  end
141
192
 
142
193
  value || default_value
@@ -186,8 +237,8 @@ module Asciidoctor
186
237
  @reader = reader
187
238
  end
188
239
 
189
- def code
190
- @code ||= @parent_block.apply_subs(@reader.lines, resolve_diagram_subs).join("\n")
240
+ def load_code
241
+ @parent_block.apply_subs(@reader.lines, resolve_diagram_subs).join("\n")
191
242
  end
192
243
  end
193
244
 
@@ -220,11 +271,7 @@ module Asciidoctor
220
271
  (@file_name && File.mtime(@file_name) > File.mtime(image_file)) || super
221
272
  end
222
273
 
223
- def code
224
- @code ||= read_code
225
- end
226
-
227
- def read_code
274
+ def load_code
228
275
  if @file_name
229
276
  lines = File.readlines(@file_name)
230
277
  lines = prepare_source_array(lines)