jekyll-diagrams 0.9.2 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +32 -20
  3. data/features/blockdiag.feature +1 -2
  4. data/features/graphviz.feature +58 -6
  5. data/features/mermaid.feature +1 -2
  6. data/features/nomnoml.feature +2 -22
  7. data/features/plantuml.feature +17 -8
  8. data/features/smcat.feature +10 -15
  9. data/features/support/env.rb +11 -5
  10. data/features/syntrax.feature +1 -2
  11. data/features/vega.feature +24 -12
  12. data/features/wavedrom.feature +2 -8
  13. data/lib/jekyll-diagrams.rb +64 -1
  14. data/lib/jekyll-diagrams/block.rb +33 -8
  15. data/lib/jekyll-diagrams/blockdiag.rb +8 -6
  16. data/lib/jekyll-diagrams/erd.rb +7 -1
  17. data/lib/jekyll-diagrams/errors.rb +25 -0
  18. data/lib/jekyll-diagrams/graphviz.rb +2 -1
  19. data/lib/jekyll-diagrams/mermaid.rb +4 -5
  20. data/lib/jekyll-diagrams/nomnoml.rb +2 -2
  21. data/lib/jekyll-diagrams/plantuml.rb +3 -4
  22. data/lib/jekyll-diagrams/rendering.rb +67 -0
  23. data/lib/jekyll-diagrams/smcat.rb +2 -2
  24. data/lib/jekyll-diagrams/vega.rb +3 -1
  25. data/lib/jekyll-diagrams/version.rb +1 -1
  26. data/test/block_test.rb +6 -0
  27. data/test/blockdiag_test.rb +28 -0
  28. data/test/erd_test.rb +5 -2
  29. data/test/rendering_test.rb +20 -0
  30. data/test/svgbob_test.rb +22 -0
  31. data/test/test_helper.rb +12 -3
  32. metadata +118 -39
  33. data/.coveralls.yml +0 -1
  34. data/.github/workflows/test.yml +0 -83
  35. data/.gitignore +0 -4
  36. data/.rubocop.yml +0 -22
  37. data/.simplecov +0 -5
  38. data/.travis.yml +0 -50
  39. data/Dockerfile +0 -53
  40. data/Gemfile +0 -8
  41. data/Rakefile +0 -28
  42. data/features/svgbob.feature +0 -22
  43. data/jekyll-diagrams.gemspec +0 -31
  44. data/lib/jekyll-diagrams/util.rb +0 -95
  45. data/test/util_test.rb +0 -20
@@ -1,6 +1,69 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'jekyll-diagrams/util'
3
+ require 'jekyll'
4
+
5
+ module Jekyll
6
+ module Diagrams
7
+ class << self
8
+ # Return configuration of Jekyll Diagrams
9
+ #
10
+ # @param context [Liquid::Context, :registers] Parsed context
11
+ # @return Configuration
12
+ def configuration(context)
13
+ site_config = context.registers[:site].config
14
+ page_config = context.registers[:page]
15
+
16
+ site_config.merge(page_config)
17
+ end
18
+
19
+ def config_for(context, name)
20
+ configuration(context).dig(config_name, name) || {}
21
+ end
22
+
23
+ def error_mode(context)
24
+ liquid_mode = configuration(context).dig('liquid', 'error_mode')
25
+ custom_mode = configuration(context).dig(config_name, 'error_mode')
26
+
27
+ (custom_mode || liquid_mode || :warn).to_sym
28
+ end
29
+
30
+ # Return file path under vendor path
31
+ #
32
+ # @param file [String] If not given, return directory path
33
+ def vendor_path(file = '')
34
+ File.join(File.expand_path('../vendor', __dir__), file)
35
+ end
36
+
37
+ # @param jar [String] Jar path to run
38
+ def run_jar(jar)
39
+ "java -Djava.awt.headless=true -jar #{jar} "
40
+ end
41
+
42
+ def normalized_attrs(attrs, prefix:, sep: '=')
43
+ attrs =
44
+ case attrs
45
+ when String
46
+ attrs
47
+ when Array
48
+ attrs.join(prefix)
49
+ when Hash
50
+ attrs.map { |k, v| "#{k}#{sep}#{v}" }.join(prefix)
51
+ end
52
+
53
+ "#{prefix}#{attrs}"
54
+ end
55
+
56
+ private
57
+
58
+ def config_name
59
+ 'jekyll-diagrams'
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ require_relative 'jekyll-diagrams/errors'
66
+ require_relative 'jekyll-diagrams/rendering'
4
67
  require_relative 'jekyll-diagrams/block'
5
68
 
6
69
  require_relative 'jekyll-diagrams/blockdiag'
@@ -3,23 +3,48 @@
3
3
  module Jekyll
4
4
  module Diagrams
5
5
  class Block < Liquid::Block
6
- include Util
6
+ include Rendering
7
7
 
8
8
  def render(context)
9
- svg = render_svg(super.to_s, read_config(context))
10
- wrap_class(svg)
9
+ config = Diagrams.config_for(context, block_name)
10
+
11
+ output = render_svg(super.to_s, config)
12
+ wrap_class(output)
13
+ rescue StandardError => e
14
+ error_mode = Diagrams.error_mode(context)
15
+
16
+ output = handle_error(e, error_mode)
17
+ wrap_class(output)
11
18
  end
12
19
 
13
- def render_svg(_, _)
20
+ private
21
+
22
+ def render_svg(_code, _config)
14
23
  ''
15
24
  end
16
25
 
17
- def read_config(context)
18
- config_for(context, block_name)
26
+ def wrap_class(content)
27
+ <<~CONTENT
28
+ <div class='jekyll-diagrams diagrams #{block_name}'>
29
+ #{content}
30
+ </div>"
31
+ CONTENT
19
32
  end
20
33
 
21
- def wrap_class(content)
22
- "<div class='jekyll-diagrams diagrams #{block_name}'>#{content}</div>"
34
+ def handle_error(error, mode)
35
+ topic = 'Jekyll Diagrams:'
36
+ msg = error.message
37
+
38
+ case mode
39
+ when :lax
40
+ Jekyll.logger.info topic, msg
41
+ ''
42
+ when :warn
43
+ Jekyll.logger.warn topic, msg
44
+ msg
45
+ when :strict
46
+ Jekyll.logger.abort_with topic, msg
47
+ end
23
48
  end
24
49
  end
25
50
  end
@@ -4,6 +4,9 @@ module Jekyll
4
4
  module Diagrams
5
5
  class BlockdiagBlock < Block
6
6
  CONFIGURATIONS = %w[config font fontmap size].freeze
7
+ SWITCHES = {
8
+ 'antialias' => false
9
+ }.freeze
7
10
 
8
11
  def render_svg(code, config)
9
12
  command = build_command(config)
@@ -13,13 +16,12 @@ module Jekyll
13
16
  end
14
17
  end
15
18
 
16
- def read_config(context)
17
- config_for(context, 'blockdiag').merge(config_for(context, block_name))
18
- end
19
-
20
19
  def build_command(config)
21
- command = "#{block_name} -T svg --nodoctype"
22
- command << ' --antialias' if config.fetch('antialias', false) != false
20
+ command = +"#{block_name} -T svg --nodoctype"
21
+
22
+ SWITCHES.merge(config.slice(*SWITCHES.keys)).each do |switch, value|
23
+ command << " --#{switch}" if value != false
24
+ end
23
25
 
24
26
  CONFIGURATIONS.each do |conf|
25
27
  command << " --#{conf}=#{config[conf]}" if config.key?(conf)
@@ -5,6 +5,9 @@ module Jekyll
5
5
  class ErdBlock < Block
6
6
  XML_REGEX = /^<\?xml(([^>]|\n)*>\n?){2}/.freeze
7
7
  CONFIGURATIONS = %w[config edge].freeze
8
+ SWITCHES = {
9
+ 'dot-entity' => false
10
+ }.freeze
8
11
 
9
12
  def render_svg(code, config)
10
13
  command = build_command(config)
@@ -15,7 +18,10 @@ module Jekyll
15
18
 
16
19
  def build_command(config)
17
20
  command = +'erd --fmt=svg'
18
- command << ' --dot-entity' if config.fetch('dot-entity', false) != false
21
+
22
+ SWITCHES.merge(config.slice(*SWITCHES.keys)).each do |switch, value|
23
+ command << " --#{switch}" if value != false
24
+ end
19
25
 
20
26
  CONFIGURATIONS.each do |conf|
21
27
  command << " --#{conf}=#{config[conf]}" if config.key?(conf)
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jekyll
4
+ module Diagrams
5
+ module Errors
6
+ BaseError = Class.new(::StandardError) do
7
+ def initialize(msg)
8
+ @msg = msg
9
+ end
10
+ end
11
+
12
+ CommandNotFoundError = Class.new(BaseError) do
13
+ def message
14
+ "Command Not Found: #{@msg}"
15
+ end
16
+ end
17
+
18
+ RenderingFailedError = Class.new(BaseError) do
19
+ def message
20
+ "Rendering Failed: #{@msg}"
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -27,7 +27,8 @@ module Jekyll
27
27
  CONFIGRATIONS.each do |prefix, conf|
28
28
  next unless config.key?(conf)
29
29
 
30
- command << normalized_attrs(config[conf], prefix: " -#{prefix}")
30
+ command << Diagrams.normalized_attrs(config[conf],
31
+ prefix: " -#{prefix}")
31
32
  end
32
33
 
33
34
  command
@@ -3,7 +3,8 @@
3
3
  module Jekyll
4
4
  module Diagrams
5
5
  class MermaidBlock < Block
6
- CONFIGURATIONS = %w[backgroundColor height theme width].freeze
6
+ CONFIGURATIONS = %w[theme width height backgroundColor
7
+ configFile cssFile scale].freeze
7
8
 
8
9
  def render_svg(code, config)
9
10
  command = build_command(config)
@@ -14,10 +15,8 @@ module Jekyll
14
15
  end
15
16
 
16
17
  def build_command(config)
17
- command = +'mmdc'
18
- command << ' --puppeteerConfigFile '
19
- command << vendor_path('mermaid_puppeteer_config.json')
20
- command << ' --transparent' if config.fetch('transparent', false) != false
18
+ command = +'mmdc --puppeteerConfigFile '
19
+ command << Diagrams.vendor_path('mermaid_puppeteer_config.json')
21
20
 
22
21
  CONFIGURATIONS.each do |conf|
23
22
  command << " --#{conf} #{config[conf]}" if config.key?(conf)
@@ -6,8 +6,8 @@ module Jekyll
6
6
  def render_svg(code, config)
7
7
  command = build_command(config)
8
8
 
9
- render_with_tempfile(command, code, stdout: true) do |input|
10
- input
9
+ render_with_tempfile(command, code) do |input, output|
10
+ "#{input} #{output}"
11
11
  end
12
12
  end
13
13
 
@@ -13,10 +13,9 @@ module Jekyll
13
13
  end
14
14
 
15
15
  def build_command(_config)
16
- options = +'java'
17
- options << ' -Djava.awt.headless=true'
18
- options << ' -jar '
19
- options << vendor_path('plantuml.1.2020.1.jar')
16
+ jar = Diagrams.vendor_path('plantuml.1.2020.1.jar')
17
+
18
+ options = +Diagrams.run_jar(jar)
20
19
  options << ' -tsvg -pipe'
21
20
  end
22
21
  end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'open3'
4
+ require 'tempfile'
5
+ require 'tmpdir'
6
+
7
+ module Jekyll
8
+ module Diagrams
9
+ module Rendering
10
+ module_function
11
+
12
+ # Render SVG with stdin and stdout
13
+ #
14
+ # @param command Command to run
15
+ # @param content Content passed to command
16
+ # @return The SVG output
17
+ def render_with_stdin_stdout(command, content)
18
+ render_with_command(command, :stdout, stdin_data: content)
19
+ end
20
+
21
+ # Render SVG with tempfile
22
+ #
23
+ # @param command Command to run
24
+ # @param content Content passed to command
25
+ # @param block Result of block will append to command
26
+ # @return The SVG output
27
+ def render_with_tempfile(command, content)
28
+ Dir.mktmpdir('jekyll-diagrams-rendering') do |dir|
29
+ input = Tempfile.new('input', tmpdir: dir)
30
+ output = Tempfile.new(%w[output .svg], tmpdir: dir)
31
+
32
+ File.write(input.path, content)
33
+
34
+ extra = yield input.path, output.path
35
+ command = "#{command} #{extra}"
36
+
37
+ render_with_command(command, output.path)
38
+ ensure
39
+ input.close!
40
+ output.close!
41
+ end
42
+ end
43
+
44
+ # Render SVG with command
45
+ #
46
+ # @param command Command to run
47
+ # @param output Output path, use :stdout for stdout
48
+ # @param options Extra options passed to Open3.captrue3
49
+ # @return The SVG output
50
+ def render_with_command(command, output = :stdout, **options)
51
+ begin
52
+ stdout, stderr, status = Open3.capture3(command, **options)
53
+ rescue Errno::ENOENT
54
+ raise Errors::CommandNotFoundError, command.split(' ')[0]
55
+ end
56
+
57
+ unless status.success?
58
+ raise Errors::RenderingFailedError, <<~MSG
59
+ #{command}: #{stderr.empty? ? stdout : stderr}
60
+ MSG
61
+ end
62
+
63
+ output == :stdout ? stdout : File.read(output)
64
+ end
65
+ end
66
+ end
67
+ end
@@ -9,8 +9,8 @@ module Jekyll
9
9
  def render_svg(code, config)
10
10
  command = build_command(config)
11
11
 
12
- svg = render_with_tempfile(command, code, stdout: true) do |input|
13
- "#{input} --output-to -"
12
+ svg = render_with_tempfile(command, code) do |input, output|
13
+ "#{input} --output-to #{output}"
14
14
  end
15
15
 
16
16
  svg.sub!(XML_REGEX, '')
@@ -6,7 +6,9 @@ module Jekyll
6
6
  CONFIGURATIONS = %w[scale].freeze
7
7
 
8
8
  def render_svg(code, config)
9
- code = render_with_stdin_stdout('vl2vg', code) if block_name == 'vegalite'
9
+ if block_name == 'vegalite'
10
+ code = render_with_stdin_stdout('vl2vg', code)
11
+ end
10
12
 
11
13
  command = build_command(config)
12
14
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Jekyll
4
4
  module Diagrams
5
- VERSION = '0.9.2'
5
+ VERSION = '0.9.3'
6
6
  end
7
7
  end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ class BlockTest < Minitest::Test
6
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ class BlockdiagTest < Minitest::Test
6
+ def setup
7
+ @block = Jekyll::Diagrams::BlockdiagBlock.parse(
8
+ 'blockdiag',
9
+ '',
10
+ Liquid::Tokenizer.new('{% endblockdiag %}'),
11
+ Liquid::ParseContext.new
12
+ )
13
+ end
14
+
15
+ def test_build_command_with_default_config
16
+ config = {}
17
+ assert_equal 'blockdiag -T svg --nodoctype', @block.build_command(config)
18
+
19
+ config = { 'antialias' => true }
20
+ assert_match '--antialias', @block.build_command(config)
21
+
22
+ config = { 'antialias' => false }
23
+ refute_match '--antialias', @block.build_command(config)
24
+
25
+ config = { 'size' => 3 }
26
+ assert_match '--size=3', @block.build_command(config)
27
+ end
28
+ end
data/test/erd_test.rb CHANGED
@@ -4,8 +4,11 @@ require 'test_helper'
4
4
 
5
5
  class ErdTest < Minitest::Test
6
6
  def setup
7
- @block = Jekyll::Diagrams::ErdBlock.send(
8
- :new, 'erd', '', Liquid::ParseContext.new
7
+ @block = Jekyll::Diagrams::ErdBlock.parse(
8
+ 'erd',
9
+ '',
10
+ Liquid::Tokenizer.new('test {% enderd %}'),
11
+ Liquid::ParseContext.new
9
12
  )
10
13
  end
11
14
 
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ class RenderingTest < Minitest::Test
6
+ include Jekyll::Diagrams::Errors
7
+ include Jekyll::Diagrams::Rendering
8
+
9
+ def test_raise_command_not_found_error
10
+ assert_raises CommandNotFoundError do
11
+ render_with_command('not_exist_command')
12
+ end
13
+ end
14
+
15
+ def test_raise_rendering_failed_error
16
+ assert_raises RenderingFailedError do
17
+ render_with_command('/bin/bash -c "exit 1"')
18
+ end
19
+ end
20
+ end