kramdown-plantuml 1.0.4 → 1.1.3

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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.github/codecov.yml +2 -0
  3. data/.github/dependabot.yml +23 -0
  4. data/.github/mergify.yml +22 -0
  5. data/.github/scripts/amend.sh +176 -0
  6. data/.github/scripts/build-gem.sh +6 -0
  7. data/.github/scripts/inspect-gem.sh +72 -0
  8. data/.github/scripts/publish-gem.sh +121 -0
  9. data/.github/scripts/test-gem.sh +170 -0
  10. data/.github/scripts/variables.sh +72 -0
  11. data/.github/workflows/amend.yml +19 -0
  12. data/.github/workflows/no-java.yml +3 -6
  13. data/.github/workflows/no-plantuml.yml +6 -9
  14. data/.github/workflows/ruby.yml +135 -81
  15. data/.github/workflows/shell.yml +11 -0
  16. data/.gitignore +9 -0
  17. data/.rubocop.yml +18 -0
  18. data/Gemfile +4 -8
  19. data/GitVersion.yml +5 -0
  20. data/LICENSE +201 -21
  21. data/README.md +130 -42
  22. data/Rakefile +33 -3
  23. data/bin/{plantuml.1.2020.5.jar → net/sourceforge/plantuml/plantuml/1.2021.8/plantuml-1.2021.8.jar} +0 -0
  24. data/kramdown-plantuml.gemspec +32 -17
  25. data/lib/kramdown-plantuml.rb +4 -6
  26. data/lib/kramdown-plantuml/bool_env.rb +24 -0
  27. data/lib/kramdown-plantuml/console_logger.rb +56 -0
  28. data/lib/kramdown-plantuml/converter.rb +40 -33
  29. data/lib/kramdown-plantuml/executor.rb +48 -0
  30. data/lib/kramdown-plantuml/logger.rb +89 -0
  31. data/lib/kramdown-plantuml/plantuml_error.rb +33 -0
  32. data/lib/kramdown-plantuml/plantuml_result.rb +50 -0
  33. data/lib/kramdown-plantuml/themer.rb +76 -0
  34. data/lib/kramdown-plantuml/version.rb +3 -2
  35. data/lib/kramdown_html.rb +21 -9
  36. data/lib/which.rb +3 -0
  37. data/pom.xml +16 -0
  38. metadata +128 -10
  39. data/bin/console +0 -14
  40. data/bin/setup +0 -8
data/Rakefile CHANGED
@@ -1,10 +1,40 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rake'
2
4
  require 'bundler/gem_tasks'
3
5
  require 'rspec/core/rake_task'
4
6
 
5
7
  RSpec::Core::RakeTask.new(:spec) do |t|
6
- t.pattern = Dir.glob('spec/**/*_spec.rb')
7
- t.rspec_opts = '--format documentation --tag ~no_plantuml --tag ~no_java'
8
+ t.pattern = Dir.glob('spec/**/*_spec.rb')
9
+ t.rspec_opts = '--format documentation --tag ~no_plantuml --tag ~no_java --tag ~debug'
10
+ end
11
+
12
+ namespace :maven do
13
+ task :install do
14
+ require 'fileutils'
15
+
16
+ system 'mvn install'
17
+ bin_dir = File.join __dir__, 'bin'
18
+ target_file = File.join bin_dir, 'plantuml.jar'
19
+ repo_dir = File.expand_path '~/.m2/repository'
20
+ jar_glob = File.join repo_dir, '/**/plantuml*.jar'
21
+ first_jar = Dir[jar_glob].first
22
+ jar_file = File.expand_path first_jar
23
+
24
+ FileUtils.mkdir_p bin_dir
25
+ FileUtils.move(jar_file, target_file)
26
+ end
27
+ end
28
+
29
+ namespace :codecov do
30
+ desc 'Uploads the latest SimpleCov result set to codecov.io'
31
+ task :upload do
32
+ require 'simplecov'
33
+ require 'codecov'
34
+
35
+ formatter = SimpleCov::Formatter::Codecov.new
36
+ formatter.format(SimpleCov::ResultMerger.merged_result)
37
+ end
8
38
  end
9
39
 
10
- task :default => :spec
40
+ task default: :spec
@@ -1,33 +1,48 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'lib/which'
2
4
  require_relative 'lib/kramdown-plantuml/version'
3
5
 
4
6
  Gem::Specification.new do |spec|
5
- spec.name = "kramdown-plantuml"
7
+ spec.name = 'kramdown-plantuml'
6
8
  spec.version = Kramdown::PlantUml::VERSION
7
- spec.authors = ["Asbjørn Ulsberg"]
8
- spec.email = ["asbjorn@ulsberg.no"]
9
+ spec.authors = ['Swedbank Pay']
10
+ spec.email = ['opensource@swedbankpay.com']
9
11
 
10
- spec.summary = "Short summary"
11
- spec.homepage = "https://github.com/SwedbankPay/kramdown-plantuml"
12
- spec.license = "MIT"
13
- spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
12
+ spec.summary = <<~SUMMARY
13
+ kramdown-plantuml allows you to use PlantUML syntax within fenced code
14
+ blocks with Kramdown (Jekyll's default Markdown parser).
15
+ SUMMARY
16
+ spec.homepage = 'https://github.com/SwedbankPay/kramdown-plantuml'
17
+ spec.license = 'MIT'
18
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.5.0')
14
19
 
15
- spec.metadata["homepage_uri"] = spec.homepage
16
- spec.metadata["source_code_uri"] = "https://github.com/SwedbankPay/kramdown-plantuml"
20
+ spec.metadata['homepage_uri'] = spec.homepage
21
+ spec.metadata['source_code_uri'] = 'https://github.com/SwedbankPay/kramdown-plantuml'
17
22
 
18
23
  # Specify which files should be added to the gem when it is released.
19
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
20
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
21
- if Which::which('git')
22
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
24
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into Git.
25
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
26
+ if Which.which('git')
27
+ files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
28
+ # Explicitly add plantuml.jar to the list of files as it is not committed to Git.
29
+ files.append(Dir['bin/**/plantuml*.jar'].first)
23
30
  else
24
31
  puts "Git not found, no files added to #{spec.name}."
25
32
  end
26
33
  end
27
- spec.bindir = "exe"
34
+ spec.bindir = 'exe'
28
35
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
29
- spec.require_paths = ["lib"]
36
+ spec.require_paths = ['lib']
37
+
38
+ spec.add_dependency 'kramdown', '~> 2.3'
39
+ spec.add_dependency 'kramdown-parser-gfm', '~> 1.1'
40
+ spec.add_dependency 'open3', '~> 0.1'
30
41
 
31
- spec.add_development_dependency "rake", "~> 13.0"
32
- spec.add_development_dependency "rspec", "~> 3.2"
42
+ spec.add_development_dependency 'rake', '~> 13.0'
43
+ spec.add_development_dependency 'rspec', '~> 3.2'
44
+ spec.add_development_dependency 'rspec-its', '~> 1.3'
45
+ spec.add_development_dependency 'rubocop', '~> 1.12'
46
+ spec.add_development_dependency 'rubocop-rake', '~> 0.6'
47
+ spec.add_development_dependency 'rubocop-rspec', '~> 2.4'
33
48
  end
@@ -1,7 +1,5 @@
1
- require 'kramdown-plantuml/version'
2
- require 'kramdown-plantuml/converter'
3
- require 'kramdown_html'
1
+ # frozen_string_literal: true
4
2
 
5
- module Kramdown::PlantUml
6
- class Error < StandardError; end
7
- end
3
+ require_relative 'kramdown-plantuml/version'
4
+ require_relative 'kramdown-plantuml/converter'
5
+ require_relative 'kramdown_html'
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kramdown
4
+ module PlantUml
5
+ # Converts envrionment variables to boolean values
6
+ class BoolEnv
7
+ TRUTHY_VALUES = %w[t true yes y 1].freeze
8
+ FALSEY_VALUES = %w[f false n no 0].freeze
9
+
10
+ def initialize(name)
11
+ @name = name
12
+ value = ENV.fetch(name, nil)
13
+ @value = value.to_s.downcase unless value.nil?
14
+ end
15
+
16
+ def true?
17
+ return true if TRUTHY_VALUES.include?(@value)
18
+ return false if FALSEY_VALUES.include?(@value) || @value.nil? || value.empty?
19
+
20
+ raise "The value '#{@value}' of '#{@name}' can't be converted to a boolean"
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'bool_env'
4
+
5
+ module Kramdown
6
+ module PlantUml
7
+ # Logs to $stdout and $stderr
8
+ class ConsoleLogger
9
+ LOG_LEVELS = %i[debug info warn error].freeze
10
+
11
+ def initialize(level)
12
+ @configured_log_level = level
13
+ end
14
+
15
+ def debug(message)
16
+ write(:debug, message)
17
+ end
18
+
19
+ def info(message)
20
+ write(:info, message)
21
+ end
22
+
23
+ def warn(message)
24
+ write(:warn, message)
25
+ end
26
+
27
+ def error(message)
28
+ write(:error, message)
29
+ end
30
+
31
+ private
32
+
33
+ def write(level, message)
34
+ return false unless write_message?(level)
35
+
36
+ pipe = pipe_for(level)
37
+ pipe.write("#{message}\n")
38
+ end
39
+
40
+ def write_message?(level_of_message)
41
+ LOG_LEVELS.index(@configured_log_level) <= LOG_LEVELS.index(level_of_message)
42
+ end
43
+
44
+ def pipe_for(level)
45
+ case level
46
+ when :debug, :info
47
+ $stdout
48
+ when :warn, :error
49
+ $stderr
50
+ else
51
+ raise ArgumentError, "Unknown log level '#{level}'."
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -1,45 +1,52 @@
1
- require 'which'
2
- require 'open3'
3
- require_relative 'version'
4
-
5
- module Kramdown::PlantUml
6
- class Converter
7
- def initialize
8
- dir = File.dirname __dir__
9
- bin = File.join dir, "../bin"
10
- bin = File.expand_path bin
11
- @plant_uml_jar_file = File.join bin, "plantuml.1.2020.5.jar"
1
+ # frozen_string_literal: true
12
2
 
13
- if not File.exists? @plant_uml_jar_file
14
- raise IOError.new("'#{@plant_uml_jar_file}' does not exist")
3
+ require_relative 'version'
4
+ require_relative 'themer'
5
+ require_relative 'plantuml_error'
6
+ require_relative 'logger'
7
+ require_relative 'executor'
8
+
9
+ module Kramdown
10
+ module PlantUml
11
+ # Converts PlantUML markup to SVG
12
+ class Converter
13
+ def initialize(options = {})
14
+ @themer = Themer.new(options)
15
+ @logger = Logger.init
16
+ @executor = Executor.new
15
17
  end
16
18
 
17
- unless Which::which("java")
18
- raise IOError.new("Java can not be found")
19
+ def convert_plantuml_to_svg(plantuml)
20
+ if plantuml.nil? || plantuml.empty?
21
+ @logger.warn ' kramdown-plantuml: PlantUML diagram is empty'
22
+ return plantuml
23
+ end
24
+
25
+ plantuml = @themer.apply_theme(plantuml)
26
+ plantuml = plantuml.strip
27
+ log(plantuml)
28
+ result = @executor.execute(plantuml)
29
+ result.validate(plantuml)
30
+ svg = result.without_xml_prologue
31
+ wrap(svg)
19
32
  end
20
- end
21
33
 
22
- def convert_plantuml_to_svg(content)
23
- cmd = "java -jar #{@plant_uml_jar_file} -tsvg -pipe"
34
+ private
24
35
 
25
- stdout, stderr, _ = Open3.capture3(cmd, :stdin_data => content)
36
+ def wrap(svg)
37
+ theme_class = @themer.theme_name ? "theme-#{@themer.theme_name}" : ''
38
+ class_name = "plantuml #{theme_class}".strip
26
39
 
27
- unless stderr.empty?
28
- raise stderr
29
- end
30
-
31
- xml_prologue_start = "<?xml"
32
- xml_prologue_end = "?>"
40
+ wrapper_element_start = "<div class=\"#{class_name}\">"
41
+ wrapper_element_end = '</div>'
33
42
 
34
- start_index = stdout.index(xml_prologue_start)
35
- end_index = stdout.index(xml_prologue_end, xml_prologue_start.length) + xml_prologue_end.length
36
-
37
- stdout.slice! start_index, end_index
38
-
39
- wrapper_element_start = "<div class=\"plantuml\">"
40
- wrapper_element_end = "</div>"
43
+ "#{wrapper_element_start}#{svg}#{wrapper_element_end}"
44
+ end
41
45
 
42
- return "#{wrapper_element_start}#{stdout}#{wrapper_element_end}"
46
+ def log(plantuml)
47
+ @logger.debug ' kramdown-plantuml: PlantUML converting diagram:'
48
+ @logger.debug_with_prefix ' kramdown-plantuml: ', plantuml
49
+ end
43
50
  end
44
51
  end
45
52
  end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: false
2
+
3
+ require 'open3'
4
+ require_relative '../which'
5
+ require_relative 'logger'
6
+ require_relative 'plantuml_result'
7
+
8
+ module Kramdown
9
+ module PlantUml
10
+ # Executes the PlantUML Java application.
11
+ class Executor
12
+ def initialize
13
+ @logger = Logger.init
14
+ @plantuml_jar_file = find_plantuml_jar_file
15
+
16
+ raise IOError, 'Java can not be found' unless Which.which('java')
17
+ raise IOError, "No 'plantuml.jar' file could be found" if @plantuml_jar_file.nil?
18
+ raise IOError, "'#{@plantuml_jar_file}' does not exist" unless File.exist? @plantuml_jar_file
19
+ end
20
+
21
+ def execute(stdin)
22
+ cmd = "java -Djava.awt.headless=true -jar #{@plantuml_jar_file} -tsvg -failfast -pipe"
23
+ cmd << if @logger.debug?
24
+ ' -verbose'
25
+ else
26
+ ' -nometadata'
27
+ end
28
+
29
+ @logger.debug " kramdown-plantuml: Executing '#{cmd}'."
30
+
31
+ stdout, stderr, status = Open3.capture3 cmd, stdin_data: stdin
32
+
33
+ @logger.debug " kramdown-plantuml: PlantUML exit code '#{status.exitstatus}'."
34
+
35
+ PlantUmlResult.new(stdout, stderr, status)
36
+ end
37
+
38
+ private
39
+
40
+ def find_plantuml_jar_file
41
+ dir = File.dirname __dir__
42
+ jar_glob = File.join dir, '../bin/**/plantuml*.jar'
43
+ first_jar = Dir[jar_glob].first
44
+ File.expand_path first_jar unless first_jar.nil?
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'console_logger'
4
+
5
+ module Kramdown
6
+ module PlantUml
7
+ # Logs stuff
8
+ class Logger
9
+ def initialize(logger)
10
+ raise ArgumentError, 'logger cannot be nil' if logger.nil?
11
+ raise ArgumentError, 'logger must respond to #debug' unless logger.respond_to? :debug
12
+ raise ArgumentError, 'logger must respond to #info' unless logger.respond_to? :info
13
+ raise ArgumentError, 'logger must respond to #warn' unless logger.respond_to? :warn
14
+ raise ArgumentError, 'logger must respond to #error' unless logger.respond_to? :error
15
+
16
+ @logger = logger
17
+ end
18
+
19
+ def debug(message)
20
+ @logger.debug message
21
+ end
22
+
23
+ def debug_with_prefix(prefix, string)
24
+ return if string.nil? || string.empty?
25
+
26
+ lines = string.lines
27
+ lines.each do |line|
28
+ @logger.debug "#{prefix}#{line.rstrip}"
29
+ end
30
+ end
31
+
32
+ def info(message)
33
+ @logger.info message
34
+ end
35
+
36
+ def warn(message)
37
+ @logger.warn message
38
+ end
39
+
40
+ def error(message)
41
+ @logger.error message
42
+ end
43
+
44
+ def debug?
45
+ self.class.level == :debug
46
+ end
47
+
48
+ def level
49
+ @level ||= level_from_logger || self.class.env
50
+ end
51
+
52
+ class << self
53
+ def init
54
+ inner = nil
55
+
56
+ begin
57
+ require 'jekyll'
58
+ inner = Jekyll.logger
59
+ rescue LoadError
60
+ inner = ConsoleLogger.new level
61
+ end
62
+
63
+ Logger.new inner
64
+ end
65
+
66
+ def level
67
+ @level ||= level_from_env
68
+ end
69
+
70
+ private
71
+
72
+ def level_from_env
73
+ return :debug if BoolEnv.new('DEBUG').true?
74
+ return :debug if BoolEnv.new('VERBOSE').true?
75
+
76
+ :warn
77
+ end
78
+ end
79
+
80
+ private
81
+
82
+ def level_from_logger
83
+ return @logger.level if @logger.respond_to? :level
84
+
85
+ nil
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kramdown
4
+ module PlantUml
5
+ # PlantUML Error
6
+ class PlantUmlError < StandardError
7
+ def initialize(plantuml, stderr, exitcode)
8
+ message = <<~MESSAGE
9
+ Conversion of the following PlantUML diagram failed:
10
+
11
+ #{plantuml}
12
+
13
+ The error received from PlantUML was:
14
+
15
+ Exit code: #{exitcode}
16
+ #{stderr}
17
+ MESSAGE
18
+
19
+ super message
20
+ end
21
+
22
+ def self.should_raise?(exitcode, stderr)
23
+ return false if exitcode.zero?
24
+
25
+ !stderr.nil? && !stderr.empty? && \
26
+ # If stderr is not empty, but contains the string 'CoreText note:',
27
+ # the error is caused by a bug in Java, and should be ignored.
28
+ # Circumvents https://bugs.openjdk.java.net/browse/JDK-8244621
29
+ !stderr.include?('CoreText note:')
30
+ end
31
+ end
32
+ end
33
+ end