asciidoctor-plantuml-0.0.16/ 0000755 0001751 0001751 00000000000 14322750275 014770 5 ustar pravi pravi asciidoctor-plantuml-0.0.16/lib/ 0000755 0001751 0001751 00000000000 14322750275 015536 5 ustar pravi pravi asciidoctor-plantuml-0.0.16/lib/asciidoctor-plantuml.rb 0000644 0001751 0001751 00000000351 14322750275 022217 0 ustar pravi pravi # frozen_string_literal: true
require 'asciidoctor'
require 'asciidoctor/extensions'
require_relative 'asciidoctor_plantuml/plantuml'
Asciidoctor::Extensions.register do
block Asciidoctor::PlantUml::BlockProcessor, :plantuml
end
asciidoctor-plantuml-0.0.16/lib/asciidoctor_plantuml/ 0000755 0001751 0001751 00000000000 14322750275 021755 5 ustar pravi pravi asciidoctor-plantuml-0.0.16/lib/asciidoctor_plantuml/plantuml.rb 0000644 0001751 0001751 00000021143 14322750275 024137 0 ustar pravi pravi # frozen_string_literal: true
require 'uri'
require 'open-uri'
require 'zlib'
require 'net/http'
module Asciidoctor
# PlantUML Module
module PlantUml
# PlantUML Configuration
class Configuration
DEFAULT_URL = ENV.fetch('PLANTUML_URL', '')
DEFAULT_ENCODING = ENV.fetch('PLANTUML_ENCODING', 'legacy')
attr_accessor :url, :txt_enable, :svg_enable, :png_enable, :encoding
def initialize
@url = DEFAULT_URL
@txt_enable = true
@svg_enable = true
@png_enable = true
@encoding = DEFAULT_ENCODING
end
end
class << self
attr_writer :configuration
end
def self.configuration
@configuration ||= Configuration.new
end
def self.configure
yield(configuration)
end
# PlantUML Processor
class Processor
FORMATS = %w[png svg txt].freeze
DEFAULT_FORMAT = FORMATS[0]
ENCODINGS = %w[legacy deflate].freeze
DEFAULT_ENCODING = ENCODINGS[0]
ENCODINGS_MAGIC_STRINGS_MAP = Hash.new('')
ENCODINGS_MAGIC_STRINGS_MAP['deflate'] = '~1'
URI_SCHEMES_REGEXP = ::URI::DEFAULT_PARSER.make_regexp(%w[http https])
class << self
def valid_format?(format)
FORMATS.include?(format)
end
def valid_encoding?(encoding)
ENCODINGS.include?(encoding)
end
def server_url
PlantUml.configuration.url
end
def txt_enabled?
PlantUml.configuration.txt_enable
end
def png_enabled?
PlantUml.configuration.png_enable
end
def svg_enabled?
PlantUml.configuration.svg_enable
end
def enabled?
txt_enabled? || png_enabled? || svg_enabled?
end
def plantuml_content_format(code, format, attrs = {})
if %w[png svg txt].include?(format) &&
method("#{format}_enabled?").call
method("plantuml_#{format}_content").call(code, format, attrs)
else
plantuml_invalid_content(format, attrs)
end
end
def plantuml_content(code, attrs = {})
format = attrs['format'] || DEFAULT_FORMAT
return plantuml_disabled_content(code, attrs) unless enabled?
return plantuml_server_unavailable_content(server_url, attrs) unless valid_uri?(server_url)
plantuml_content_format(code, format, attrs)
end
# Compression code used to generate PlantUML URLs. Taken directly from
# the transcoder class in the PlantUML java code.
def gen_url(text, format)
result = ''
result += encoding_magic_prefix
compressed_data = Zlib::Deflate.deflate(text)
compressed_data.chars.each_slice(3) do |bytes|
# print bytes[0], ' ' , bytes[1] , ' ' , bytes[2]
b1 = bytes[0].nil? ? 0 : (bytes[0].ord & 0xFF)
b2 = bytes[1].nil? ? 0 : (bytes[1].ord & 0xFF)
b3 = bytes[2].nil? ? 0 : (bytes[2].ord & 0xFF)
result += append3bytes(b1, b2, b3)
end
join_paths(server_url, "#{format}/", result).to_s
end
private
def plantuml_txt_content(code, format, attrs = {})
url = gen_url(code, format)
URI(url).open do |f|
plantuml_ascii_content(f.read, attrs)
end
rescue OpenURI::HTTPError, Errno::ECONNREFUSED, SocketError
plantuml_png_content(code, format, attrs)
end
def plantuml_ascii_content(code, attrs = {})
content = '
'
content += '
'
content += '
\n'
content += code
content += '
'
content += '
'
content + '
'
end
def plantuml_png_content(code, format, attrs = {})
content = ''
content += '
'
content += '
![]()
"
content += '
'
content + '
'
end
def plantuml_svg_content(code, format, attrs = {})
content = ''
content += '
'
content += ''
content += '
'
content + '
'
end
def plantuml_invalid_content(format, attrs = {})
error = "PlantUML Error: Invalid format \"#{format}\""
_plantuml_error_content(error, attrs)
end
def plantuml_server_unavailable_content(url, attrs = {})
error = "Error: cannot connect to PlantUML server at \"#{url}\""
_plantuml_error_content(error, attrs)
end
def plantuml_disabled_content(code, attrs = {})
_plantuml_error_content(code, attrs)
end
def _plantuml_error_content(error, attrs = {})
content = ''
content += '
'
content += '
\n'
content += error
content += '
'
content += '
'
content + '
'
end
def encode6bit(bit)
return ('0'.ord + bit).chr if bit < 10
bit -= 10
return ('A'.ord + bit).chr if bit < 26
bit -= 26
return ('a'.ord + bit).chr if bit < 26
bit -= 26
return '-' if bit.zero?
return '_' if bit == 1
'?'
end
def append3bytes(bit1, bit2, bit3)
c1 = bit1 >> 2
c2 = ((bit1 & 0x3) << 4) | (bit2 >> 4)
c3 = ((bit2 & 0xF) << 2) | (bit3 >> 6)
c4 = bit3 & 0x3F
encode6bit(c1 & 0x3F).chr +
encode6bit(c2 & 0x3F).chr +
encode6bit(c3 & 0x3F).chr +
encode6bit(c4 & 0x3F).chr
end
def encoding_magic_prefix
ENCODINGS_MAGIC_STRINGS_MAP[PlantUml.configuration.encoding]
end
# Make a call to the PlantUML server with the simplest diagram possible
# to check if the server is available or not.
def check_server(check_url)
response = Net::HTTP.get_response(URI(check_url))
response.is_a?(Net::HTTPSuccess)
rescue OpenURI::HTTPError, Errno::ECONNREFUSED, SocketError
false
end
def valid_uri?(uri)
!(uri =~ /\A#{URI_SCHEMES_REGEXP}\z/).nil?
end
def join_paths(*paths, separator: '/')
paths = paths.compact.reject(&:empty?)
last = paths.length - 1
paths.each_with_index.map do |path, index|
expand_path(path, index, last, separator)
end.join
end
def expand_path(path, current, last, separator)
path = path[1..] if path.start_with?(separator) && current.zero?
path = [path, separator] unless path.end_with?(separator) || current == last
path
end
end
end
# PlantUML BlockProcessor
class BlockProcessor < Asciidoctor::Extensions::BlockProcessor
use_dsl
named :plantuml
on_context :listing, :literal
content_model :simple
def process(parent, target, attrs)
lines = target.lines
lines = ['@startuml'] + target.lines unless target.lines[0] =~ /@startuml/
lines += ['@enduml'] unless target.lines[-1] =~ /@enduml/
content = Processor.plantuml_content(lines.join("\n"), attrs)
create_plantuml_block(parent, content, attrs)
end
private
def create_plantuml_block(parent, content, attrs)
Asciidoctor::Block.new parent, :pass, {
content_model: :raw,
source: content,
subs: :default
}.merge(attrs)
end
end
end
end
asciidoctor-plantuml-0.0.16/lib/asciidoctor_plantuml/version.rb 0000644 0001751 0001751 00000000145 14322750275 023767 0 ustar pravi pravi # frozen_string_literal: true
module Asciidoctor
module PlantUML
VERSION = '0.0.16'
end
end
asciidoctor-plantuml-0.0.16/asciidoctor-plantuml.gemspec 0000644 0001751 0001751 00000004126 14322750275 022475 0 ustar pravi pravi #########################################################
# This file has been automatically generated by gem2tgz #
#########################################################
# -*- encoding: utf-8 -*-
# stub: asciidoctor-plantuml 0.0.16 ruby lib
Gem::Specification.new do |s|
s.name = "asciidoctor-plantuml".freeze
s.version = "0.0.16"
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
s.metadata = { "rubygems_mfa_required" => "true" } if s.respond_to? :metadata=
s.require_paths = ["lib".freeze]
s.authors = ["Horacio Sanson".freeze]
s.date = "2022-04-30"
s.description = "Asciidoctor PlantUML extension".freeze
s.email = ["hsanson@gmail.com".freeze]
s.files = ["lib/asciidoctor-plantuml.rb".freeze, "lib/asciidoctor_plantuml/plantuml.rb".freeze, "lib/asciidoctor_plantuml/version.rb".freeze, "test/test_plantuml.rb".freeze]
s.homepage = "https://github.com/hsanson/asciidoctor-plantuml".freeze
s.licenses = ["MIT".freeze]
s.required_ruby_version = Gem::Requirement.new(">= 2.6".freeze)
s.rubygems_version = "3.3.15".freeze
s.summary = "Asciidoctor support for PlantUML diagrams.".freeze
s.test_files = ["test/test_plantuml.rb".freeze]
if s.respond_to? :specification_version then
s.specification_version = 4
end
if s.respond_to? :add_runtime_dependency then
s.add_runtime_dependency(%q.freeze, [">= 2.0.17", "< 3.0.0"])
s.add_development_dependency(%q.freeze, ["~> 2.2"])
s.add_development_dependency(%q.freeze, ["~> 1.13.4"])
s.add_development_dependency(%q.freeze, ["~> 13.0"])
s.add_development_dependency(%q.freeze, ["~> 1.28"])
s.add_development_dependency(%q.freeze, ["~> 3.5"])
else
s.add_dependency(%q.freeze, [">= 2.0.17", "< 3.0.0"])
s.add_dependency(%q.freeze, ["~> 2.2"])
s.add_dependency(%q.freeze, ["~> 1.13.4"])
s.add_dependency(%q.freeze, ["~> 13.0"])
s.add_dependency(%q.freeze, ["~> 1.28"])
s.add_dependency(%q.freeze, ["~> 3.5"])
end
end
asciidoctor-plantuml-0.0.16/test/ 0000755 0001751 0001751 00000000000 14322750275 015747 5 ustar pravi pravi asciidoctor-plantuml-0.0.16/test/test_plantuml.rb 0000644 0001751 0001751 00000024663 14322750275 021202 0 ustar pravi pravi # frozen_string_literal: true
require 'test/unit'
require 'asciidoctor'
require 'stringio'
require 'nokogiri'
require 'asciidoctor-plantuml'
DOC_BASIC = <<~ENDOFSTRING
= Hello PlantUML!
[plantuml, format="png"]
.Title Of this
----
User -> (Start)
User --> (Use the application) : Label
----
ENDOFSTRING
DOC_BASIC_LITERAL = <<~ENDOFSTRING
= Hello PlantUML!
[plantuml, format="png"]
.Title Of this
....
User -> (Start)
User --> (Use the application) : Label
....
ENDOFSTRING
DOC_BASIC2 = <<~ENDOFSTRING
= Hello PlantUML!
[plantuml, format="png"]
.Title Of this
[[fig-xref]]
----
@startuml
User -> (Start)
User --> (Use the application) : Label
@enduml
----
ENDOFSTRING
DOC_BASIC2_LITERAL = <<~ENDOFSTRING
= Hello PlantUML!
[plantuml, format="png"]
.Title Of this
[[fig-xref]]
....
@startuml
User -> (Start)
User --> (Use the application) : Label
@enduml
....
ENDOFSTRING
DOC_BASIC3 = <<~ENDOFSTRING
= Hello Compound PlantUML!
[plantuml, format="png"]
----
[COMP1]
[COMP2]
[COMP1] -> [COMP2]
[COMP2] --> [COMP3]
----
ENDOFSTRING
DOC_BASIC3_LITERAL = <<~ENDOFSTRING
= Hello Compound PlantUML!
[plantuml, format="png"]
....
[COMP1]
[COMP2]
[COMP1] -> [COMP2]
[COMP2] --> [COMP3]
....
ENDOFSTRING
DOC_ID = <<~ENDOFSTRING
= Hello PlantUML!
[plantuml, format="png", id="myId"]
----
User -> (Start)
User --> (Use the application) : Label
----
ENDOFSTRING
DOC_DIM = <<~ENDOFSTRING
= Hello PlantUML!
[plantuml, format="png", width="100px", height="50px"]
----
User -> (Start)
User --> (Use the application) : Label
----
ENDOFSTRING
DOC_ALT = <<~ENDOFSTRING
= Hello PlantUML!
[plantuml, format="png", alt="alt"]
----
User -> (Start)
User --> (Use the application) : Label
----
ENDOFSTRING
DOC_BAD_FORMAT = <<~ENDOFSTRING
= Hello PlantUML!
[plantuml, format="jpg"]
----
User -> (Start)
User --> (Use the application) : Label
----
ENDOFSTRING
DOC_MULTI = <<~ENDOFSTRING
= Hello PlantUML!
[plantuml, format="png"]
----
User -> (Start)
User --> (Use the application) : Label
----
[plantuml, format="png"]
----
User -> (Start)
User --> (Use the application) : Label
----
[plantuml, format="txt"]
----
User -> (Start)
User --> (Use the application) : Label
----
ENDOFSTRING
DOC_MULTI_LITERAL = <<~ENDOFSTRING
= Hello PlantUML!
[plantuml, format="png"]
....
User -> (Start)
User --> (Use the application) : Label
....
[plantuml, format="png"]
....
User -> (Start)
User --> (Use the application) : Label
....
[plantuml, format="txt"]
....
User -> (Start)
User --> (Use the application) : Label
....
ENDOFSTRING
DOC_TXT = <<~ENDOFSTRING
= Hello PlantUML!
[plantuml, format="txt"]
----
User -> (Start)
User --> (Use the application) : Label
----
ENDOFSTRING
DOC_SVG = <<~ENDOFSTRING
= Hello PlantUML!
[plantuml, format="svg"]
----
User -> (Start)
User --> (Use the application) : Label
----
ENDOFSTRING
class PlantUmlTest < Test::Unit::TestCase
GENURL = 'http://localhost:8080/plantuml/png/U9npA2v9B2efpStX2YrEBLBGjLFG20Q9Q4Bv804WIw4a8rKXiQ0W9pCviIGpFqzJmKh19p4fDOVB8JKl1QWT05kd5wq0'
GENURL2 = 'http://localhost:8080/plantuml/png/U9npA2v9B2efpStXYdRszmqmZ8NGHh4mleAkdGAAa15G22Pc7Clba9gN0jGE00W75Cm0'
GENURL_ENCODING = 'http://localhost:8080/plantuml/png/~1U9npA2v9B2efpStX2YrEBLBGjLFG20Q9Q4Bv804WIw4a8rKXiQ0W9pCviIGpFqzJmKh19p4fDOVB8JKl1QWT05kd5wq0'
SVGGENURL = 'http://localhost:8080/plantuml/svg/~1U9npA2v9B2efpStX2YrEBLBGjLFG20Q9Q4Bv804WIw4a8rKXiQ0W9pCviIGpFqzJmKh19p4fDOVB8JKl1QWT05kd5wq0'
def setup
Asciidoctor::PlantUml.configure do |c|
c.url = 'http://localhost:8080/plantuml'
c.txt_enable = true
c.png_enable = true
c.svg_enable = true
end
end
def test_plantuml_block_processor
html = ::Asciidoctor.convert(StringIO.new(DOC_BASIC), backend: 'html5')
page = Nokogiri::HTML(html)
elements = page.css('img.plantuml')
assert_equal elements.size, 1
element = elements.first
assert_equal GENURL, element['src']
end
def test_plantuml_block_literal_processor
html = ::Asciidoctor.convert(
StringIO.new(DOC_BASIC_LITERAL), backend: 'html5'
)
page = Nokogiri::HTML(html)
elements = page.css('img.plantuml')
assert_equal elements.size, 1
element = elements.first
assert_equal GENURL, element['src']
end
def test_plantuml_block_processor2
html = ::Asciidoctor.convert(
StringIO.new(DOC_BASIC2), backend: 'html5'
)
page = Nokogiri::HTML(html)
elements = page.css('img.plantuml')
assert_equal elements.size, 1
element = elements.first
assert_equal GENURL, element['src']
end
def test_plantuml_block_literal_processor2
html = ::Asciidoctor.convert(
StringIO.new(DOC_BASIC2_LITERAL), backend: 'html5'
)
page = Nokogiri::HTML(html)
elements = page.css('img.plantuml')
assert_equal elements.size, 1
element = elements.first
assert_equal GENURL, element['src']
end
def test_plantuml_block_processor3
html = ::Asciidoctor.convert(StringIO.new(DOC_BASIC3), backend: 'html5')
page = Nokogiri::HTML(html)
elements = page.css('img.plantuml')
assert_equal elements.size, 1
element = elements.first
assert_equal GENURL2, element['src']
end
def test_plantuml_block_literal_processor3
html = ::Asciidoctor.convert(
StringIO.new(DOC_BASIC3_LITERAL), backend: 'html5'
)
page = Nokogiri::HTML(html)
elements = page.css('img.plantuml')
assert_equal elements.size, 1
element = elements.first
assert_equal GENURL2, element['src']
end
def test_plantuml_block_processor_encoding
Asciidoctor::PlantUml.configure do |c|
c.encoding = 'deflate'
end
html = ::Asciidoctor.convert(StringIO.new(DOC_BASIC), backend: 'html5')
page = Nokogiri::HTML(html)
elements = page.css('img.plantuml')
assert_equal elements.size, 1
element = elements.first
assert_equal GENURL_ENCODING, element['src']
end
def test_plantuml_id_attribute
html = ::Asciidoctor.convert(StringIO.new(DOC_ID), backend: 'html5')
page = Nokogiri::HTML(html)
elements = page.css('img.plantuml')
assert_equal elements.size, 1
element = elements.first
assert_equal 'myId', element['id']
end
def test_plantuml_dimension_attribute
html = ::Asciidoctor.convert(StringIO.new(DOC_DIM), backend: 'html5')
page = Nokogiri::HTML(html)
elements = page.css('img.plantuml')
assert_equal elements.size, 1
element = elements.first
assert_equal '100px', element['width']
assert_equal '50px', element['height']
end
def test_plantuml_alt_attribute
html = ::Asciidoctor.convert(StringIO.new(DOC_ALT), backend: 'html5')
page = Nokogiri::HTML(html)
elements = page.css('img.plantuml')
assert_equal elements.size, 1
element = elements.first
assert_equal 'alt', element['alt']
end
def test_should_show_bad_format
html = ::Asciidoctor.convert(StringIO.new(DOC_BAD_FORMAT), backend: 'html5')
page = Nokogiri::HTML(html)
elements = page.css('pre.plantuml-error')
assert_equal elements.size, 1
end
def test_plantuml_multiple_listing
html = ::Asciidoctor.convert(StringIO.new(DOC_MULTI), backend: 'html5')
page = Nokogiri::HTML(html)
elements = page.css('img.plantuml')
assert elements.size >= 2
elements = page.css('.plantuml-error')
assert_equal elements.size, 0
end
def test_plantuml_multiple_literal
html = ::Asciidoctor.convert(
StringIO.new(DOC_MULTI_LITERAL), backend: 'html5'
)
page = Nokogiri::HTML(html)
elements = page.css('img.plantuml')
assert elements.size >= 2
elements = page.css('.plantuml-error')
assert_equal elements.size, 0
end
def test_plantuml_bad_server
Asciidoctor::PlantUml.configure do |c|
c.url = 'http://nonexistent.com/plantuml'
end
html = ::Asciidoctor.convert(StringIO.new(DOC_MULTI), backend: 'html5')
page = Nokogiri::HTML(html)
elements = page.css('img.plantuml')
assert_equal 3, elements.size
elements = page.css('.plantuml-error')
assert_equal 0, elements.size
end
def test_plantuml_invalid_uri
Asciidoctor::PlantUml.configure do |c|
c.url = 'ftp://test.com'
end
html = ::Asciidoctor.convert(StringIO.new(DOC_BASIC), backend: 'html5')
page = Nokogiri::HTML(html)
elements = page.css('pre.plantuml-error')
assert_equal elements.size, 1
end
def test_plantuml_nil_uri
Asciidoctor::PlantUml.configure do |c|
c.url = nil
end
html = ::Asciidoctor.convert(StringIO.new(DOC_BASIC), backend: 'html5')
page = Nokogiri::HTML(html)
elements = page.css('pre.plantuml-error')
assert_equal elements.size, 1
end
def test_plantuml_empty_uri
Asciidoctor::PlantUml.configure do |c|
c.url = ''
end
html = ::Asciidoctor.convert(StringIO.new(DOC_BASIC), backend: 'html5')
page = Nokogiri::HTML(html)
elements = page.css('pre.plantuml-error')
assert_equal elements.size, 1
end
def test_disable_txt
Asciidoctor::PlantUml.configure do |c|
c.url = 'http://localhost:8080/plantuml'
c.txt_enable = false
end
html = ::Asciidoctor.convert(StringIO.new(DOC_TXT), backend: 'html5')
page = Nokogiri::HTML(html)
elements = page.css('pre.plantuml-error')
assert_equal elements.size, 1
end
def test_svg
Asciidoctor::PlantUml.configure do |c|
c.url = 'http://localhost:8080/plantuml'
c.svg_enable = true
end
html = ::Asciidoctor.convert(StringIO.new(DOC_SVG), backend: 'html5')
page = Nokogiri::HTML(html)
elements = page.css("object[type='image/svg+xml']")
assert_equal elements.size, 1
element = elements.first
assert_equal SVGGENURL, element['data']
end
def test_disable_svg
Asciidoctor::PlantUml.configure do |c|
c.url = 'http://localhost:8080/plantuml'
c.svg_enable = false
end
html = ::Asciidoctor.convert(StringIO.new(DOC_SVG), backend: 'html5')
page = Nokogiri::HTML(html)
elements = page.css('pre.plantuml-error')
assert_equal elements.size, 1
end
def test_disable_png
Asciidoctor::PlantUml.configure do |c|
c.url = 'http://localhost:8080/plantuml'
c.png_enable = false
end
html = ::Asciidoctor.convert(StringIO.new(DOC_BASIC_LITERAL), backend: 'html5')
page = Nokogiri::HTML(html)
elements = page.css('pre.plantuml-error')
assert_equal elements.size, 1
end
end