asciidoctor-diagram 2.2.1 → 2.2.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f13f5d250305d3a9da90af8da4a0b784c247979b9e23462b8b8bd77f6c92ca0a
4
- data.tar.gz: 5f757455ea6ba101f8543d87a2bbe06106ed354e09bec89bf3d22959d1674f96
3
+ metadata.gz: 629ba788527640ff6cd5bd7c0e6cc18a1a2b7afa4071737b667f95859491dbfc
4
+ data.tar.gz: 762433ab8f23c6d7a4e44fc5d580c77a1fa52b56c47780d1ba28077ae1c309ee
5
5
  SHA512:
6
- metadata.gz: 2e08ce3f20a0d241e177cbf06680f68149af8adc8e65b6ab25fa57bf1e620aead335d7c8fbe96047bb10b95bf52ce7b22d7c67c3160882e8fd4f0a261c597eb2
7
- data.tar.gz: 9ff970387205a3686999220bd37e0d54b08f10f5c95be8d37d05764fbf2f46a5606c9efe4184249b951ad845194e108d7d283fd178216fd42958230dbd50afce
6
+ metadata.gz: eb2cac4b23d86cc7fb37787208b221a42c839d06b31eff51585a108c674b0517e3c9c72afe1f4ed556e671d4ff5bff06c825cff764098a8925f860975e96146b
7
+ data.tar.gz: 35a265251153d038515a89aea7322373495e6e72d768df42e200c517e905a6b257f8916b7c3b0ff8645a15a8aeff258b345bd7b744c6e514bd6dc7291bf26bdc
data/CHANGELOG.adoc CHANGED
@@ -1,5 +1,17 @@
1
1
  = Asciidoctor-diagram Changelog
2
2
 
3
+ == 2.2.2
4
+
5
+ Enhancements::
6
+
7
+ * Issue #375: Add support for PlantUML include directories (@mskyaxl)
8
+ * Add support for `graphviz-py` (@Alwinator)
9
+ * Issue #380: Allow local PlantUML preprocessing to be disabled using the `preprocess` attribute
10
+
11
+ Bug Fixes::
12
+
13
+ * Issue #370: Only use absolute paths for 'interactive' style SVGs when 'data-uri' is also in use.
14
+
3
15
  == 2.2.1
4
16
 
5
17
  Bug Fixes::
@@ -317,9 +317,11 @@ No specific attributes.
317
317
 
318
318
  [cols=">,<,<",options="header"]
319
319
  |===
320
- |Name |Default value |Description
321
- |config |unspecified |Path to a config file to pass to PlantUML.
322
- |size-limit |4096 |The maximum dimensions (width and height) of generated diagrams.
320
+ |Name |Default value |Description
321
+ |config |unspecified |Path to a config file to pass to PlantUML.
322
+ |size-limit |4096 |The maximum dimensions (width and height) of generated diagrams.
323
+ |includedir |unspecified |sets a common directory for puml includes (plantuml.include.path)
324
+ |preprocess |true |Preprocess PlantUML code before rendering the diagram.
323
325
  |===
324
326
 
325
327
  ==== State Machine Cat
@@ -118,6 +118,31 @@ graph ethane {
118
118
  }
119
119
  ----
120
120
 
121
+ With https://github.com/Alwinator/graphviz-py[graphviz_py] you can also use variables and Python code to do calculations:
122
+
123
+ [graphviz_py, "graphviz_py_example", "svg"]
124
+ ----
125
+ graph python_graph {
126
+ {{
127
+ import math
128
+
129
+ value = 0.5
130
+ sin = math.sin(value)
131
+ cos = math.cos(value)
132
+ }}
133
+
134
+ A [label="{{= value }}"];
135
+ B [label="{{= sin }}"];
136
+ C [label="{{= cos }}"];
137
+
138
+ A -- B [headlabel="sin"];
139
+ A -- C [headlabel="cos"];
140
+
141
+ }
142
+ ----
143
+
144
+ Don't forget to install graphviz-py as described https://github.com/Alwinator/graphviz-py#installation[here].
145
+
121
146
  == Using standard asciidoc features
122
147
 
123
148
  Any remaining other attributes that are specified on a diagram block are copied over to the generated block.
@@ -249,9 +249,11 @@ module Asciidoctor
249
249
  case svg_type
250
250
  when nil, 'static'
251
251
  # Nothing to do
252
- when 'inline', 'interactive'
252
+ when 'inline'
253
253
  node.set_option(svg_type)
254
254
  use_absolute_path = true
255
+ when 'interactive'
256
+ node.set_option(svg_type)
255
257
  else
256
258
  raise "Unsupported SVG type: #{svg_type}"
257
259
  end
@@ -31,7 +31,7 @@ module Asciidoctor
31
31
  require 'asciidoctor-diagram/ditaa/classpath'
32
32
  ::Asciidoctor::Diagram::DitaaClasspath::JAR_FILES
33
33
  rescue LoadError
34
- raise "Could not load PlantUML. Eiter require 'asciidoctor-diagram-ditaamini' or specify the location of the PlantUML JAR(s) using the 'DIAGRAM_DITAA_CLASSPATH' environment variable."
34
+ raise "Could not load Ditaa. Eiter require 'asciidoctor-diagram-ditaamini' or specify the location of the Ditaa JAR(s) using the 'DIAGRAM_DITAA_CLASSPATH' environment variable."
35
35
  end
36
36
  end
37
37
 
@@ -96,4 +96,4 @@ module Asciidoctor
96
96
  end
97
97
  end
98
98
  end
99
- end
99
+ end
@@ -0,0 +1,42 @@
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 GraphvizPyConverter
9
+ include DiagramConverter
10
+ include CliGenerator
11
+
12
+ def supported_formats
13
+ [:png, :pdf, :svg]
14
+ end
15
+
16
+ def collect_options(source)
17
+ {
18
+ :layout => source.attr('layout'),
19
+ :argument => source.attr('argument')
20
+ }
21
+ end
22
+
23
+ def convert(source, format, options)
24
+ generate_stdin(source.find_command('graphviz-py'), format.to_s, source.to_s) do |tool_path, output_path|
25
+ args = [tool_path, "-o#{Platform.native_path(output_path)}", "-T#{format.to_s}"]
26
+
27
+ layout = options[:layout]
28
+ args << "-K#{layout}" if layout
29
+
30
+ argument = options[:argument]
31
+
32
+ if argument
33
+ args << "-a"
34
+ args << argument
35
+ end
36
+
37
+ args
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,18 @@
1
+ require_relative 'converter'
2
+ require_relative '../diagram_processor'
3
+
4
+ module Asciidoctor
5
+ module Diagram
6
+ class GraphvizPyBlockProcessor < DiagramBlockProcessor
7
+ use_converter GraphvizPyConverter
8
+ end
9
+
10
+ class GraphvizPyBlockMacroProcessor < DiagramBlockMacroProcessor
11
+ use_converter GraphvizPyConverter
12
+ end
13
+
14
+ class GraphvizPyInlineMacroProcessor < DiagramInlineMacroProcessor
15
+ use_converter GraphvizPyConverter
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,8 @@
1
+ require 'asciidoctor/extensions'
2
+ require_relative 'graphviz_py/extension'
3
+
4
+ Asciidoctor::Extensions.register do
5
+ block Asciidoctor::Diagram::GraphvizPyBlockProcessor, :graphviz_py
6
+ block_macro Asciidoctor::Diagram::GraphvizPyBlockMacroProcessor, :graphviz_py
7
+ inline_macro Asciidoctor::Diagram::GraphvizPyInlineMacroProcessor, :graphviz_py
8
+ end
@@ -113,27 +113,36 @@ module Asciidoctor
113
113
 
114
114
  code = "@start#{@tag}\n#{code}\n@end#{@tag}" unless code.index("@start") && code.index("@end")
115
115
 
116
- headers = {}
116
+ should_preprocess = attr('preprocess', 'true') == 'true'
117
117
 
118
- config_file = attr('plantumlconfig', nil, true) || attr('config')
119
- if config_file
120
- headers['X-PlantUML-Config'] = File.expand_path(config_file, base_dir)
121
- end
118
+ if should_preprocess
119
+ headers = {}
122
120
 
123
- headers['X-PlantUML-Basedir'] = Platform.native_path(File.expand_path(base_dir))
121
+ config_file = attr('plantumlconfig', nil, true) || attr('config')
122
+ if config_file
123
+ headers['X-PlantUML-Config'] = File.expand_path(config_file, base_dir)
124
+ end
124
125
 
125
- response = Java.send_request(
126
- :url => '/plantumlpreprocessor',
127
- :body => code,
128
- :headers => headers
129
- )
126
+ headers['X-PlantUML-Basedir'] = Platform.native_path(File.expand_path(base_dir))
130
127
 
131
- unless response[:code] == 200
132
- raise Java.create_error("PlantUML preprocessing failed", response)
133
- end
128
+ include_dir = attr('includedir')
129
+ if include_dir
130
+ headers['X-PlantUML-IncludeDir'] = Platform.native_path(File.expand_path(include_dir, base_dir))
131
+ end
134
132
 
135
- code = response[:body]
136
- code.force_encoding(Encoding::UTF_8)
133
+ response = Java.send_request(
134
+ :url => '/plantumlpreprocessor',
135
+ :body => code,
136
+ :headers => headers
137
+ )
138
+
139
+ unless response[:code] == 200
140
+ raise Java.create_error("PlantUML preprocessing failed", response)
141
+ end
142
+
143
+ code = response[:body]
144
+ code.force_encoding(Encoding::UTF_8)
145
+ end
137
146
 
138
147
  code
139
148
  end
@@ -44,7 +44,7 @@ module Asciidoctor
44
44
  OPTIONS[option].call(flags, value)
45
45
  end
46
46
 
47
- generate_stdin(source.find_command('svgbob'), format.to_s, source.to_s) do |tool_path, output_path|
47
+ generate_stdin(source.find_command('svgbob', :alt_cmds => ['svgbob_cli']), format.to_s, source.to_s) do |tool_path, output_path|
48
48
  ([tool_path, '-o', Platform.native_path(output_path)] + flags)
49
49
  end
50
50
  end
@@ -1,5 +1,5 @@
1
1
  module Asciidoctor
2
2
  module Diagram
3
- VERSION = "2.2.1"
3
+ VERSION = "2.2.2"
4
4
  end
5
5
  end
@@ -9,6 +9,7 @@ require_relative 'asciidoctor-diagram/dpic'
9
9
  require_relative 'asciidoctor-diagram/erd'
10
10
  require_relative 'asciidoctor-diagram/gnuplot'
11
11
  require_relative 'asciidoctor-diagram/graphviz'
12
+ require_relative 'asciidoctor-diagram/graphviz_py'
12
13
  require_relative 'asciidoctor-diagram/lilypond'
13
14
  require_relative 'asciidoctor-diagram/meme'
14
15
  require_relative 'asciidoctor-diagram/mermaid'
@@ -0,0 +1,33 @@
1
+ require_relative 'test_helper'
2
+
3
+ GRAPHVIZ_PY_CODE = <<-eos
4
+ graph python_graph {
5
+ {{
6
+ import math
7
+
8
+ value = 0.5
9
+ sin = math.sin(value)
10
+ cos = math.cos(value)
11
+ }}
12
+
13
+ A [label="{{= value }}"];
14
+ B [label="{{= sin }}"];
15
+ C [label="{{= cos }}"];
16
+
17
+ A -- B [headlabel="sin"];
18
+ A -- C [headlabel="cos"];
19
+
20
+ }
21
+ eos
22
+
23
+ describe Asciidoctor::Diagram::GraphvizPyInlineMacroProcessor, :broken_on_github do
24
+ include_examples "inline_macro", :graphviz_py, GRAPHVIZ_PY_CODE, [:png, :svg]
25
+ end
26
+
27
+ describe Asciidoctor::Diagram::GraphvizPyBlockMacroProcessor, :broken_on_github do
28
+ include_examples "block_macro", :graphviz_py, GRAPHVIZ_PY_CODE, [:png, :svg]
29
+ end
30
+
31
+ describe Asciidoctor::Diagram::GraphvizPyBlockProcessor, :broken_on_github do
32
+ include_examples "block", :graphviz_py, GRAPHVIZ_PY_CODE, [:png, :svg]
33
+ end
@@ -4,14 +4,14 @@ LILYPOND_CODE = <<-eos
4
4
  \\relative c' { f d f a d f e d cis a cis e a g f e }
5
5
  eos
6
6
 
7
- describe Asciidoctor::Diagram::LilypondInlineMacroProcessor do
7
+ describe Asciidoctor::Diagram::LilypondInlineMacroProcessor, :broken_on_windows do
8
8
  include_examples "inline_macro", :lilypond, LILYPOND_CODE, [:png]
9
9
  end
10
10
 
11
- describe Asciidoctor::Diagram::LilypondBlockMacroProcessor do
11
+ describe Asciidoctor::Diagram::LilypondBlockMacroProcessor, :broken_on_windows do
12
12
  include_examples "block_macro", :lilypond, LILYPOND_CODE, [:png]
13
13
  end
14
14
 
15
- describe Asciidoctor::Diagram::LilypondBlockProcessor do
15
+ describe Asciidoctor::Diagram::LilypondBlockProcessor, :broken_on_windows do
16
16
  include_examples "block", :lilypond, LILYPOND_CODE, [:png]
17
17
  end
data/spec/msc_spec.rb CHANGED
@@ -24,14 +24,14 @@ msc {
24
24
  }
25
25
  eos
26
26
 
27
- describe Asciidoctor::Diagram::MscInlineMacroProcessor do
27
+ describe Asciidoctor::Diagram::MscInlineMacroProcessor, :broken_on_windows do
28
28
  include_examples "inline_macro", :msc, MSC_CODE, [:png, :svg]
29
29
  end
30
30
 
31
- describe Asciidoctor::Diagram::MscBlockMacroProcessor do
31
+ describe Asciidoctor::Diagram::MscBlockMacroProcessor, :broken_on_windows do
32
32
  include_examples "block_macro", :msc, MSC_CODE, [:png, :svg]
33
33
  end
34
34
 
35
- describe Asciidoctor::Diagram::MscBlockProcessor do
35
+ describe Asciidoctor::Diagram::MscBlockProcessor, :broken_on_windows do
36
36
  include_examples "block", :msc, MSC_CODE, [:png, :svg]
37
37
  end
@@ -253,6 +253,43 @@ skinparam ArrowColor #DEADBE
253
253
  expect(svg).to match(/<[^<]+ fill=["']#DEADBE["']/)
254
254
  end
255
255
 
256
+ it 'should use plantuml include dir when specified as a document attribute' do
257
+ doc = <<-eos
258
+ = Hello, PlantUML!
259
+ Doc Writer <doc@example.com>
260
+ :plantuml-includedir: include
261
+ :plantuml-format: svg
262
+
263
+ == First Section
264
+
265
+ [plantuml]
266
+ ----
267
+ !include common.puml
268
+ actor Foo1
269
+ boundary Foo2
270
+ Foo1 -> Foo2 : To boundary
271
+ ----
272
+ eos
273
+
274
+ includefile = <<-eos
275
+ skinparam ArrowColor #DEADBE
276
+ eos
277
+ Dir.mkdir('include')
278
+ File.open('include/common.puml', 'w') do |f|
279
+ f.write includefile
280
+ end
281
+
282
+ d = load_asciidoc doc
283
+ b = d.find { |bl| bl.context == :image }
284
+
285
+ target = b.attributes['target']
286
+ expect(target).to_not be_nil
287
+ expect(File.exist?(target)).to be true
288
+
289
+ svg = File.read(target, :encoding => Encoding::UTF_8)
290
+ expect(svg).to match(/<[^<]+ fill=["']#DEADBE["']/)
291
+ end
292
+
256
293
  it 'should support salt diagrams using salt block type' do
257
294
  doc = <<-eos
258
295
  = Hello, PlantUML!
@@ -14,14 +14,14 @@ package demo is
14
14
  end package;
15
15
  eos
16
16
 
17
- describe Asciidoctor::Diagram::SymbolatorInlineMacroProcessor, :broken_on_windows do
17
+ describe Asciidoctor::Diagram::SymbolatorInlineMacroProcessor, :broken_on_windows, :broken_on_github do
18
18
  include_examples "inline_macro", :symbolator, SYMBOLATOR_CODE, [:png, :svg, :pdf]
19
19
  end
20
20
 
21
- describe Asciidoctor::Diagram::SymbolatorBlockMacroProcessor, :broken_on_windows do
21
+ describe Asciidoctor::Diagram::SymbolatorBlockMacroProcessor, :broken_on_windows, :broken_on_github do
22
22
  include_examples "block_macro", :symbolator, SYMBOLATOR_CODE, [:png, :svg, :pdf]
23
23
  end
24
24
 
25
- describe Asciidoctor::Diagram::SymbolatorBlockProcessor, :broken_on_windows do
25
+ describe Asciidoctor::Diagram::SymbolatorBlockProcessor, :broken_on_windows, :broken_on_github do
26
26
  include_examples "block", :symbolator, SYMBOLATOR_CODE, [:png, :svg, :pdf]
27
27
  end
data/spec/syntrax_spec.rb CHANGED
@@ -9,14 +9,14 @@ indentstack(10,
9
9
  )
10
10
  eos
11
11
 
12
- describe Asciidoctor::Diagram::SyntraxInlineMacroProcessor, :broken_on_windows do
12
+ describe Asciidoctor::Diagram::SyntraxInlineMacroProcessor, :broken_on_windows, :broken_on_github do
13
13
  include_examples "inline_macro", :syntrax, SYNTRAX_CODE, [:png, :svg]
14
14
  end
15
15
 
16
- describe Asciidoctor::Diagram::SyntraxBlockMacroProcessor, :broken_on_windows do
16
+ describe Asciidoctor::Diagram::SyntraxBlockMacroProcessor, :broken_on_windows, :broken_on_github do
17
17
  include_examples "block_macro", :syntrax, SYNTRAX_CODE, [:png, :svg]
18
18
  end
19
19
 
20
- describe Asciidoctor::Diagram::SyntraxBlockProcessor, :broken_on_windows do
20
+ describe Asciidoctor::Diagram::SyntraxBlockProcessor, :broken_on_windows, :broken_on_github do
21
21
  include_examples "block", :syntrax, SYNTRAX_CODE, [:png, :svg]
22
22
  end
@@ -8,14 +8,14 @@ WAVEDROM_CODE = <<-eos
8
8
  ]}
9
9
  eos
10
10
 
11
- describe Asciidoctor::Diagram::WavedromInlineMacroProcessor, :broken_on_windows do
11
+ describe Asciidoctor::Diagram::WavedromInlineMacroProcessor, :broken_on_windows, :broken_on_github do
12
12
  include_examples "inline_macro", :wavedrom, WAVEDROM_CODE, [:png, :svg]
13
13
  end
14
14
 
15
- describe Asciidoctor::Diagram::WavedromBlockMacroProcessor, :broken_on_windows do
15
+ describe Asciidoctor::Diagram::WavedromBlockMacroProcessor, :broken_on_windows, :broken_on_github do
16
16
  include_examples "block_macro", :wavedrom, WAVEDROM_CODE, [:png, :svg]
17
17
  end
18
18
 
19
- describe Asciidoctor::Diagram::WavedromBlockProcessor, :broken_on_windows do
19
+ describe Asciidoctor::Diagram::WavedromBlockProcessor, :broken_on_windows, :broken_on_github do
20
20
  include_examples "block", :wavedrom, WAVEDROM_CODE, [:png, :svg]
21
21
  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: 2.2.1
4
+ version: 2.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pepijn Van Eeckhoudt
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-09-01 00:00:00.000000000 Z
11
+ date: 2022-05-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -164,7 +164,7 @@ files:
164
164
  - lib/asciidoctor-diagram/diagrams/extension.rb
165
165
  - lib/asciidoctor-diagram/ditaa.rb
166
166
  - lib/asciidoctor-diagram/ditaa/converter.rb
167
- - lib/asciidoctor-diagram/ditaa/ditaa-1.3.20.jar
167
+ - lib/asciidoctor-diagram/ditaa/ditaa-1.3.21.jar
168
168
  - lib/asciidoctor-diagram/ditaa/extension.rb
169
169
  - lib/asciidoctor-diagram/dpic.rb
170
170
  - lib/asciidoctor-diagram/dpic/converter.rb
@@ -178,6 +178,9 @@ files:
178
178
  - lib/asciidoctor-diagram/graphviz.rb
179
179
  - lib/asciidoctor-diagram/graphviz/converter.rb
180
180
  - lib/asciidoctor-diagram/graphviz/extension.rb
181
+ - lib/asciidoctor-diagram/graphviz_py.rb
182
+ - lib/asciidoctor-diagram/graphviz_py/converter.rb
183
+ - lib/asciidoctor-diagram/graphviz_py/extension.rb
181
184
  - lib/asciidoctor-diagram/http/converter.rb
182
185
  - lib/asciidoctor-diagram/http/server.rb
183
186
  - lib/asciidoctor-diagram/lilypond.rb
@@ -201,7 +204,7 @@ files:
201
204
  - lib/asciidoctor-diagram/plantuml.rb
202
205
  - lib/asciidoctor-diagram/plantuml/converter.rb
203
206
  - lib/asciidoctor-diagram/plantuml/extension.rb
204
- - lib/asciidoctor-diagram/plantuml/plantuml-1.3.20.jar
207
+ - lib/asciidoctor-diagram/plantuml/plantuml-1.3.21.jar
205
208
  - lib/asciidoctor-diagram/salt.rb
206
209
  - lib/asciidoctor-diagram/shaape.rb
207
210
  - lib/asciidoctor-diagram/shaape/converter.rb
@@ -234,7 +237,7 @@ files:
234
237
  - lib/asciidoctor-diagram/util/pdf.rb
235
238
  - lib/asciidoctor-diagram/util/platform.rb
236
239
  - lib/asciidoctor-diagram/util/png.rb
237
- - lib/asciidoctor-diagram/util/server-1.3.20.jar
240
+ - lib/asciidoctor-diagram/util/server-1.3.21.jar
238
241
  - lib/asciidoctor-diagram/util/svg.rb
239
242
  - lib/asciidoctor-diagram/util/which.rb
240
243
  - lib/asciidoctor-diagram/vega.rb
@@ -254,6 +257,7 @@ files:
254
257
  - spec/dpic_spec.rb
255
258
  - spec/erd_spec.rb
256
259
  - spec/gnuplot_spec.rb
260
+ - spec/graphviz_py_spec.rb
257
261
  - spec/graphviz_spec.rb
258
262
  - spec/lilypond_spec.rb
259
263
  - spec/man.jpg
@@ -278,7 +282,7 @@ homepage: https://github.com/asciidoctor/asciidoctor-diagram
278
282
  licenses:
279
283
  - MIT
280
284
  metadata: {}
281
- post_install_message:
285
+ post_install_message:
282
286
  rdoc_options: []
283
287
  require_paths:
284
288
  - lib
@@ -293,8 +297,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
293
297
  - !ruby/object:Gem::Version
294
298
  version: '0'
295
299
  requirements: []
296
- rubygems_version: 3.0.3
297
- signing_key:
300
+ rubygems_version: 3.2.22
301
+ signing_key:
298
302
  specification_version: 4
299
303
  summary: A family of Asciidoctor extensions that generate images from a broad range
300
304
  of embedded plain text diagram descriptions, including PlantUML, ditaa, Kroki, and
@@ -310,6 +314,7 @@ test_files:
310
314
  - spec/dpic_spec.rb
311
315
  - spec/erd_spec.rb
312
316
  - spec/gnuplot_spec.rb
317
+ - spec/graphviz_py_spec.rb
313
318
  - spec/graphviz_spec.rb
314
319
  - spec/lilypond_spec.rb
315
320
  - spec/man.jpg