asciidoctor-plantuml 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/asciidoctor-plantuml.rb +7 -0
- data/lib/asciidoctor-plantuml/plantuml.rb +178 -0
- data/lib/asciidoctor-plantuml/version.rb +5 -0
- data/test/test_plantuml.rb +166 -0
- metadata +105 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ed5ecef9a1e029694a9d18e2800a7a95869455e6
|
4
|
+
data.tar.gz: b47a156f1e832ac35092f3ff6dfec092ebda99a6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4b8ee673ee3d5a3432a27d94bee9525e7e941791f6055a529300a5a065a1d659925d7d63b8a5d942e35ec4ec6ca11d2a5387232c9fb2cd2e28988b0500850742
|
7
|
+
data.tar.gz: 34a6ebd97cacd0ee47361c6ba1e62aa014f6e4ba028f0e7a43863a51212ae2985be179db107db811daf3094097453189d77938d3d65f3e5eac0ad5ba3f86cb22
|
@@ -0,0 +1,178 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'zlib'
|
3
|
+
require 'open-uri'
|
4
|
+
require 'net/http'
|
5
|
+
|
6
|
+
module Asciidoctor
|
7
|
+
module PlantUml
|
8
|
+
|
9
|
+
class Configuration
|
10
|
+
|
11
|
+
DEFAULT_URL = ENV["PLANTUML_URL"] || "http://localhost:8080/plantuml"
|
12
|
+
|
13
|
+
attr_accessor :url, :test
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@url = DEFAULT_URL
|
17
|
+
@test = false
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class << self
|
22
|
+
attr_writer :configuration
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.configuration
|
26
|
+
@configuration ||= Configuration.new
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.configure
|
30
|
+
yield(configuration)
|
31
|
+
end
|
32
|
+
|
33
|
+
module Processor
|
34
|
+
|
35
|
+
FORMATS = ["png", "svg", "txt"]
|
36
|
+
DEFAULT_FORMAT = FORMATS[0]
|
37
|
+
|
38
|
+
def valid_format?(format)
|
39
|
+
FORMATS.include?(format)
|
40
|
+
end
|
41
|
+
|
42
|
+
def server_url
|
43
|
+
PlantUml::configuration.url
|
44
|
+
end
|
45
|
+
|
46
|
+
def plantuml_content(code, format, attrs = {})
|
47
|
+
content = "<img "
|
48
|
+
content +="id=\"#{attrs['id']}\" " if attrs['id']
|
49
|
+
content +="class=\"plantuml\" "
|
50
|
+
content +="width=\"#{attrs['width']}\" " if attrs['width']
|
51
|
+
content +="height=\"#{attrs['height']}\" " if attrs['height']
|
52
|
+
content +="alt=\"#{attrs['alt']}\" " if attrs['alt']
|
53
|
+
content +="src=\"#{gen_url(code, format)}\" />"
|
54
|
+
end
|
55
|
+
|
56
|
+
# Compression code used to generate PlantUML URLs. Taken directly from the
|
57
|
+
# Transcoder class in the PlantUML java code.
|
58
|
+
def gen_url(text, format)
|
59
|
+
result = ""
|
60
|
+
compressedData = Zlib::Deflate.deflate(text)
|
61
|
+
compressedData.chars.each_slice(3) do |bytes|
|
62
|
+
#print bytes[0], ' ' , bytes[1] , ' ' , bytes[2]
|
63
|
+
b1 = bytes[0].nil? ? 0 : (bytes[0].ord & 0xFF)
|
64
|
+
b2 = bytes[1].nil? ? 0 : (bytes[1].ord & 0xFF)
|
65
|
+
b3 = bytes[2].nil? ? 0 : (bytes[2].ord & 0xFF)
|
66
|
+
result += append3bytes(b1, b2, b3)
|
67
|
+
end
|
68
|
+
join_paths(server_url, "/#{format}/", result).to_s
|
69
|
+
end
|
70
|
+
|
71
|
+
def encode6bit(b)
|
72
|
+
if b < 10
|
73
|
+
return ('0'.ord + b).chr
|
74
|
+
end
|
75
|
+
b = b - 10
|
76
|
+
if b < 26
|
77
|
+
return ('A'.ord + b).chr
|
78
|
+
end
|
79
|
+
b = b - 26
|
80
|
+
if b < 26
|
81
|
+
return ('a'.ord + b).chr
|
82
|
+
end
|
83
|
+
b = b - 26
|
84
|
+
if b == 0
|
85
|
+
return '-'
|
86
|
+
end
|
87
|
+
if b == 1
|
88
|
+
return '_'
|
89
|
+
end
|
90
|
+
return '?'
|
91
|
+
end
|
92
|
+
|
93
|
+
def append3bytes(b1, b2, b3)
|
94
|
+
c1 = b1 >> 2
|
95
|
+
c2 = ((b1 & 0x3) << 4) | (b2 >> 4)
|
96
|
+
c3 = ((b2 & 0xF) << 2) | (b3 >> 6)
|
97
|
+
c4 = b3 & 0x3F
|
98
|
+
return encode6bit(c1 & 0x3F).chr +
|
99
|
+
encode6bit(c2 & 0x3F).chr +
|
100
|
+
encode6bit(c3 & 0x3F).chr +
|
101
|
+
encode6bit(c4 & 0x3F).chr
|
102
|
+
end
|
103
|
+
|
104
|
+
# Make a call to the PlantUML server with the simplest diagram possible to
|
105
|
+
# check if the server is available or not.
|
106
|
+
def check_server(check_url)
|
107
|
+
response = Net::HTTP.get_response(URI(check_url))
|
108
|
+
return response.is_a?(Net::HTTPSuccess)
|
109
|
+
rescue
|
110
|
+
return false
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
def create_plantuml_block(parent, content)
|
115
|
+
Asciidoctor::Block.new parent, :pass, :content_model => :raw,
|
116
|
+
:source => content, :subs => :default
|
117
|
+
end
|
118
|
+
|
119
|
+
def join_paths(*paths, separator: '/')
|
120
|
+
paths = paths.compact.reject(&:empty?)
|
121
|
+
last = paths.length - 1
|
122
|
+
paths.each_with_index.map { |path, index|
|
123
|
+
expand_path(path, index, last, separator)
|
124
|
+
}.join
|
125
|
+
end
|
126
|
+
|
127
|
+
def expand_path(path, current, last, separator)
|
128
|
+
if path.start_with?(separator) && current != 0
|
129
|
+
path = path[1..-1]
|
130
|
+
end
|
131
|
+
|
132
|
+
unless path.end_with?(separator) || current == last
|
133
|
+
path = [path, separator]
|
134
|
+
end
|
135
|
+
|
136
|
+
path
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
class BlockProcessor < Asciidoctor::Extensions::BlockProcessor
|
141
|
+
include Processor
|
142
|
+
|
143
|
+
def process(parent, target, attrs)
|
144
|
+
|
145
|
+
testing = attrs["test"] == "true"
|
146
|
+
|
147
|
+
check_url = join_paths(server_url, "/png/SyfFKj2rKt3CoKnELR1Io4ZDoSa70000")
|
148
|
+
|
149
|
+
if ! check_server(check_url) && ! testing
|
150
|
+
content = "<div class='plantuml'>PlantUML server [#{check_url}] is unreachable</div>"
|
151
|
+
return create_plantuml_block(parent, content)
|
152
|
+
end
|
153
|
+
|
154
|
+
format = attrs["format"] || DEFAULT_FORMAT
|
155
|
+
|
156
|
+
if ! valid_format?(format)
|
157
|
+
content = "<div class='plantuml'>Invalid format #{format}</div>"
|
158
|
+
return create_plantuml_block(parent, content)
|
159
|
+
end
|
160
|
+
|
161
|
+
lines = target.lines
|
162
|
+
|
163
|
+
if !(target.lines[0] =~ /@startuml/)
|
164
|
+
lines = ["@startuml"] + target.lines
|
165
|
+
end
|
166
|
+
|
167
|
+
if !(target.lines[-1] =~ /@enduml/)
|
168
|
+
lines += ["@enduml"]
|
169
|
+
end
|
170
|
+
|
171
|
+
content = plantuml_content(lines.join("\n"), format, attrs)
|
172
|
+
return create_plantuml_block(parent, content)
|
173
|
+
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
end
|
178
|
+
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
require "asciidoctor"
|
3
|
+
require "stringio"
|
4
|
+
require "nokogiri"
|
5
|
+
require "asciidoctor-plantuml"
|
6
|
+
|
7
|
+
DOC_BASIC = <<-eos
|
8
|
+
= Hello PlantUML!
|
9
|
+
|
10
|
+
[plantuml, format="png", test="true"]
|
11
|
+
User -> (Start)
|
12
|
+
User --> (Use the application) : Label
|
13
|
+
eos
|
14
|
+
|
15
|
+
DOC_BASIC2 = <<-eos
|
16
|
+
= Hello PlantUML!
|
17
|
+
|
18
|
+
[plantuml, format="png", test="true"]
|
19
|
+
@startuml
|
20
|
+
User -> (Start)
|
21
|
+
User --> (Use the application) : Label
|
22
|
+
@enduml
|
23
|
+
eos
|
24
|
+
|
25
|
+
DOC_ID = <<-eos
|
26
|
+
= Hello PlantUML!
|
27
|
+
|
28
|
+
[plantuml, format="png", test="true", id="myId"]
|
29
|
+
User -> (Start)
|
30
|
+
User --> (Use the application) : Label
|
31
|
+
eos
|
32
|
+
|
33
|
+
DOC_DIM = <<-eos
|
34
|
+
= Hello PlantUML!
|
35
|
+
|
36
|
+
[plantuml, format="png", test="true", width="100px", height="50px"]
|
37
|
+
User -> (Start)
|
38
|
+
User --> (Use the application) : Label
|
39
|
+
eos
|
40
|
+
|
41
|
+
DOC_ALT = <<-eos
|
42
|
+
= Hello PlantUML!
|
43
|
+
|
44
|
+
[plantuml, format="png", test="true", alt="alt"]
|
45
|
+
User -> (Start)
|
46
|
+
User --> (Use the application) : Label
|
47
|
+
eos
|
48
|
+
|
49
|
+
DOC_BAD_FORMAT = <<-eos
|
50
|
+
= Hello PlantUML!
|
51
|
+
|
52
|
+
[plantuml, format="jpg", test="true"]
|
53
|
+
User -> (Start)
|
54
|
+
User --> (Use the application) : Label
|
55
|
+
eos
|
56
|
+
|
57
|
+
DOC_MULTI = <<-eos
|
58
|
+
= Hello PlantUML!
|
59
|
+
|
60
|
+
[plantuml, format="png", test="true"]
|
61
|
+
User -> (Start)
|
62
|
+
User --> (Use the application) : Label
|
63
|
+
|
64
|
+
[plantuml, format="txt", test="true"]
|
65
|
+
User -> (Start)
|
66
|
+
User --> (Use the application) : Label
|
67
|
+
eos
|
68
|
+
|
69
|
+
class PlantUmlTest < Test::Unit::TestCase
|
70
|
+
|
71
|
+
GENURL = "http://localhost:8080/plantuml/png/U9npA2v9B2efpStX2YrEBLBGjLFG20Q9Q4Bv804WIw4a8rKXiQ0W9pCviIGpFqzJmKh19p4fDOVB8JKl1QWT05kd5wq0"
|
72
|
+
|
73
|
+
def test_plantuml_block_processor
|
74
|
+
|
75
|
+
html = ::Asciidoctor.convert(StringIO.new(DOC_BASIC), backend: "html5")
|
76
|
+
page = Nokogiri::HTML(html)
|
77
|
+
|
78
|
+
elements = page.css('img.plantuml')
|
79
|
+
|
80
|
+
assert_equal elements.size, 1
|
81
|
+
|
82
|
+
element = elements.first
|
83
|
+
|
84
|
+
assert_equal GENURL, element["src"]
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_plantuml_block_processor2
|
88
|
+
html = ::Asciidoctor.convert(StringIO.new(DOC_BASIC2), backend: "html5")
|
89
|
+
page = Nokogiri::HTML(html)
|
90
|
+
|
91
|
+
elements = page.css('img.plantuml')
|
92
|
+
|
93
|
+
assert_equal elements.size, 1
|
94
|
+
|
95
|
+
element = elements.first
|
96
|
+
|
97
|
+
assert_equal GENURL, element["src"]
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_plantuml_id_attribute
|
101
|
+
|
102
|
+
html = ::Asciidoctor.convert(StringIO.new(DOC_ID), backend: "html5")
|
103
|
+
page = Nokogiri::HTML(html)
|
104
|
+
|
105
|
+
elements = page.css('img.plantuml')
|
106
|
+
|
107
|
+
assert_equal elements.size, 1
|
108
|
+
element = elements.first
|
109
|
+
|
110
|
+
assert_equal "myId", element["id"]
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_plantuml_dimension_attribute
|
115
|
+
|
116
|
+
html = ::Asciidoctor.convert(StringIO.new(DOC_DIM), backend: "html5")
|
117
|
+
page = Nokogiri::HTML(html)
|
118
|
+
|
119
|
+
elements = page.css('img.plantuml')
|
120
|
+
|
121
|
+
assert_equal elements.size, 1
|
122
|
+
element = elements.first
|
123
|
+
|
124
|
+
assert_equal "100px", element["width"]
|
125
|
+
assert_equal "50px", element["height"]
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_plantuml_alt_attribute
|
130
|
+
|
131
|
+
html = ::Asciidoctor.convert(StringIO.new(DOC_ALT), backend: "html5")
|
132
|
+
page = Nokogiri::HTML(html)
|
133
|
+
|
134
|
+
elements = page.css('img.plantuml')
|
135
|
+
|
136
|
+
assert_equal elements.size, 1
|
137
|
+
element = elements.first
|
138
|
+
|
139
|
+
assert_equal "alt", element["alt"]
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_should_show_bad_format
|
144
|
+
html = ::Asciidoctor.convert(StringIO.new(DOC_BAD_FORMAT), backend: "html5")
|
145
|
+
|
146
|
+
page = Nokogiri::HTML(html)
|
147
|
+
|
148
|
+
elements = page.css('img.plantuml')
|
149
|
+
assert_equal elements.size, 0
|
150
|
+
|
151
|
+
elements = page.css('div.plantuml')
|
152
|
+
assert_equal elements.size, 1
|
153
|
+
end
|
154
|
+
|
155
|
+
def test_plantuml_multiple
|
156
|
+
|
157
|
+
html = ::Asciidoctor.convert(StringIO.new(DOC_MULTI), backend: "html5")
|
158
|
+
page = Nokogiri::HTML(html)
|
159
|
+
|
160
|
+
elements = page.css('img.plantuml')
|
161
|
+
|
162
|
+
assert_equal elements.size, 2
|
163
|
+
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
metadata
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: asciidoctor-plantuml
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Horacio Sanson
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-11-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.5'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.5'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: nokogiri
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.6'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.6'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: asciidoctor
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.5'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.5'
|
69
|
+
description: Asciidoctor PlantUML extension
|
70
|
+
email:
|
71
|
+
- hsanson@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- lib/asciidoctor-plantuml.rb
|
77
|
+
- lib/asciidoctor-plantuml/plantuml.rb
|
78
|
+
- lib/asciidoctor-plantuml/version.rb
|
79
|
+
- test/test_plantuml.rb
|
80
|
+
homepage: https://github.com/hsanson/asciidoctor-plantuml
|
81
|
+
licenses:
|
82
|
+
- MIT
|
83
|
+
metadata: {}
|
84
|
+
post_install_message:
|
85
|
+
rdoc_options: []
|
86
|
+
require_paths:
|
87
|
+
- lib
|
88
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '0'
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
requirements: []
|
99
|
+
rubyforge_project:
|
100
|
+
rubygems_version: 2.5.1
|
101
|
+
signing_key:
|
102
|
+
specification_version: 4
|
103
|
+
summary: An extension for Asciidoctor that enables support for PlantUML diagrams.
|
104
|
+
test_files:
|
105
|
+
- test/test_plantuml.rb
|