kramdown-plantuml 1.1.3 → 1.1.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 51cbb0be0b06278afe3b3d1eb572190a9f7a04fc869454b023854d5d8012e596
4
- data.tar.gz: 0e7cb4345aeab6972d3b0009b71ddc714f046f5b558ae1d37b334697af39575b
3
+ metadata.gz: 178996116d7a833c324db54da1b3c367fe13c1d55fabc47026df12bec25b6f9d
4
+ data.tar.gz: d5dc3e4824ab5095b42b33e4b01cc6cb38735fe0bb220472f02e8014f069261b
5
5
  SHA512:
6
- metadata.gz: c18e9c35a4fef278f506106c1365839e7f58b0b45c8b352912187cd324df373b342400e56f51b9c13278ab199fd5fb6101c63cd02aa25ce9efef07722d7c517a
7
- data.tar.gz: d822db2c31c38db0f7ce0a5b92221ebf30a55be1f5d011141199d07d94a01b5ddba99a1ba127d13b88219f6135a384d90741315b6e00b88d0e72c20fa1220d2f
6
+ metadata.gz: 5dd2e36fc7b66a4a8948ba801d75107c04fedbbb612fe525cabac758de15e3908368999d8779126a082dfcef70f990194c3abf0bace90eea019b182e3d26626c
7
+ data.tar.gz: 166be327fab188558c365c5284739d57ed7b851ce953e616b98d7f9002a20f89ab6af7527134a148eefdf547c4465adfe469d597eb8919af26a51cf3615e2b57
data/.github/mergify.yml CHANGED
@@ -17,6 +17,7 @@ pull_request_rules:
17
17
  - name: Thank contributor
18
18
  conditions:
19
19
  - merged
20
+ - -author~=^.*\[bot\]$
20
21
  actions:
21
22
  comment:
22
23
  message: "Thank you @{{author}} for your contribution!"
@@ -1,6 +1,73 @@
1
1
  #!/usr/bin/env bash
2
2
  set -o errexit # Abort if any command fails
3
3
 
4
- gem_build_name=$(gem build kramdown-plantuml.gemspec | awk '/File/ {print $2}')
5
- echo "Gem filename: '${gem_build_name}'"
6
- echo "::set-output name=name::${gem_build_name}"
4
+ me=$(basename "$0")
5
+ help_message="\
6
+ Usage:
7
+ ${me} [--ref <ref>] [--verbose]
8
+ ${me} --help
9
+ Arguments:
10
+ -r, --ref The Git reference that is being built.
11
+ -h, --help Displays this help screen.
12
+ -v, --verbose Increase verbosity. Useful for debugging."
13
+
14
+ parse_args() {
15
+ while : ; do
16
+ if [[ $1 = "-h" || $1 = "--help" ]]; then
17
+ echo "${help_message}"
18
+ return 0
19
+ elif [[ $1 = "-v" || $1 = "--verbose" ]]; then
20
+ verbose=true
21
+ shift
22
+ elif [[ $1 = "-r" || $1 = "--ref" ]]; then
23
+ ref=${2// }
24
+
25
+ if [[ "${ref}" = "--"* ]]; then
26
+ ref=""
27
+ shift 1
28
+ else
29
+ shift 2
30
+ fi
31
+ else
32
+ break
33
+ fi
34
+ done
35
+ }
36
+
37
+ # Echo expanded commands as they are executed (for debugging)
38
+ enable_expanded_output() {
39
+ if [ "${verbose}" = true ]; then
40
+ set -o xtrace
41
+ set +o verbose
42
+ export VERBOSE=true
43
+ fi
44
+ }
45
+
46
+ add_coverage() {
47
+ # If we're not building a tag, bootstrap code coverage.
48
+ if [[ "${ref}" != "refs/tags/"* ]]; then
49
+ [[ "${verbose}" = true ]] && echo "Bootstrapping code coverage."
50
+ export COVER=true
51
+ export COVERAGE=true
52
+ printf "require 'simplecov'\nSimpleCov.start\n" >> lib/kramdown-plantuml.rb
53
+ elif [[ "${verbose}" = true ]]; then
54
+ echo "Skipping coverage report since a tag ref was pushed."
55
+ fi
56
+ }
57
+
58
+ build_gem() {
59
+ gem_build_name=$(gem build kramdown-plantuml.gemspec | awk '/File/ {print $2}')
60
+
61
+ [[ "${verbose}" = true ]] && echo "Gem filename: '${gem_build_name}'"
62
+
63
+ echo "::set-output name=name::${gem_build_name}"
64
+ }
65
+
66
+ main() {
67
+ parse_args "$@"
68
+ enable_expanded_output
69
+ add_coverage
70
+ build_gem
71
+ }
72
+
73
+ main "$@"
@@ -6,7 +6,7 @@ me=$(basename "$0")
6
6
 
7
7
  help_message="\
8
8
  Usage:
9
- ${me} --workdir <workdir> [--gemdir <gemdir> | --version <version> --token <token>] [--verbose]
9
+ ${me} --workdir <workdir> [--gemdir <gemdir> | --version <version> --token <token>] [--verbose] [--theme <name> [--theme-directory <path>]]
10
10
  ${me} --help
11
11
  Arguments:
12
12
  -w, --workdir <workdir> The path to the working directory.
@@ -14,6 +14,8 @@ Arguments:
14
14
  -v, --version <version> The version of the Gem to test.
15
15
  -t, --token <token> The GitHub token to use for retrieving the gem
16
16
  from the GitHub Package Registry.
17
+ -T, --theme-name <name> The theme name to use for the test.
18
+ -p, --theme-directory <path> The directory in which the [--theme-name] is placed.
17
19
  -h, --help Displays this help screen.
18
20
  -v, --verbose Increase verbosity. Useful for debugging."
19
21
 
@@ -52,6 +54,24 @@ parse_args() {
52
54
  else
53
55
  shift 2
54
56
  fi
57
+ elif [[ $1 = "-T" || $1 = "--theme-name" ]]; then
58
+ theme_name=${2// }
59
+
60
+ if [[ "${theme_name}" = "--"* ]]; then
61
+ theme_name=""
62
+ shift 1
63
+ else
64
+ shift 2
65
+ fi
66
+ elif [[ $1 = "-p" || $1 = "--theme-directory" ]]; then
67
+ theme_directory=${2// }
68
+
69
+ if [[ "${theme_directory}" = "--"* ]]; then
70
+ theme_directory=""
71
+ shift 1
72
+ else
73
+ shift 2
74
+ fi
55
75
  elif [[ $1 = "-w" || $1 = "--workdir" ]]; then
56
76
  workdir=${2// }
57
77
 
@@ -67,22 +87,29 @@ parse_args() {
67
87
  done
68
88
 
69
89
  if [[ -z "${workdir}" ]]; then
70
- echo "Missing required argument: --workdir <workdir>."
71
- echo "${help_message}"
90
+ echo "Missing required argument: --workdir <workdir>." >&2
91
+ echo "${help_message}" >&2
72
92
  return 1
73
93
  fi
74
94
 
75
95
  if [[ (-z "${gemdir}" && -z "${token}") || (-n "${gemdir}" && -n "${token}") ]]; then
76
- echo "Missing or invalid required arguments: --gemdir <gem-path> or --token <token>."
77
- echo "Either [--gemdir] or [--token] needs to be provided, but not both."
96
+ echo "Missing or invalid required arguments: --gemdir <gem-path> or --token <token>." >&2
97
+ echo "Either [--gemdir] or [--token] needs to be provided, but not both." >&2
78
98
  echo "${help_message}"
79
99
  return 1
80
100
  fi
81
101
 
82
102
  if [[ (-n "${version}" && -z "${token}") || (-z "${version}" && -n "${token}") ]]; then
83
- echo "Missing or invalid required arguments: --version <gem-path> and --token <token>."
84
- echo "When either argument is present, both must be."
85
- echo "${help_message}"
103
+ echo "Missing or invalid required arguments: --version <gem-path> and --token <token>." >&2
104
+ echo "When either argument is present, both must be." >&2
105
+ echo "${help_message}" >&2
106
+ return 1
107
+ fi
108
+
109
+ if [[ -z "${theme_name}" && -n "${theme_directory}" ]]; then
110
+ echo "Missing or invalid required arguments: --theme-name <name>." >&2
111
+ echo "[--theme-name] is required when [--theme-directory] is provided." >&2
112
+ echo "${help_message}" >&2
86
113
  return 1
87
114
  fi
88
115
  }
@@ -101,19 +128,37 @@ test_gem() {
101
128
 
102
129
  cd "${workdir}"
103
130
 
104
- gem install bundler
131
+ # Recreate Gemfile
132
+ printf "# frozen_string_literal: true\nsource 'https://rubygems.org'\ngem 'jekyll'\ngem 'simplecov'\n" > Gemfile
105
133
 
106
134
  if [[ -n "${token}" ]]; then
107
135
  # A non-empty $token means we should install the Gem from GPR
108
136
  repository="https://rubygems.pkg.github.com/swedbankpay"
109
137
  bundle config "${repository}" "SwedbankPay:${token}"
110
- printf "source '%s' do\n\tgem 'kramdown-plantuml', '%s'\nend" "${repository}" "${version}" >> Gemfile
138
+ printf "source '%s' do\n\tgem 'kramdown-plantuml', '%s'\nend\n" "${repository}" "${version}" >> Gemfile
139
+ else
140
+ printf "gem 'kramdown-plantuml', path: '%s'\n" "${gemdir}" >> Gemfile
141
+ fi
142
+
143
+ # Recreate _config.yml
144
+ printf "plugins:\n- kramdown-plantuml\n" > _config.yml
145
+
146
+ if [[ -n "${theme_name}" ]]; then
147
+ printf "kramdown:\n plantuml:\n theme:\n name: %s\n" "${theme_name}" >> _config.yml
148
+ class="plantuml theme-${theme_name}"
111
149
  else
112
- echo "gem 'kramdown-plantuml', path: '${gemdir}'" >> Gemfile
150
+ class='plantuml'
151
+ fi
152
+
153
+ if [[ -n "${theme_directory}" ]]; then
154
+ printf " directory: %s\n" "${theme_directory}" >> _config.yml
113
155
  fi
114
156
 
115
157
  if [[ "${verbose}" = true ]]; then
158
+ printf "\nGemfile:\n"
116
159
  cat Gemfile
160
+ printf "\n_config.yml\n"
161
+ cat _config.yml
117
162
  jekyll_build_args+=(--verbose)
118
163
  fi
119
164
 
@@ -122,7 +167,7 @@ test_gem() {
122
167
 
123
168
  file="${workdir}/_site/index.html"
124
169
 
125
- file_contains "${file}" "class=\"plantuml theme-spacelab\""
170
+ file_contains "${file}" "class=\"${class}\""
126
171
  file_contains "${file}" "<svg"
127
172
  file_contains "${file}" "<ellipse"
128
173
  file_contains "${file}" "<polygon"
@@ -91,20 +91,51 @@ jobs:
91
91
  - name: rubocop
92
92
  run: bundle exec rubocop --fail-level warning --display-only-fail-level-offenses
93
93
 
94
- - name: Test with Rake
95
- run: bundle exec rake
96
-
97
94
  - name: RSPec (debug)
98
95
  env:
99
96
  DEBUG: 1
100
- run: bundle exec rspec --tag debug
97
+ run: bundle exec rspec --format documentation --tag debug
98
+
99
+ - name: Upload code coverage (debug)
100
+ uses: actions/upload-artifact@v2
101
+ with:
102
+ name: rspec-debug-coverage
103
+ path: ./coverage
104
+
105
+ - name: Codecov upload (debug)
106
+ run: bundle exec rake codecov:upload || echo 'Codecov upload failed'
107
+
108
+ - name: Test with Rake
109
+ run: bundle exec rake
110
+
111
+ - name: Upload code coverage
112
+ uses: actions/upload-artifact@v2
113
+ with:
114
+ name: rspec-coverage
115
+ path: ./coverage
101
116
 
102
117
  - name: Codecov upload
103
118
  run: bundle exec rake codecov:upload || echo 'Codecov upload failed'
104
119
 
120
+ - name: RSPec (Jekyll)
121
+ run: |
122
+ echo "gem 'jekyll', require: false, group: :test" >> Gemfile
123
+ bundle install
124
+ bundle exec rspec --format documentation --tag jekyll
125
+ git checkout HEAD -- Gemfile
126
+
127
+ - name: Upload code coverage (Jekyll)
128
+ uses: actions/upload-artifact@v2
129
+ with:
130
+ name: rspec-jekyll-coverage
131
+ path: ./coverage
132
+
133
+ - name: Codecov upload (Jekyll)
134
+ run: bundle exec rake codecov:upload || echo 'Codecov upload failed'
135
+
105
136
  - name: Build gem
106
137
  id: gem
107
- run: .github/scripts/build-gem.sh
138
+ run: .github/scripts/build-gem.sh --ref ${{ github.ref }} --verbose
108
139
 
109
140
  - name: Upload gem
110
141
  uses: actions/upload-artifact@v2-preview
@@ -116,7 +147,16 @@ jobs:
116
147
  run: .github/scripts/inspect-gem.sh --gem "${{ github.workspace }}/${{ steps.gem.outputs.name }}" --verbose
117
148
 
118
149
  - name: Test gem
119
- run: .github/scripts/test-gem.sh --workdir "${{ github.workspace }}/spec/fixture" --gemdir "${{ github.workspace }}" --verbose
150
+ run: .github/scripts/test-gem.sh --workdir "${{ github.workspace }}/spec/examples" --gemdir "${{ github.workspace }}" --verbose
151
+
152
+ - name: Upload code coverage (gem)
153
+ uses: actions/upload-artifact@v2
154
+ with:
155
+ name: gem-coverage
156
+ path: ./coverage
157
+
158
+ - name: Codecov upload (gem)
159
+ run: bundle exec rake codecov:upload || echo 'Codecov upload failed'
120
160
 
121
161
  publish-dev:
122
162
  needs: [version, gem]
@@ -150,15 +190,21 @@ jobs:
150
190
  - name: Publish to GPR
151
191
  run: .github/scripts/publish-gem.sh --gem ${{ needs.gem.outputs.name }} --token "${{ secrets.GPR_TOKEN }}" --owner SwedbankPay --verbose
152
192
 
153
- - name: Test gem
154
- run: .github/scripts/test-gem.sh --workdir "${{ github.workspace }}/spec/fixture" --version ${{ needs.version.outputs.version }} --token "${{ secrets.GPR_TOKEN }}" --verbose
193
+ - name: Test gem (no theme)
194
+ run: .github/scripts/test-gem.sh --workdir "${{ github.workspace }}/spec/examples" --version ${{ needs.version.outputs.version }} --token "${{ secrets.GPR_TOKEN }}" --verbose
195
+
196
+ - name: Test gem (built-in theme)
197
+ run: .github/scripts/test-gem.sh --workdir "${{ github.workspace }}/spec/examples" --version ${{ needs.version.outputs.version }} --token "${{ secrets.GPR_TOKEN }}" --verbose --theme-name spacelab
198
+
199
+ - name: Test gem (custom theme)
200
+ run: .github/scripts/test-gem.sh --workdir "${{ github.workspace }}/spec/examples" --version ${{ needs.version.outputs.version }} --token "${{ secrets.GPR_TOKEN }}" --verbose --theme-name c2a3b0 --theme-directory "${{ github.workspace }}/spec/examples"
155
201
 
156
202
  - name: Upload Jekyll site
157
203
  uses: actions/upload-artifact@v2-preview
158
204
  if: always()
159
205
  with:
160
206
  name: site
161
- path: ${{ github.workspace }}/spec/fixture/_site
207
+ path: ${{ github.workspace }}/spec/examples/_site
162
208
 
163
209
  publish-prod:
164
210
  needs: [version, gem]
data/README.md CHANGED
@@ -6,6 +6,7 @@
6
6
  [![No PlantUML][no-plantuml-badge]][no-plantuml-workflow]
7
7
  [![Shell][shell-badge]][shell-workflow]
8
8
  [![Codecov][codecov-badge]][codecov]
9
+ [![Codacy Badge][codacy-badge]][codacy]
9
10
  [![License][license-badge]][license]
10
11
  [![CLA assistant][cla-badge]][cla]
11
12
  [![Contributor Covenant][coc-badge]][coc]
@@ -129,6 +130,20 @@ kramdown:
129
130
  directory: path/to/themes
130
131
  ```
131
132
 
133
+ ### Errors
134
+
135
+ By default, `kramdown-plantuml` will raise an error and crash if something goes
136
+ wrong during processing. This can be circumvented by setting the `raise_errors`
137
+ configuration key to `false`:
138
+
139
+ ```yaml
140
+ kramdown:
141
+ plantuml:
142
+ raise_errors: false
143
+ ```
144
+
145
+ The default value of `raise_errors` is `true`.
146
+
132
147
  ## Contributing
133
148
 
134
149
  Bug reports and pull requests are welcome on [GitHub][github]. This project is
@@ -180,6 +195,8 @@ agreement][cla].
180
195
  [clone]: https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/cloning-a-repository
181
196
  [coc-badge]: https://img.shields.io/badge/Contributor%20Covenant-v2.0%20adopted-ff69b4.svg
182
197
  [coc]: ./CODE_OF_CONDUCT.md
198
+ [codacy-badge]: https://app.codacy.com/project/badge/Grade/de72385f4ca444c18819a3ce8a506638
199
+ [codacy]: https://www.codacy.com/gh/SwedbankPay/kramdown-plantuml/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=SwedbankPay/kramdown-plantuml&amp;utm_campaign=Badge_Grade
183
200
  [codecov-badge]: https://codecov.io/gh/SwedbankPay/kramdown-plantuml/branch/main/graph/badge.svg?token=U3QJLVG3HY
184
201
  [codecov]: https://codecov.io/gh/SwedbankPay/kramdown-plantuml/
185
202
  [diagram-svg]: ./spec/examples/diagram.svg
data/Rakefile CHANGED
@@ -6,7 +6,7 @@ require 'rspec/core/rake_task'
6
6
 
7
7
  RSpec::Core::RakeTask.new(:spec) do |t|
8
8
  t.pattern = Dir.glob('spec/**/*_spec.rb')
9
- t.rspec_opts = '--format documentation --tag ~no_plantuml --tag ~no_java --tag ~debug'
9
+ t.rspec_opts = '--format documentation --tag ~no_plantuml --tag ~no_java --tag ~debug --tag ~jekyll'
10
10
  end
11
11
 
12
12
  namespace :maven do
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'lib/which'
3
+ require_relative 'lib/kramdown-plantuml/which'
4
4
  require_relative 'lib/kramdown-plantuml/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'version'
4
+ require_relative 'theme'
5
+ require_relative 'options'
6
+ require_relative 'plantuml_error'
7
+ require_relative 'log_wrapper'
8
+ require_relative 'executor'
9
+
10
+ module Kramdown
11
+ module PlantUml
12
+ # Represents a PlantUML diagram that can be converted to SVG.
13
+ class Diagram
14
+ attr_reader :theme, :plantuml, :result
15
+
16
+ def initialize(plantuml, options)
17
+ raise ArgumentError, 'options cannot be nil' if options.nil?
18
+ raise ArgumentError, "options must be a '#{Options}'." unless options.is_a?(Options)
19
+
20
+ @plantuml = plantuml
21
+ @options = options
22
+ @theme = Theme.new(options)
23
+ @logger = LogWrapper.init
24
+ @executor = Executor.new
25
+ @logger.warn 'PlantUML diagram is empty' if @plantuml.nil? || @plantuml.empty?
26
+ end
27
+
28
+ def convert_to_svg
29
+ return @svg unless @svg.nil?
30
+ return @plantuml if @plantuml.nil? || @plantuml.empty?
31
+
32
+ @plantuml = @theme.apply(@plantuml)
33
+ log(plantuml)
34
+ @result = @executor.execute(self)
35
+ @result.validate
36
+ @svg = wrap(@result.without_xml_prologue)
37
+ rescue StandardError => e
38
+ raise e if @options.raise_errors?
39
+
40
+ @logger.error e.to_s
41
+ end
42
+
43
+ private
44
+
45
+ def wrap(svg)
46
+ theme_class = @theme.name ? "theme-#{@theme.name}" : ''
47
+ class_name = "plantuml #{theme_class}".strip
48
+
49
+ wrapper_element_start = "<div class=\"#{class_name}\">"
50
+ wrapper_element_end = '</div>'
51
+
52
+ "#{wrapper_element_start}#{svg}#{wrapper_element_end}"
53
+ end
54
+
55
+ def log(plantuml)
56
+ @logger.debug 'PlantUML converting diagram:'
57
+ @logger.debug_multiline plantuml
58
+ end
59
+ end
60
+ end
61
+ end
@@ -1,8 +1,8 @@
1
- # frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'open3'
4
- require_relative '../which'
5
- require_relative 'logger'
4
+ require_relative 'which'
5
+ require_relative 'log_wrapper'
6
6
  require_relative 'plantuml_result'
7
7
 
8
8
  module Kramdown
@@ -10,38 +10,52 @@ module Kramdown
10
10
  # Executes the PlantUML Java application.
11
11
  class Executor
12
12
  def initialize
13
- @logger = Logger.init
13
+ @logger = LogWrapper.init
14
+
15
+ java_location = Which.which('java')
16
+
17
+ raise IOError, 'Java can not be found' if java_location.nil?
18
+
19
+ @logger.debug "Java found: #{java_location}"
14
20
  @plantuml_jar_file = find_plantuml_jar_file
15
21
 
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
22
  raise IOError, "'#{@plantuml_jar_file}' does not exist" unless File.exist? @plantuml_jar_file
23
+
24
+ @logger.debug "plantuml.jar found: #{@plantuml_jar_file}"
19
25
  end
20
26
 
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
27
+ def execute(diagram)
28
+ raise ArgumentError, 'diagram cannot be nil' if diagram.nil?
29
+ raise ArgumentError, "diagram must be a #{Diagram}" unless diagram.is_a?(Diagram)
30
+
31
+ cmd = "java -Djava.awt.headless=true -jar #{@plantuml_jar_file} -tsvg -failfast -pipe #{debug_args}"
28
32
 
29
- @logger.debug " kramdown-plantuml: Executing '#{cmd}'."
33
+ @logger.debug "Executing '#{cmd}'."
30
34
 
31
- stdout, stderr, status = Open3.capture3 cmd, stdin_data: stdin
35
+ stdout, stderr, status = Open3.capture3 cmd, stdin_data: diagram.plantuml
32
36
 
33
- @logger.debug " kramdown-plantuml: PlantUML exit code '#{status.exitstatus}'."
37
+ @logger.debug "PlantUML exit code '#{status.exitstatus}'."
34
38
 
35
- PlantUmlResult.new(stdout, stderr, status)
39
+ PlantUmlResult.new(diagram, stdout, stderr, status.exitstatus)
36
40
  end
37
41
 
38
42
  private
39
43
 
40
44
  def find_plantuml_jar_file
41
45
  dir = File.dirname __dir__
42
- jar_glob = File.join dir, '../bin/**/plantuml*.jar'
46
+ bin_dir = File.expand_path File.join dir, '../bin'
47
+ jar_glob = File.join bin_dir, '/**/plantuml*.jar'
43
48
  first_jar = Dir[jar_glob].first
44
- File.expand_path first_jar unless first_jar.nil?
49
+
50
+ raise IOError, "No 'plantuml.jar' file could be found within the '#{bin_dir}' directory." if first_jar.nil?
51
+
52
+ File.expand_path first_jar
53
+ end
54
+
55
+ def debug_args
56
+ return ' -verbose' if @logger.debug?
57
+
58
+ ' -nometadata'
45
59
  end
46
60
  end
47
61
  end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'English'
5
+ require 'rexml/document'
6
+ require_relative 'log_wrapper'
7
+ require_relative 'diagram'
8
+
9
+ module Kramdown
10
+ module PlantUml
11
+ # Provides an instance of Jekyll if available.
12
+ module JekyllProvider
13
+ class << self
14
+ def jekyll
15
+ return @jekyll if defined? @jekyll
16
+
17
+ @jekyll = load_jekyll
18
+ end
19
+
20
+ def install
21
+ return @installed = false if jekyll.nil?
22
+
23
+ logger.debug 'Jekyll detected, hooking into :site:post_render'
24
+
25
+ Jekyll::Hooks.register :site, :post_render do |site|
26
+ logger.debug ':site:post_render triggered.'
27
+
28
+ site.pages.each do |page|
29
+ page.output = replace_needles(page.output)
30
+ end
31
+ end
32
+
33
+ @installed = true
34
+ end
35
+
36
+ def installed?
37
+ @installed
38
+ end
39
+
40
+ def needle(plantuml, options)
41
+ hash = { 'plantuml' => plantuml, 'options' => options.to_h }
42
+
43
+ <<~NEEDLE
44
+ <!--#kramdown-plantuml.start#-->
45
+ #{hash.to_json}
46
+ <!--#kramdown-plantuml.end#-->
47
+ NEEDLE
48
+ rescue StandardError => e
49
+ raise e if options.raise_errors?
50
+
51
+ puts e
52
+ logger.error 'Error while placing needle.'
53
+ logger.error e.to_s
54
+ logger.debug_multiline plantuml
55
+ end
56
+
57
+ private
58
+
59
+ def replace_needles(html)
60
+ return html if html.nil? || html.empty? || !html.is_a?(String)
61
+
62
+ html.gsub(/<!--#kramdown-plantuml\.start#-->(?<json>.*?)<!--#kramdown-plantuml\.end#-->/m) do
63
+ json = $LAST_MATCH_INFO[:json]
64
+ return replace_needle(json)
65
+ rescue StandardError => e
66
+ raise e if options.raise_errors?
67
+
68
+ logger.error "Error while replacing needle: #{e.inspect}"
69
+ end
70
+ end
71
+
72
+ def replace_needle(json)
73
+ hash = JSON.parse(json)
74
+ encoded_plantuml = hash['plantuml']
75
+ plantuml = decode_html_entities(encoded_plantuml)
76
+ options = ::Kramdown::PlantUml::Options.new({ plantuml: hash['options'] })
77
+ diagram = ::Kramdown::PlantUml::Diagram.new(plantuml, options)
78
+ diagram.convert_to_svg
79
+ end
80
+
81
+ def decode_html_entities(encoded_plantuml)
82
+ doc = REXML::Document.new "<plantuml>#{encoded_plantuml}</plantuml>"
83
+ doc.root.text
84
+ end
85
+
86
+ def load_jekyll
87
+ require 'jekyll'
88
+ ::Jekyll
89
+ rescue LoadError
90
+ nil
91
+ end
92
+
93
+ def logger
94
+ @logger ||= ::Kramdown::PlantUml::LogWrapper.init
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -1,11 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'console_logger'
4
+ require_relative 'jekyll_provider'
4
5
 
5
6
  module Kramdown
6
7
  module PlantUml
7
8
  # Logs stuff
8
- class Logger
9
+ class LogWrapper
9
10
  def initialize(logger)
10
11
  raise ArgumentError, 'logger cannot be nil' if logger.nil?
11
12
  raise ArgumentError, 'logger must respond to #debug' unless logger.respond_to? :debug
@@ -17,28 +18,28 @@ module Kramdown
17
18
  end
18
19
 
19
20
  def debug(message)
20
- @logger.debug message
21
+ write :debug, message
21
22
  end
22
23
 
23
- def debug_with_prefix(prefix, string)
24
- return if string.nil? || string.empty?
24
+ def debug_multiline(multiline_string)
25
+ return if multiline_string.nil? || multiline_string.empty?
25
26
 
26
- lines = string.lines
27
+ lines = multiline_string.lines
27
28
  lines.each do |line|
28
- @logger.debug "#{prefix}#{line.rstrip}"
29
+ write :debug, line.rstrip
29
30
  end
30
31
  end
31
32
 
32
33
  def info(message)
33
- @logger.info message
34
+ write :info, message
34
35
  end
35
36
 
36
37
  def warn(message)
37
- @logger.warn message
38
+ write :warn, message
38
39
  end
39
40
 
40
41
  def error(message)
41
- @logger.error message
42
+ write :error, message
42
43
  end
43
44
 
44
45
  def debug?
@@ -51,16 +52,9 @@ module Kramdown
51
52
 
52
53
  class << self
53
54
  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
55
+ inner = JekyllProvider.jekyll ? JekyllProvider.jekyll.logger : nil
56
+ inner ||= ConsoleLogger.new(level)
57
+ new inner
64
58
  end
65
59
 
66
60
  def level
@@ -79,6 +73,10 @@ module Kramdown
79
73
 
80
74
  private
81
75
 
76
+ def write(level, message)
77
+ @logger.public_send(level, " kramdown-plantuml: #{message}")
78
+ end
79
+
82
80
  def level_from_logger
83
81
  return @logger.level if @logger.respond_to? :level
84
82
 
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'log_wrapper'
4
+
5
+ module Kramdown
6
+ module PlantUml
7
+ # Options for PlantUML processing
8
+ class Options
9
+ attr_reader :theme_name, :theme_directory
10
+
11
+ def initialize(options_hash = {})
12
+ @logger = LogWrapper.init
13
+ @options = massage(options_hash)
14
+ @raise_errors = extract_raise_errors(@options)
15
+ extract_theme_options(@options)
16
+ end
17
+
18
+ def raise_errors?
19
+ @raise_errors
20
+ end
21
+
22
+ def to_h
23
+ @options
24
+ end
25
+
26
+ private
27
+
28
+ def boolean(value, default_value)
29
+ return value if [true, false].include? value
30
+ return default_value if value.nil?
31
+
32
+ s = value.to_s.strip
33
+ return true if %w[true yes 1].select { |v| v.casecmp(s).zero? }.any?
34
+ return false if %w[false no 0].select { |v| v.casecmp(s).zero? }.any?
35
+
36
+ default_value
37
+ end
38
+
39
+ def extract_plantuml_options(options_hash)
40
+ return options_hash[:plantuml] if options_hash.key?(:plantuml)
41
+ return options_hash['plantuml'] if options_hash.key?('plantuml')
42
+
43
+ {}
44
+ end
45
+
46
+ def extract_theme_options(options)
47
+ return if options.empty? || !options.key?(:theme)
48
+
49
+ theme = options[:theme] || {}
50
+
51
+ unless theme.is_a?(Hash)
52
+ @logger.warn ":theme is not a Hash: #{theme}"
53
+ return
54
+ end
55
+
56
+ @theme_name = theme.key?(:name) ? theme[:name] : nil
57
+ @theme_directory = theme.key?(:directory) ? theme[:directory] : nil
58
+ end
59
+
60
+ def extract_raise_errors(options)
61
+ if options.key?(:raise_errors)
62
+ raise_errors = options[:raise_errors]
63
+ return boolean(raise_errors, true)
64
+ end
65
+
66
+ true
67
+ end
68
+
69
+ def massage(options_hash)
70
+ if options_hash.nil? || !options_hash.is_a?(Hash) || options_hash.empty?
71
+ @logger.debug 'No options provided'
72
+ return {}
73
+ end
74
+
75
+ plantuml_options = extract_plantuml_options(options_hash)
76
+ symbolize_keys(plantuml_options)
77
+ end
78
+
79
+ def symbolize_keys(options)
80
+ return options if options.nil? || options.empty?
81
+
82
+ array = options.map do |key, value|
83
+ value = value.is_a?(Hash) ? symbolize_keys(value) : value
84
+ [key.to_sym, value]
85
+ end
86
+
87
+ array.to_h
88
+ end
89
+ end
90
+ end
91
+ end
@@ -1,32 +1,69 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'plantuml_result'
4
+
3
5
  module Kramdown
4
6
  module PlantUml
5
7
  # PlantUML Error
6
8
  class PlantUmlError < StandardError
7
- def initialize(plantuml, stderr, exitcode)
9
+ def initialize(result)
10
+ raise ArgumentError, 'result cannot be nil' if result.nil?
11
+ raise ArgumentError, "result must be a #{PlantUmlResult}" unless result.is_a?(PlantUmlResult)
12
+
13
+ super create_message(result)
14
+ end
15
+
16
+ private
17
+
18
+ def create_message(result)
19
+ header = header(result).gsub("\n", ' ').strip
20
+ plantuml = plantuml(result)
21
+ result = result(result)
8
22
  message = <<~MESSAGE
9
- Conversion of the following PlantUML diagram failed:
23
+ #{header}
10
24
 
11
25
  #{plantuml}
12
26
 
13
- The error received from PlantUML was:
14
-
15
- Exit code: #{exitcode}
16
- #{stderr}
27
+ #{result}
17
28
  MESSAGE
18
29
 
19
- super message
30
+ message.strip
20
31
  end
21
32
 
22
- def self.should_raise?(exitcode, stderr)
23
- return false if exitcode.zero?
33
+ def header(result)
34
+ if theme_not_found?(result) && !result.diagram.nil? && !result.diagram.theme.nil?
35
+ return <<~HEADER
36
+ Conversion of the following PlantUML result failed because the
37
+ theme '#{result.diagram.theme.name}' can't be found in the directory
38
+ '#{result.diagram.theme.directory}':
39
+ HEADER
40
+ end
41
+
42
+ 'Conversion of the following PlantUML result failed:'
43
+ end
44
+
45
+ def theme_not_found?(result)
46
+ !result.nil? \
47
+ && !result.stderr.nil? \
48
+ && result.stderr.include?('NullPointerException') \
49
+ && result.stderr.include?('getTheme')
50
+ end
51
+
52
+ def plantuml(result)
53
+ return nil if result.nil? || result.diagram.nil?
54
+
55
+ result.diagram.plantuml
56
+ end
57
+
58
+ def result(result)
59
+ return nil if result.nil?
60
+
61
+ <<~RESULT
62
+ The error received from PlantUML was:
24
63
 
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:')
64
+ Exit code: #{result.exitcode}
65
+ #{result.stderr}
66
+ RESULT
30
67
  end
31
68
  end
32
69
  end
@@ -1,19 +1,26 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'logger'
3
+ require_relative 'log_wrapper'
4
4
  require_relative 'plantuml_error'
5
+ require_relative 'diagram'
5
6
 
6
7
  module Kramdown
7
8
  module PlantUml
8
9
  # Executes the PlantUML Java application.
9
10
  class PlantUmlResult
10
- attr_reader :stdout, :stderr, :exitcode
11
+ attr_reader :diagram, :stdout, :stderr, :exitcode
11
12
 
12
- def initialize(stdout, stderr, status)
13
+ def initialize(diagram, stdout, stderr, exitcode)
14
+ raise ArgumentError, 'diagram cannot be nil' if diagram.nil?
15
+ raise ArgumentError, "diagram must be a #{Diagram}" unless diagram.is_a?(Diagram)
16
+ raise ArgumentError, 'exitcode cannot be nil' if exitcode.nil?
17
+ raise ArgumentError, "exitcode must be a #{Integer}" unless exitcode.is_a?(Integer)
18
+
19
+ @diagram = diagram
13
20
  @stdout = stdout
14
21
  @stderr = stderr
15
- @exitcode = status.exitstatus
16
- @logger = Logger.init
22
+ @exitcode = exitcode
23
+ @logger = LogWrapper.init
17
24
  end
18
25
 
19
26
  def without_xml_prologue
@@ -37,13 +44,22 @@ module Kramdown
37
44
  @stdout
38
45
  end
39
46
 
40
- def validate(plantuml)
41
- raise PlantUmlError.new(plantuml, @stderr, @exitcode) if PlantUmlError.should_raise?(@exitcode, @stderr)
47
+ def valid?
48
+ return true if @exitcode.zero? || @stderr.nil? || @stderr.empty?
49
+
50
+ # If stderr is not empty, but contains the string 'CoreText note:',
51
+ # the error is caused by a bug in Java, and should be ignored.
52
+ # Circumvents https://bugs.openjdk.java.net/browse/JDK-8244621
53
+ @stderr.include?('CoreText note:')
54
+ end
55
+
56
+ def validate
57
+ raise PlantUmlError, self unless valid?
42
58
 
43
59
  return if @stderr.nil? || @stderr.empty?
44
60
 
45
- @logger.debug ' kramdown-plantuml: PlantUML log:'
46
- @logger.debug_with_prefix ' kramdown-plantuml: ', @stderr
61
+ @logger.debug 'PlantUML log:'
62
+ @logger.debug_multiline @stderr
47
63
  end
48
64
  end
49
65
  end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: false
2
+
3
+ require_relative 'options'
4
+ require_relative 'log_wrapper'
5
+
6
+ module Kramdown
7
+ module PlantUml
8
+ # Provides theming support for PlantUML
9
+ class Theme
10
+ attr_reader :name, :directory
11
+
12
+ def initialize(options)
13
+ raise ArgumentError, 'options cannot be nil' if options.nil?
14
+ raise ArgumentError, "options must be a '#{Options}'." unless options.is_a?(Options)
15
+
16
+ @logger = LogWrapper.init
17
+ @name = options.theme_name
18
+ @directory = options.theme_directory
19
+ end
20
+
21
+ def apply(plantuml)
22
+ if plantuml.nil? || !plantuml.is_a?(String) || plantuml.empty?
23
+ @logger.debug 'Empty diagram or not a String.'
24
+ return plantuml
25
+ end
26
+
27
+ if @name.nil? || @name.empty?
28
+ @logger.debug 'No theme to apply.'
29
+ return plantuml.strip
30
+ end
31
+
32
+ theme(plantuml)
33
+ end
34
+
35
+ private
36
+
37
+ def theme(plantuml)
38
+ startuml = '@startuml'
39
+ startuml_index = plantuml.index(startuml) + startuml.length
40
+
41
+ return plantuml if startuml_index.nil?
42
+
43
+ theme_string = "\n!theme #{@name}"
44
+ theme_string << " from #{@directory}" unless @directory.nil?
45
+
46
+ @logger.debug "Applying #{theme_string.strip}"
47
+
48
+ /@startuml.*/.match(plantuml) do |match|
49
+ return plantuml.insert match.end(0), theme_string
50
+ end
51
+
52
+ plantuml.strip
53
+ end
54
+ end
55
+ end
56
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Kramdown
4
4
  module PlantUml
5
- VERSION = '1.1.3'
5
+ VERSION = '1.1.7'
6
6
  end
7
7
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Wraps the `which` Unix utility
3
+ # Mimics the `which` Unix utility
4
4
  class Which
5
5
  def self.which(cmd)
6
6
  exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
@@ -10,6 +10,7 @@ class Which
10
10
  return exe if File.executable?(exe) && !File.directory?(exe)
11
11
  end
12
12
  end
13
+
13
14
  nil
14
15
  end
15
16
  end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'kramdown-plantuml/version'
4
- require_relative 'kramdown-plantuml/converter'
5
3
  require_relative 'kramdown_html'
4
+ require_relative 'kramdown-plantuml/jekyll_provider'
5
+
6
+ ::Kramdown::PlantUml::JekyllProvider.install
data/lib/kramdown_html.rb CHANGED
@@ -2,9 +2,11 @@
2
2
 
3
3
  require 'kramdown'
4
4
  require 'kramdown-parser-gfm'
5
- require_relative 'kramdown-plantuml/converter'
6
- require_relative 'kramdown-plantuml/logger'
5
+ require_relative 'kramdown-plantuml/log_wrapper'
7
6
  require_relative 'kramdown-plantuml/plantuml_error'
7
+ require_relative 'kramdown-plantuml/options'
8
+ require_relative 'kramdown-plantuml/diagram'
9
+ require_relative 'kramdown-plantuml/jekyll_provider'
8
10
 
9
11
  module Kramdown
10
12
  module Converter
@@ -14,13 +16,31 @@ module Kramdown
14
16
  alias super_convert_codeblock convert_codeblock
15
17
 
16
18
  def convert_codeblock(element, indent)
17
- return super_convert_codeblock(element, indent) if element.attr['class'] != 'language-plantuml'
19
+ return super_convert_codeblock(element, indent) unless plantuml?(element)
18
20
 
19
- plantuml = element.value
20
- plantuml_options = @options.key?(:plantuml) ? @options[:plantuml] : {}
21
- converter = ::Kramdown::PlantUml::Converter.new(plantuml_options || {})
21
+ jekyll = ::Kramdown::PlantUml::JekyllProvider
22
22
 
23
- converter.convert_plantuml_to_svg(plantuml)
23
+ # If Jekyll is successfully loaded, we'll wait with converting the
24
+ # PlantUML diagram to SVG since a theme may be configured that needs to
25
+ # be copied to the assets directory before the PlantUML conversion can
26
+ # be performed. We therefore place a needle in the haystack that we will
27
+ # convert in the :site:pre_render hook.
28
+ options = ::Kramdown::PlantUml::Options.new(@options)
29
+ return jekyll.needle(element.value, options) if jekyll.installed?
30
+
31
+ convert_plantuml(element.value)
32
+ end
33
+
34
+ private
35
+
36
+ def plantuml?(element)
37
+ element.attr['class'] == 'language-plantuml'
38
+ end
39
+
40
+ def convert_plantuml(plantuml)
41
+ options = ::Kramdown::PlantUml::Options.new(@options)
42
+ diagram = ::Kramdown::PlantUml::Diagram.new(plantuml, options)
43
+ diagram.convert_to_svg
24
44
  end
25
45
  end
26
46
  end
data/pom.xml CHANGED
@@ -10,7 +10,7 @@
10
10
  <dependency>
11
11
  <groupId>net.sourceforge.plantuml</groupId>
12
12
  <artifactId>plantuml</artifactId>
13
- <version>1.2021.9</version>
13
+ <version>1.2021.12</version>
14
14
  </dependency>
15
15
  </dependencies>
16
16
  </project>
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kramdown-plantuml
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.3
4
+ version: 1.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Swedbank Pay
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-08-04 00:00:00.000000000 Z
11
+ date: 2021-11-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: kramdown
@@ -166,20 +166,22 @@ files:
166
166
  - LICENSE
167
167
  - README.md
168
168
  - Rakefile
169
- - bin/net/sourceforge/plantuml/plantuml/1.2021.8/plantuml-1.2021.8.jar
169
+ - bin/net/sourceforge/plantuml/plantuml/1.2021.12/plantuml-1.2021.12.jar
170
170
  - kramdown-plantuml.gemspec
171
171
  - lib/kramdown-plantuml.rb
172
172
  - lib/kramdown-plantuml/bool_env.rb
173
173
  - lib/kramdown-plantuml/console_logger.rb
174
- - lib/kramdown-plantuml/converter.rb
174
+ - lib/kramdown-plantuml/diagram.rb
175
175
  - lib/kramdown-plantuml/executor.rb
176
- - lib/kramdown-plantuml/logger.rb
176
+ - lib/kramdown-plantuml/jekyll_provider.rb
177
+ - lib/kramdown-plantuml/log_wrapper.rb
178
+ - lib/kramdown-plantuml/options.rb
177
179
  - lib/kramdown-plantuml/plantuml_error.rb
178
180
  - lib/kramdown-plantuml/plantuml_result.rb
179
- - lib/kramdown-plantuml/themer.rb
181
+ - lib/kramdown-plantuml/theme.rb
180
182
  - lib/kramdown-plantuml/version.rb
183
+ - lib/kramdown-plantuml/which.rb
181
184
  - lib/kramdown_html.rb
182
- - lib/which.rb
183
185
  - pom.xml
184
186
  homepage: https://github.com/SwedbankPay/kramdown-plantuml
185
187
  licenses:
@@ -1,52 +0,0 @@
1
- # frozen_string_literal: true
2
-
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
17
- end
18
-
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)
32
- end
33
-
34
- private
35
-
36
- def wrap(svg)
37
- theme_class = @themer.theme_name ? "theme-#{@themer.theme_name}" : ''
38
- class_name = "plantuml #{theme_class}".strip
39
-
40
- wrapper_element_start = "<div class=\"#{class_name}\">"
41
- wrapper_element_end = '</div>'
42
-
43
- "#{wrapper_element_start}#{svg}#{wrapper_element_end}"
44
- end
45
-
46
- def log(plantuml)
47
- @logger.debug ' kramdown-plantuml: PlantUML converting diagram:'
48
- @logger.debug_with_prefix ' kramdown-plantuml: ', plantuml
49
- end
50
- end
51
- end
52
- end
@@ -1,76 +0,0 @@
1
- # frozen_string_literal: false
2
-
3
- require_relative 'logger'
4
-
5
- module Kramdown
6
- module PlantUml
7
- # Provides theming support for PlantUML
8
- class Themer
9
- attr_reader :theme_name, :theme_directory
10
-
11
- def initialize(options = {})
12
- @logger = Logger.init
13
- @theme_name, @theme_directory = theme_options(options)
14
- end
15
-
16
- def apply_theme(plantuml)
17
- if plantuml.nil? || plantuml.empty?
18
- @logger.debug ' kramdown-plantuml: Empty diagram.'
19
- return plantuml
20
- end
21
-
22
- if @theme_name.nil? || @theme_name.empty?
23
- @logger.debug ' kramdown-plantuml: No theme to apply.'
24
- return plantuml
25
- end
26
-
27
- theme(plantuml)
28
- end
29
-
30
- private
31
-
32
- def theme_options(options)
33
- options = symbolize_keys(options)
34
-
35
- @logger.debug " kramdown-plantuml: Options: #{options}"
36
-
37
- return nil if options.nil? || !options.key?(:theme)
38
-
39
- theme = options[:theme] || {}
40
- theme_name = theme.key?(:name) ? theme[:name] : nil
41
- theme_directory = theme.key?(:directory) ? theme[:directory] : nil
42
-
43
- [theme_name, theme_directory]
44
- end
45
-
46
- def symbolize_keys(options)
47
- return options if options.nil?
48
-
49
- array = options.map do |key, value|
50
- value = value.is_a?(Hash) ? symbolize_keys(value) : value
51
- [key.to_sym, value]
52
- end
53
-
54
- array.to_h
55
- end
56
-
57
- def theme(plantuml)
58
- startuml = '@startuml'
59
- startuml_index = plantuml.index(startuml) + startuml.length
60
-
61
- return plantuml if startuml_index.nil?
62
-
63
- theme_string = "\n!theme #{@theme_name}"
64
- theme_string << " from #{@theme_directory}" unless @theme_directory.nil?
65
-
66
- @logger.debug " kramdown-plantuml: Applying #{theme_string.strip}"
67
-
68
- /@startuml.*/.match(plantuml) do |match|
69
- return plantuml.insert match.end(0), theme_string
70
- end
71
-
72
- plantuml
73
- end
74
- end
75
- end
76
- end