jekyll_remote_plantuml_plugin 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 967fc61058c4df183be6629dda3ec094fc315e902fc28b20174136537abe495a
4
+ data.tar.gz: 8dea1992278c76251aa93fae9bf98d86ca7c0988bab2bd907e4cce8d1208c2e3
5
+ SHA512:
6
+ metadata.gz: 85bcc911939780f5c058f1a27571bf9f169cf6c33722c483670f80eb2c50789fad22f5beec5775dad04be24f557aef74930e84d4729a93577215b14e8c901383
7
+ data.tar.gz: f1c2e0808ecb7a53d60031231cf57f36541f9b65e45d2de1da361093e0822bfef7b276f4b4c717212918ddd373ebf97569f517b66f3e60b97bbd883f11984b30
@@ -0,0 +1,5 @@
1
+ require_relative "jekyll_remote_plantuml_plugin/utils"
2
+ require_relative "jekyll_remote_plantuml_plugin/jekyll_remote_plantuml_plugin"
3
+ require_relative "jekyll_remote_plantuml_plugin/version"
4
+
5
+ Liquid::Template.register_tag("plantuml", JekyllRemotePlantUMLPlugin::Block)
@@ -0,0 +1,145 @@
1
+ require "liquid"
2
+ require "digest"
3
+
4
+ module JekyllRemotePlantUMLPlugin
5
+ class Block < Liquid::Block
6
+ include Utils::Common
7
+ include Utils::PlantUML
8
+ include Utils::Encode
9
+
10
+ FORMATS = %w[png svg].freeze
11
+ CONFIG_OPTIONS = %i[
12
+ provider
13
+ format
14
+ save_images_locally cache_dir
15
+ div_class div_style
16
+ img_class img_style img_id img_width img_height img_alt
17
+ ].freeze
18
+ TAG_OPTIONS = CONFIG_OPTIONS.dup.tap do |h|
19
+ %i[provider save_images_locally cache_dir].each do |k|
20
+ h.delete(k)
21
+ end
22
+ end.freeze
23
+ DEFAULT_CONFIG_OPTIONS = {
24
+ provider: "http://www.plantuml.com/plantuml",
25
+ format: "svg",
26
+ save_images_locally: false,
27
+ cache_dir: "plantuml",
28
+ div_class: "plantuml",
29
+ img_class: "plantuml"
30
+ }.freeze
31
+
32
+ PARAMS_SYNTAX = /
33
+ ([\w-]+)\s*=\s*
34
+ (?:"([^"\\]*(?:\\.[^"\\]*)*)"|'([^'\\]*(?:\\.[^'\\]*)*)'|([\w.-]+))
35
+ /x.freeze
36
+
37
+ def initialize(tag_name, markup, _)
38
+ super
39
+ @markup = markup.strip
40
+ end
41
+
42
+ def render(context)
43
+ content = super(context).strip
44
+ options = tag_options(context)
45
+
46
+ check_format(options[:format])
47
+
48
+ url = generate_url(options[:provider], encode(content), options[:format])
49
+ img_src_attr = options[:save_images_locally] ? img_local_src(context, content, url, options) : url
50
+ prepare_html(img_src_attr, options)
51
+ end
52
+
53
+ private
54
+
55
+ def tag_options(context)
56
+ tag_options = parse_params(context)
57
+
58
+ # delete unsupported options
59
+ tag_options.each { |key, _| tag_options.delete(key) unless TAG_OPTIONS.include?(key) }
60
+
61
+ # merge with config options
62
+ configuration_options.merge(tag_options)
63
+ end
64
+
65
+ # rubocop:disable Metrics/MethodLength
66
+ def parse_params(context)
67
+ {}.tap do |params|
68
+ @markup.scan(PARAMS_SYNTAX) do |key, d_quoted, s_quoted, variable|
69
+ params[key] = if d_quoted
70
+ d_quoted.include?('\\"') ? d_quoted.gsub('\\"', '"') : d_quoted
71
+ elsif s_quoted
72
+ s_quoted.include?("\\'") ? s_quoted.gsub("\\'", "'") : s_quoted
73
+ elsif variable
74
+ context[variable]
75
+ end
76
+ end
77
+ end.transform_keys(&:to_sym)
78
+ end
79
+ # rubocop:enable Metrics/MethodLength
80
+
81
+ def configuration_options
82
+ @configuration_options ||= Jekyll.configuration({})["plantuml"].transform_keys(&:to_sym).tap do |conf|
83
+ # delete unsupported options
84
+ conf.each { |key, _| conf.delete(key) unless CONFIG_OPTIONS.include?(key) }
85
+
86
+ # set defaults
87
+ DEFAULT_CONFIG_OPTIONS.each { |key, value| conf[key] = value if conf[key].nil? }
88
+ end
89
+ end
90
+
91
+ def img_local_src(context, content, url, options)
92
+ # prepare source image path
93
+ site = context.registers[:site]
94
+ image_basename = "#{Digest::SHA1.hexdigest encode(content)}.#{options[:format]}"
95
+ source_image_path = File.join(site.source, options[:cache_dir], image_basename)
96
+
97
+ unless File.exist?(source_image_path)
98
+ begin
99
+ download_image(url, source_image_path)
100
+ rescue StandardError => e
101
+ raise <<~TEXT
102
+ The download of the PlantUml diagram image failed: #{e}
103
+
104
+ === CONTENT START
105
+ #{content}
106
+ === CONTENT END
107
+
108
+ URL: #{url}
109
+ TEXT
110
+ end
111
+
112
+ # make the image available in the destination directory
113
+ site.static_files << Jekyll::StaticFile.new(site, site.source, options[:cache_dir], image_basename)
114
+ end
115
+
116
+ "/#{join_paths(site.baseurl, options[:cache_dir], image_basename)}"
117
+ end
118
+
119
+ def check_format(format)
120
+ raise "Invalid PlantUML diagram format \"#{format}\"" unless FORMATS.include?(format)
121
+ end
122
+
123
+ def prepare_html(img_src_attr, options)
124
+ div_tag = ""
125
+ div_tag += "<div#{prepare_optional_attrs_content("div_", options)}>"
126
+ img_tag = "<img src=\"#{img_src_attr}\"#{prepare_optional_attrs_content("img_", options)} />"
127
+ div_tag += "\n #{img_tag}\n"
128
+ "#{div_tag}</div>"
129
+ end
130
+
131
+ def prepare_optional_attrs_content(prefix, options)
132
+ result = ""
133
+ TAG_OPTIONS.each do |key|
134
+ next if !key.to_s.start_with?(prefix) || options[key].nil? || options[key].empty?
135
+
136
+ attribute_name = key.to_s.reverse.chomp(prefix.reverse).reverse
137
+ attribute_value = options[key]
138
+
139
+ result += " #{attribute_name}=\"#{attribute_value}\""
140
+ end
141
+
142
+ result
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,93 @@
1
+ require "open-uri"
2
+ require "zlib"
3
+
4
+ module JekyllRemotePlantUMLPlugin
5
+ module Utils
6
+ module Common
7
+ def download_image(url, dest_path)
8
+ dest_dir = File.dirname(dest_path)
9
+ FileUtils.mkdir_p(dest_dir) unless File.directory?(dest_dir)
10
+
11
+ uri = URI.parse(url)
12
+ uri.open do |f|
13
+ File.open(dest_path, "wb") do |file|
14
+ file << f.read
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ module Encode
21
+ def encode(content)
22
+ encoded = content.force_encoding("utf-8")
23
+ encoded = Zlib::Deflate.new(nil, -Zlib::MAX_WBITS).deflate(encoded, Zlib::FINISH)
24
+ encode64(encoded)
25
+ end
26
+
27
+ def encode64(content)
28
+ length = content.length
29
+ ind = 0
30
+ out = ""
31
+
32
+ while ind < length
33
+ i1 = ind + 1 < length ? content[ind + 1].ord : 0
34
+ i2 = ind + 2 < length ? content[ind + 2].ord : 0
35
+ out += append3bytes(content[ind].ord, i1, i2)
36
+ ind += 3
37
+ end
38
+
39
+ out
40
+ end
41
+
42
+ # rubocop:disable Metrics/AbcSize
43
+ def append3bytes(bit1, bit2, bit3)
44
+ c1 = bit1 >> 2
45
+ c2 = ((bit1 & 0x3) << 4) | (bit2 >> 4)
46
+ c3 = ((bit2 & 0xF) << 2) | (bit3 >> 6)
47
+ c4 = bit3 & 0x3F
48
+ encode6bit(c1 & 0x3F).chr +
49
+ encode6bit(c2 & 0x3F).chr +
50
+ encode6bit(c3 & 0x3F).chr +
51
+ encode6bit(c4 & 0x3F).chr
52
+ end
53
+ # rubocop:enable Metrics/AbcSize
54
+
55
+ # rubocop:disable Naming/MethodParameterName
56
+ def encode6bit(b)
57
+ return (48 + b).chr if b < 10
58
+
59
+ b -= 10
60
+ return (65 + b).chr if b < 26
61
+
62
+ b -= 26
63
+ return (97 + b).chr if b < 26
64
+
65
+ b -= 26
66
+ return "-" if b.zero?
67
+
68
+ b == 1 ? "_" : "?"
69
+ end
70
+ # rubocop:enable Naming/MethodParameterName
71
+ end
72
+
73
+ module PlantUML
74
+ def generate_url(provider, encoded_content, format)
75
+ join_paths(provider, format, encoded_content).to_s
76
+ end
77
+
78
+ def join_paths(*paths, separator: "/")
79
+ paths = paths.compact.reject(&:empty?)
80
+ last = paths.length - 1
81
+ paths.each_with_index.map do |path, index|
82
+ expand_path(path, index, last, separator)
83
+ end.join
84
+ end
85
+
86
+ def expand_path(path, current, last, separator)
87
+ path = path[1..] if path.start_with?(separator) && current.zero?
88
+ path = [path, separator] unless path.end_with?(separator) || current == last
89
+ path
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,3 @@
1
+ module JekyllRemotePlantUMLPlugin
2
+ VERSION = "0.1.0".freeze
3
+ end
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jekyll_remote_plantuml_plugin
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Alexey Igrychev
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-06-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: jekyll
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.9'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.9'
27
+ - !ruby/object:Gem::Dependency
28
+ name: liquid
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '4.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '4.0'
41
+ description:
42
+ email:
43
+ - alexey.igrychev@flant.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - lib/jekyll_remote_plantuml_plugin.rb
49
+ - lib/jekyll_remote_plantuml_plugin/jekyll_remote_plantuml_plugin.rb
50
+ - lib/jekyll_remote_plantuml_plugin/utils.rb
51
+ - lib/jekyll_remote_plantuml_plugin/version.rb
52
+ homepage: https://github.com/flant/jekyll_remote_plantuml_plugin
53
+ licenses:
54
+ - MIT
55
+ metadata:
56
+ homepage_uri: https://github.com/flant/jekyll_remote_plantuml_plugin
57
+ source_code_uri: https://github.com/flant/jekyll_remote_plantuml_plugin
58
+ post_install_message:
59
+ rdoc_options: []
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: 2.6.3
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ requirements: []
73
+ rubygems_version: 3.1.2
74
+ signing_key:
75
+ specification_version: 4
76
+ summary: Jekyll plugin that allows including local/remote PlantUML diagrams into your
77
+ pages, works only with an external PlantUML server (http://www.plantuml.com/plantuml
78
+ by default) — PlantUML jar installed locally not required.
79
+ test_files: []