yard-sd 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Example.md +74 -0
- data/LICENSE +20 -0
- data/README.md +212 -0
- data/lib/yard-sd/sequence_diagram/diagram.rb +168 -0
- data/lib/yard-sd/sequence_diagram/parse_error.rb +4 -0
- data/lib/yard-sd/sequence_diagram/participant.rb +30 -0
- data/lib/yard-sd/sequence_diagram.rb +24 -0
- data/lib/yard-sd/sequence_diagram_mixin.rb +40 -0
- data/lib/yard-sd.rb +2 -0
- metadata +56 -0
data/Example.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
Input:
|
2
|
+
|
3
|
+
!!!plain
|
4
|
+
!!!sd
|
5
|
+
% size = 800
|
6
|
+
|
7
|
+
thread SimulationServer as SiS
|
8
|
+
participant SimControlNode as SCN
|
9
|
+
participant PhysicsServer as PS
|
10
|
+
participant[2] SenseServer as SeS
|
11
|
+
|
12
|
+
SiS->SeS: Initialize()
|
13
|
+
SeS-->SiS:
|
14
|
+
|
15
|
+
block "Run Loop" "The main loop"
|
16
|
+
SiS->SCN: StartCycle()
|
17
|
+
SCN->SeS: ActAgent()
|
18
|
+
SeS-->SCN:
|
19
|
+
SCN-->SiS:
|
20
|
+
|
21
|
+
SiS->PS: Update()
|
22
|
+
PS->SeS: PrePhysicsUpdate
|
23
|
+
noreturn
|
24
|
+
|
25
|
+
PS->PS: PhysicsUpdate()
|
26
|
+
PS-->PS:
|
27
|
+
|
28
|
+
PS->SeS: PostPhysicsUpdate()
|
29
|
+
SeS-->PS:
|
30
|
+
|
31
|
+
PS-->SiS:
|
32
|
+
|
33
|
+
SiS->SCN: EndCycle()
|
34
|
+
SCN->SeS: SenseAgent()
|
35
|
+
SeS-->SCN:
|
36
|
+
SCN-->SiS:
|
37
|
+
|
38
|
+
Output:
|
39
|
+
|
40
|
+
!!!sd
|
41
|
+
% size = 800
|
42
|
+
|
43
|
+
thread SimulationServer as SiS
|
44
|
+
participant SimControlNode as SCN
|
45
|
+
participant PhysicsServer as PS
|
46
|
+
participant[2] SenseServer as SeS
|
47
|
+
|
48
|
+
SiS->SeS: Initialize()
|
49
|
+
SeS-->SiS:
|
50
|
+
|
51
|
+
block "Run Loop" "The main loop"
|
52
|
+
SiS->SCN: StartCycle()
|
53
|
+
SCN->SeS: ActAgent()
|
54
|
+
SeS-->SCN:
|
55
|
+
SCN-->SiS:
|
56
|
+
SiS->SCN: Something
|
57
|
+
SCN-->SiS: Something else
|
58
|
+
|
59
|
+
SiS->PS: Update()
|
60
|
+
PS->SeS: PrePhysicsUpdate
|
61
|
+
noreturn
|
62
|
+
|
63
|
+
PS->PS: PhysicsUpdate()
|
64
|
+
PS-->PS:
|
65
|
+
|
66
|
+
PS->SeS: PostPhysicsUpdate()
|
67
|
+
SeS-->PS:
|
68
|
+
|
69
|
+
PS-->SiS:
|
70
|
+
|
71
|
+
SiS->SCN: EndCycle()
|
72
|
+
SCN->SeS: SenseAgent()
|
73
|
+
SeS-->SCN:
|
74
|
+
SCN-->SiS:
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Dominik Honnef
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,212 @@
|
|
1
|
+
# yard-sd
|
2
|
+
|
3
|
+
Note: This README and {file:Example.md the example} are best viewed on
|
4
|
+
{http://doc.fork-bomb.org/yard-sd/} or a service supporting the
|
5
|
+
yard-sd plugin.
|
6
|
+
|
7
|
+
## Description
|
8
|
+
|
9
|
+
yard-sd allows embedding sequence diagrams directly in docstrings and
|
10
|
+
files. During documentation generation, it replaces the text
|
11
|
+
description with images.
|
12
|
+
|
13
|
+
## Requirements
|
14
|
+
|
15
|
+
yard-sd needs YARD 0.7.5/0.8.0 to function properly.
|
16
|
+
|
17
|
+
Furthermore, yard-sd needs the following binaries:
|
18
|
+
|
19
|
+
- pdflatex
|
20
|
+
- convert (from the ImageMagick suite)
|
21
|
+
- gs (Ghostscript, needed by convert)
|
22
|
+
|
23
|
+
## Installation
|
24
|
+
|
25
|
+
$ gem install yard-sd
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
yard-sd defines a new language for code blocks called "sd". Like other
|
30
|
+
languages, it can be used with the tripple-bang syntax (!!!LANG).
|
31
|
+
|
32
|
+
## Example
|
33
|
+
|
34
|
+
### Input
|
35
|
+
|
36
|
+
!!!plain
|
37
|
+
!!!sd
|
38
|
+
% size = 400
|
39
|
+
|
40
|
+
thread Alice
|
41
|
+
participant[2] Bob
|
42
|
+
participant[2] Eve
|
43
|
+
|
44
|
+
Alice -> Bob: Some message
|
45
|
+
Bob -> Eve: Another message
|
46
|
+
Eve --> Bob: Return value
|
47
|
+
noreturn
|
48
|
+
|
49
|
+
### Output
|
50
|
+
|
51
|
+
!!!sd
|
52
|
+
%size = 400
|
53
|
+
|
54
|
+
thread Alice
|
55
|
+
participant[2] Bob
|
56
|
+
participant[2] Eve
|
57
|
+
|
58
|
+
Alice -> Bob: Some message
|
59
|
+
Bob -> Eve: Another message
|
60
|
+
Eve --> Bob: Return value
|
61
|
+
noreturn
|
62
|
+
|
63
|
+
## The format
|
64
|
+
|
65
|
+
A sequence diagram consists of two parts: the metadata (currently only
|
66
|
+
the size) and the actual description of the diagram's content.
|
67
|
+
|
68
|
+
### Metadata
|
69
|
+
|
70
|
+
The only currently supported and required metadata is the size of the
|
71
|
+
diagram. You can either specify only a width (e.g. `500`), only a
|
72
|
+
height (e.g. `x500`) or both (e.g. `500x500`). In most cases it makes
|
73
|
+
sense to specify only one of the dimensions so the aspect ratio can be
|
74
|
+
kept.
|
75
|
+
|
76
|
+
### Content
|
77
|
+
|
78
|
+
The content itself can also be separated into two parts: The list of
|
79
|
+
threads/participants (simply called participants from now on) and the
|
80
|
+
messages between those.
|
81
|
+
|
82
|
+
#### Participants
|
83
|
+
|
84
|
+
In their most basic form, they consist of a type (`thread` or
|
85
|
+
`participant`) and a name.
|
86
|
+
|
87
|
+
Example:
|
88
|
+
|
89
|
+
!!!plain
|
90
|
+
thread Alice
|
91
|
+
participant Bob
|
92
|
+
|
93
|
+
Output:
|
94
|
+
|
95
|
+
!!!sd
|
96
|
+
% size = 200
|
97
|
+
thread Alice
|
98
|
+
participant Bob
|
99
|
+
|
100
|
+
It is also possible to specify the distance to the previous
|
101
|
+
participant by adding a number in square brackets. The default is `0`,
|
102
|
+
so `1` will double the distance, `2` will triple it and so on.
|
103
|
+
|
104
|
+
Example:
|
105
|
+
|
106
|
+
!!!plain
|
107
|
+
thread Alice
|
108
|
+
participant[1] Bob
|
109
|
+
|
110
|
+
Output:
|
111
|
+
|
112
|
+
!!!sd
|
113
|
+
% size = 200
|
114
|
+
thread Alice
|
115
|
+
participant[1] Bob
|
116
|
+
|
117
|
+
Finally, it is also possible to assign aliases to avoid typing out
|
118
|
+
long names over and over again.
|
119
|
+
|
120
|
+
Example:
|
121
|
+
|
122
|
+
!!!plain
|
123
|
+
participant "Alice, the wonderful girl" as Alice
|
124
|
+
participant Bob
|
125
|
+
|
126
|
+
Alice -> Bob: Yey
|
127
|
+
|
128
|
+
Output:
|
129
|
+
|
130
|
+
!!!sd
|
131
|
+
% size = 300
|
132
|
+
participant "Alice, the wonderful girl" as Alice
|
133
|
+
participant Bob
|
134
|
+
|
135
|
+
Alice -> Bob: Yey
|
136
|
+
#### Messages
|
137
|
+
|
138
|
+
The second part of description of the sequende diagram consists of
|
139
|
+
messages between participants. Messages are denoted by an arrow and
|
140
|
+
text (`p1 -> p2: The message`) while return values are denoted by a
|
141
|
+
dashed arrow and also text (`p2 --> p1: The return value`). If a
|
142
|
+
message has no return value, a `noreturn` has to be placed after the
|
143
|
+
execution finished.
|
144
|
+
|
145
|
+
Example:
|
146
|
+
|
147
|
+
!!!plain
|
148
|
+
Alice -> Bob: Some message
|
149
|
+
Bob -> Eve: Another message
|
150
|
+
Eve --> Bob: Return value
|
151
|
+
noreturn
|
152
|
+
|
153
|
+
Output:
|
154
|
+
|
155
|
+
!!!sd
|
156
|
+
% size = 400
|
157
|
+
participant Alice
|
158
|
+
participant[1] Bob
|
159
|
+
participant[2] Eve
|
160
|
+
|
161
|
+
Alice -> Bob: Some message
|
162
|
+
Bob -> Eve: Another message
|
163
|
+
Eve --> Bob: Return value
|
164
|
+
noreturn
|
165
|
+
|
166
|
+
#### Blocks
|
167
|
+
|
168
|
+
Furthermore, it is possible to group messages into blocks, for example
|
169
|
+
for representing loops:
|
170
|
+
|
171
|
+
Example:
|
172
|
+
|
173
|
+
!!!plain
|
174
|
+
block "Name" "Description"
|
175
|
+
Alice -> Bob: Msg1
|
176
|
+
Bob --> Alice: Ret1
|
177
|
+
|
178
|
+
block "Another name" "Nested blocks, yey"
|
179
|
+
Alice -> Bob: Msg2
|
180
|
+
noreturn
|
181
|
+
|
182
|
+
Alice -> Bob: Msg3
|
183
|
+
Bob --> Alice: Ret3
|
184
|
+
|
185
|
+
Output:
|
186
|
+
|
187
|
+
!!!sd
|
188
|
+
% size = 200
|
189
|
+
|
190
|
+
participant Alice
|
191
|
+
participant Bob
|
192
|
+
|
193
|
+
block "Name" "Description"
|
194
|
+
Alice -> Bob: Msg1
|
195
|
+
Bob --> Alice: Ret1
|
196
|
+
|
197
|
+
block "Another name" "Nested blocks, yey"
|
198
|
+
Alice -> Bob: Msg2
|
199
|
+
noreturn
|
200
|
+
|
201
|
+
Alice -> Bob: Msg3
|
202
|
+
Bob --> Alice: Ret3
|
203
|
+
|
204
|
+
Blocks automatically get closed, based on the indentation level.
|
205
|
+
|
206
|
+
### More information
|
207
|
+
|
208
|
+
For a more advanced example, see {file:Example.md Example.md}.
|
209
|
+
|
210
|
+
## Caveats
|
211
|
+
|
212
|
+
yard-sd currently does not support Unicode.
|
@@ -0,0 +1,168 @@
|
|
1
|
+
require "tmpdir"
|
2
|
+
require "fileutils"
|
3
|
+
|
4
|
+
module SequenceDiagram
|
5
|
+
|
6
|
+
class Diagram
|
7
|
+
Block = Struct.new(:level, :name, :description)
|
8
|
+
Call = Struct.new(:p1, :p2, :message, :return, :block)
|
9
|
+
@@uid = 0
|
10
|
+
|
11
|
+
attr_reader :uid
|
12
|
+
def initialize
|
13
|
+
@participants = []
|
14
|
+
@calls = []
|
15
|
+
@uid = @@uid += 1
|
16
|
+
end
|
17
|
+
|
18
|
+
def parse(s)
|
19
|
+
last_calls = Hash.new {|h, k| h[k] = []}
|
20
|
+
blocks = [Block.new(0, nil, nil)]
|
21
|
+
last_indent = 0
|
22
|
+
|
23
|
+
s.each_line do |line|
|
24
|
+
line.chomp!
|
25
|
+
next if line.empty?
|
26
|
+
|
27
|
+
case line
|
28
|
+
when /^(participant|thread)(?:\[(\d+)\])? ("?)(.+?)\3(?: as (.+))?$/
|
29
|
+
distance = $2 && $2.to_i
|
30
|
+
name = $4
|
31
|
+
aliasing = $5 || name
|
32
|
+
thread = $1 == "thread"
|
33
|
+
@participants << Participant.new(name, aliasing, distance, thread)
|
34
|
+
when /^(\s*)block "([^"]+)" "([^"]+)"/
|
35
|
+
if $1.size < last_indent
|
36
|
+
blocks.pop
|
37
|
+
end
|
38
|
+
|
39
|
+
blocks << Block.new(blocks.size, $2, $3)
|
40
|
+
when /^(\s*)(.+?)\s*(->|-->)\s*(.+?):(?: (.+))?$/
|
41
|
+
p1 = @participants.find {|p| p.aliasing == $2}
|
42
|
+
p2 = @participants.find {|p| p.aliasing == $4}
|
43
|
+
|
44
|
+
error(:unknown_participant, line) if p1.nil?
|
45
|
+
error(:unknown_participant, line) if p2.nil?
|
46
|
+
|
47
|
+
message = $5.to_s
|
48
|
+
|
49
|
+
if $1.size < last_indent
|
50
|
+
blocks.pop
|
51
|
+
end
|
52
|
+
|
53
|
+
last_indent = $1.size
|
54
|
+
|
55
|
+
case $3
|
56
|
+
when "->"
|
57
|
+
call = Call.new(p1, p2, message, nil, blocks.last)
|
58
|
+
last_calls[p1] << call
|
59
|
+
@calls << call
|
60
|
+
when "-->"
|
61
|
+
last_calls[p2].pop.return = message.to_s
|
62
|
+
@calls << :pop
|
63
|
+
end
|
64
|
+
when /^\s*noreturn$/
|
65
|
+
@calls << :pop
|
66
|
+
else
|
67
|
+
error(:cannot_parse, line)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
self
|
72
|
+
end
|
73
|
+
|
74
|
+
def error(kind, information)
|
75
|
+
raise ParseError, [kind, information].inspect
|
76
|
+
end
|
77
|
+
|
78
|
+
def to_s
|
79
|
+
s = "\\begin{sequencediagram}\n"
|
80
|
+
@participants.each do |p|
|
81
|
+
s << p.to_s << "\n"
|
82
|
+
end
|
83
|
+
|
84
|
+
last_callee = nil
|
85
|
+
prev_block_level = 0
|
86
|
+
open = []
|
87
|
+
|
88
|
+
indent = 0
|
89
|
+
@calls.each do |call|
|
90
|
+
if call == :pop
|
91
|
+
indent -= 1
|
92
|
+
s << " " * indent << "\\end{#{open.pop}}\n"
|
93
|
+
next
|
94
|
+
end
|
95
|
+
|
96
|
+
if call.block.level > prev_block_level
|
97
|
+
s << " " * indent << "\\begin{sdblock}{#{call.block.name}}{#{call.block.description}}\n"
|
98
|
+
indent += 1
|
99
|
+
elsif call.block.level < prev_block_level
|
100
|
+
indent -= 1
|
101
|
+
s << " " * indent << "\\end{sdblock}\n"
|
102
|
+
end
|
103
|
+
prev_block_level = call.block.level
|
104
|
+
|
105
|
+
if !call.return.nil?
|
106
|
+
if call.p1 == call.p2
|
107
|
+
s << " " * indent << "\\begin{callself}{#{call.p1.uid}}{#{SequenceDiagram.latex_escape(call.message)}}{#{SequenceDiagram.latex_escape(call.return)}}\n"
|
108
|
+
open << :callself
|
109
|
+
else
|
110
|
+
s << " " * indent << "\\begin{call}{#{call.p1.uid}}{#{SequenceDiagram.latex_escape(call.message)}}{#{call.p2.uid}}{#{SequenceDiagram.latex_escape(call.return)}}\n"
|
111
|
+
open << :call
|
112
|
+
end
|
113
|
+
else
|
114
|
+
s << " "* indent << "\\begin{messcall}{#{call.p1.uid}}{#{SequenceDiagram.latex_escape(call.message)}}{#{call.p2.uid}}\n"
|
115
|
+
open << :messcall
|
116
|
+
end
|
117
|
+
indent += 1
|
118
|
+
end
|
119
|
+
|
120
|
+
while close = open.pop
|
121
|
+
s << " " * indent << "\\end{#{close}}\n"
|
122
|
+
indent -= 1
|
123
|
+
end
|
124
|
+
|
125
|
+
while prev_block_level > 0
|
126
|
+
indent -= 1
|
127
|
+
s << " " * indent << "\\end{sdblock}\n"
|
128
|
+
prev_block_level -= 1
|
129
|
+
end
|
130
|
+
|
131
|
+
s << "\\end{sequencediagram}"
|
132
|
+
end
|
133
|
+
|
134
|
+
def to_png(options = {})
|
135
|
+
graph = self.to_s
|
136
|
+
tex = Template.sub("%%EMBED\n", graph.sub(/\n+$/, ""))
|
137
|
+
dir = Dir.mktmpdir
|
138
|
+
image = nil
|
139
|
+
|
140
|
+
Dir.chdir(dir) do
|
141
|
+
# File.open("/tmp/debug.tex", "w"){|f| f.print tex}
|
142
|
+
IO.popen("pdflatex -halt-on-error", "w+") do |pipe|
|
143
|
+
pipe.write tex
|
144
|
+
pipe.close_write
|
145
|
+
pipe.read
|
146
|
+
end
|
147
|
+
|
148
|
+
if $?.exitstatus != 0
|
149
|
+
error("Couldn't compile latex", nil)
|
150
|
+
end
|
151
|
+
|
152
|
+
args = ["-depth", "4",
|
153
|
+
"-quality", "95",
|
154
|
+
"-colorspace", "RGB",
|
155
|
+
"-density", "500x500",
|
156
|
+
"-flatten"]
|
157
|
+
|
158
|
+
args << "-resize" << options[:size] if options[:size]
|
159
|
+
|
160
|
+
image = `convert #{args.join(" ")} texput.pdf png:-`
|
161
|
+
end
|
162
|
+
|
163
|
+
FileUtils.rm_rf(dir)
|
164
|
+
|
165
|
+
return image
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module SequenceDiagram
|
2
|
+
class Participant
|
3
|
+
@@uid = 0
|
4
|
+
|
5
|
+
attr_reader :name
|
6
|
+
attr_reader :distance
|
7
|
+
attr_reader :uid
|
8
|
+
attr_reader :aliasing
|
9
|
+
def initialize(name, aliasing, distance = nil, thread = false)
|
10
|
+
@name = name
|
11
|
+
@aliasing = aliasing
|
12
|
+
@distance = distance
|
13
|
+
@thread = thread
|
14
|
+
@uid = @@uid += 1
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
cmd = @thread ? "newthread" : "newinst"
|
19
|
+
if @distance.nil?
|
20
|
+
"\\#{cmd}{#@uid}{#{SequenceDiagram.latex_escape(@name)}}"
|
21
|
+
else
|
22
|
+
"\\#{cmd}[#@distance]{#@uid}{#{SequenceDiagram.latex_escape(@name)}}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def ==(other)
|
27
|
+
@uid == other.uid
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "zlib"
|
2
|
+
|
3
|
+
require "yard-sd/sequence_diagram/parse_error"
|
4
|
+
require "yard-sd/sequence_diagram/participant"
|
5
|
+
require "yard-sd/sequence_diagram/diagram"
|
6
|
+
|
7
|
+
module SequenceDiagram
|
8
|
+
# Author: Xu Yuan <xuyuan.cn@gmail.com>, Southeast University, China
|
9
|
+
# Contributor: Nobel Huang <nobel1984@gmail.com>, Southeast University, China
|
10
|
+
Template = Zlib::Inflate.inflate "x\x9C\xE5ZK\x8F\xDB8\x12\xBE\xF7\xAF\xE0\xA2\xD1@w\xDA\x16\xFC\xE8\xCE\x06\t\x9C\xC3\xCC\x06\x8B=\f\xB0X\xCC\xCD6\x06\xB4D\xDB\x9C\x96H\rE\xB5\xE3\xD1\xEA\xBFo\x15\x1F\x12\xF5pO\xD2\xC9a13\x87\x8EE\x16\x8B\xF5\xFCX,\xCE&\x91q\x991\xA1\xE3\x94\x16EUh*\x12\x9AJ\xC1\xEA\xABMN\x0F\xAC\xD0\xE7\x94U,\xCB\xF5\x19F\xCA\x82\xE54~\x82\xF1J\xF3\xA7\xDF\xEB+3\x84?S\xBEST\x9D+\xAA\x94<\x150qC\x12\x06<\x15#)=3U\x00\xBB\xC3\xDE\r\x99\x91j\a\x9C\x0EJ\x96\"\xA9\x87\x93\xFA\xA8\x18M\xC2i\xD8\xC7r\n\x16NB\xB2IF\xB90;\vv\"1\fi\xB3/|\xB9\x8F*W\x8C\x8BB\xD7\x9DA\x1C\x11e\xD6\x1D\xB4\x8C\a\xC3\x05\xFB-e\xCF,\xAD\xC9\r1?:\xB31M\xED\xEC`\xB4`\xE9~dj\x97\xCA\xF8\xC9\x8D;\xB9\xA9 (\x10\x151\x83\x91O\x9Fi\x96\xA7\xEC=\xFC\xC4u8\xB3f\xC9\x81\x91\x84[\x9Am\xF5LU]\t\x9A\xB1\xF7\xC6\x85~\x83,\x03OV~Q\xBD^n\xD7\xB3h\xB1\xAD\xAE\b\xD9\x14\x9A\xE5\x03\xEDa<\xA7\xFAHnqd\xA3\x8F\xCC\x19+b\xB4\xD0w\xF7\xB7\xD7\xF3\xC9\xEC\x8E\b\x99\xB05\x0E\x9B\xC0\xD8\xB6\xD4\x8E\xCF\x1D\xF0\xA96\xE0\r\xA6R.Xu\xBD\xAC\xEB\x0FC\xDE\x9E\xFA\xFEv6\x99\xCE\xA2\xC77\xB0\x84\xEB=\x8D\xB5Tv\x13r{\xBD\xB8#\x95]\x8C\x11f#\x11\x17\xC62\x95\xEAzQ\xAF\xD6\xDB\xBE6\x8D\x83\xC7\xECI\xACS/\x98\xD5p\r\xCCYW\x17\xECi\xB9\x18\x8B\x1E\x14=\xFFm9\xB3Vu\x8C*\x90\f\xD5\xEE\x8B\x16D\x14\x12\xA3\x1Dw,\x95'\"\xF7\xAB\x9EY&\xC6\x00\xDE\xC5\xABY\xF4.\xCE\xC0\xD4\x96\x03\xD25\xBCF,d\xE7\x8C6\x1DR0\xD7\x9E\xA7\xE9\xEAz\xBE}\xC9\xA4\r\x8D\xCDaEOD\x95Bpq@\x01x\xFCtG\xD0\xB1\x13R\x1Ce\x99&\xE0+M0\xC2A\\\xC5b\x9D\x9EC{\xBD\xA96\xC8\xC1[\xCC\x85\xDF\x8E\x1D\xB8\xA8 \xA5\xA50\x19]\xF7\xB2\x9D\xC0\x7Ff\xDD\xDA\x8E\e1';\xA9 \xA8~\xB1\x1FF\xCA\xD3\x91k\f\xC1\xEByt\x02\xA0\xBA#\xD3\xA9\xF90\x01k?\x16\xDD\x8F\x86,>\xC7)3\x86c\xE0\xD5@\x14\xAB6%\xFBR\xC4\x9AKat\xEBE\x8C\x95\x1F'\xEA5\xF8\xECp\xD4[\x9B\xFA\xA0\x89_W\xDB\x11\x88\"\xC5t\xA9\x00\x97n\xEC^f\x99\xB1\x11\x13\xCF\\I\x81\xE0\xEB\x98=n\xD7\xF3a\x866\x98\xD3\x9Fh\xE0\x06\xC0(/\x8B\xA3O3\xF8\x17\x93\xC7\xE4\x16\x86\x80g\x10&\x19$\xDD\xDF\xC7\x92.\xDE\xE3\n\xCF\x19\xC3\xCBp{\x886\xD6\x17;N\x8BWr\xD6}\xCE\x1F\xAE\xAE\xBC\xA3\xCD\xB1\xE1|;\xFD8\xF9\xB8\xD2\x8ASqH\x19y;\x03\x0FW]\xB1j\xEB\xD0\x1EG`f\xB2*\xE3\xC9\x89\x9E'\x84\xEE\xE43\x84\a\xE6\xA2\xF1t\xC2\xF6\x9B4\\Q]\xCFk?\xB1\xEFN,\x9A\t\xDD\x9Dxh&\xAC_\x9FiZ\x02\xCA=\xD6cIh~\xD7\xF7\xABu\x90b\x98X\xC6\xC54I\xB4\x1C\xF8\xB8\xEA\x8AX\x87>\xED\n\xF9:/\xA8Q\xFFv\xB5\xFCv_\xAB\x11_\x8F\xB9:\xA1\xC5\x91%\xD6\xE3\xA1\xBB\xBB\xEB\x9D\xBB{\xA2\x8F\xBB\xBB\n\xFD\xD2\xEEj\x15\xAA\xBA\x11S\xF7\xF7\x19\xB8\xA5\xA5\x9C\xCEM\x96\xC9|\x00\x10\x894\x18(\x18K,\x10J`\tu\xC7%\xCC\xC0R\xE0%\xDC\x18\xC1\v\xB3d\x143,\xB3\x87o\xC7\x8D\xFE|P\xB0\f`\xC5\xDB\xAC\xA1y3\x8B\xE6\x10\n\xF3\xAF\x0F\x94\"\x1E\v\xC7\xAA;\\\xFB\x12\xC4\xD4\n\xCB\xE58\xA3\xDD\v\xF0\x82'\x96\xC9\xBF\x89f\x9F\xF5j\x97B\x059\x8A3\xA3\ec\xF4\xDD\xC3\xEE\xD1;\xA8\x80|\xD8\tF\x15\x81\x03Zi\x17zD\x19\x8F\x1A\xBC\xF1+F\xE4\x85\xF5\x18\xCC}y\xBF\x01\xA1:@\xF4\xF05@\xF4\n\x1C\x1AA\xA1\xD7\x85\xC3\x98\e\xD1\xF7\xC5\x8B\xE7\x04\xFEY\xB5\xDE\xBC\x84\x1F=&\xDE\x8F\xED\x1E\xAC\xBFG\xC7\xC7\xF8\xD1\xC1\x16\xEB\xDA.\xB6\\r\xB0\xE34\xB5\xAC\xFA\b\xD4\xF3{]\xF5d\xF92\f\x1A\xA3i3\x16\t-Le\xAC(\xE0\xB2FvL\x9F\x18\x13\xAE\x00\xEEc\x13R\x81\xE7\xB1f\xAF+\xBF$\x96\xC0Yh\xC4\xA3\x98\xF1g,\x8D:\x850\xD2a\r\xFC2\xEC4\xB81\x7F\xDDA\x82\xBB\x00t6u\xC8\xF2\xF5l@\xBF\xEEA\xD4\x8F\x9Af/\xCC\xCFf\xC5xI\xB1\x00>x\xFB\xEDA2\xAE\xB2\xA5\xDCw\x80\xE4?K)\xF7\x7F\\\xC7\xFD\x15\v\xB6\xD1\xE3\xF3\x85\x82\xED{\x97N\xFFB\x18b\xA4\xE0\xBA\xA4\xA6\x80\x92{\x92\x95\xA9\xE6S\xE7\x03\xB8Z\xCA\x8C\x11\xB9\xFB\x15\xEE\x93\x05\xC1\x16\x92a\x96\x10\xAAq)\xF0(\xE0~N4\xCFXD~,\x95\x82\xD4K!PN\x8C\x1C)\x1C\xC4Z\x12\x9A\xFCZ\x16\x86\x9A\xA0Qp\x0F\xCB\xDD\\^\x11\x19\xA9(\x81\xE99\"\xFF\x96E\xC1w\x10\xA19U\xC0\x16{F\xB8\xE7{\x123T\x04\xD9\x16p\xC6\xE3\t\xD2E\xC0\x82\xE9\xD6\xEC5\xA6\xFB\xE6\x90\xCA\x1DMm\xBC5S\x18\x9E_\xA59\x98M\x80\xE2G\x9A\xE7\x80\xD9Vi\xA32\xF0\xF8B\xA5\x8D\xE9o\x91\xF8\x0Ew\xB1\x1C;j\xFF|\xE4E[\xC4f\xF4\x89\x15f\xA5)a\xA1\xB6I9SQW\xE1\\1\x1F\xF3\x17ra\xEA4\xA5\xC4t\xB6\xC8N~&'\x0EUCLs\xDC\xA7\xAD\x84\x8B\xC4P\xD4k7C\xDA\xA6\x1Eq\x9D\x187\x037i\x10\x00\xE5ojb\xBFx\x80\xBF\r\xD7\xE5vm\xBB\x03_\x0E\xC1A/.\x00\xE1XJ\x95pA5$\x89\xA1\x00\xF11\xF0[\xEA;\xF4\xD0\x8B9\x17\xE6\xDB\x87\x17\xE5\xC1\xC01\x9C\x9B\xF6M\xBBO\x88rf\x14\x9BT}\x92E\x9FM\x96\xF5Ilg\xAA\xE9\xC1p\x94B\x95\xB9\xDE\xA1\xED\xB98\x80\xCFjW\x1A\x0E\x947'\xE2\x1F\xA9\xBBx3P\xD8V\x8E\xB1\x8DZ\xE2w\xC2\xF0hJ\xFBh\xE1\xDB\x8B\xB0\x97\xFCl\v6\vv\xA3\xEB0+\xC9\x7F\xA7\xA4\x1A\xF7\n\x1C-\xF7\x04\x8B\xB0E[\xB3\x93[qj\xA0\xCD\x8A\xE4vBF\xAD\x82\xEEF\xC1:0h\x17c\x8B\xCB\x9Eg8oN=\xCCI\x9D\xB2\xB6\xA9\x87||w\xD4|\x98yk7#\xC0%\xF7u\x04k\x16F\x85,a\xC4\x1A\xE4\x1EM\x0FJ\xB5B6V\xBA\xBCb\xDA1n\xC1v#K\x84T\x9DM\xC2\x15\x18E\xDD\xD2\xC9\xB4\xDF.F\xEAv\x84s\xDB\xA0\xBB\xB0\xE9tj*s\xA6#\x8B\xBB\x96\x18\x84\xED|\x0F\x94\x1C\xE9\xE8}\x17/\xB4L<\xFA\x84\xBC\xDC\x98\xE5\xE6\xCCs)\xE3\\m\xE4\xFA\x8C\xE3\xE9f\xC2\b0\x95\xE8\x93\x84\x93\x92#\xFC\x03\xA0?1\x96\xDB3,\x88\xFCF\xBAD\xC2m\xF3v\x8F\xCA4J\x05\xC2\xBB\xE9\xC2\xE9\xEC\xC3ypP\a\x92vo\x18\xE3(e\xF0\x1De\np\x17\x8F\x18\xA0(\x196\xD9\x13N\x0Fp\x90\x0E\xB1\xD9\x11\xB8\xF9:h\x05c\x19\x96\xF3\x18\xEEV\xCCu\x7F\xF1\xB1\x87\x89\x83>V\x06K\xEC\xEF\xBA\x9A\xC7\x99o\x0F\xB3\xBD\xBF\x05V\xBB\x83\xF9\xB7\xAE\xFE\xF3\xCF\x1F\xEAj\xB1|\x98\x90\xC5\xC3\f\xFE<>\x8EP7\xB7GG\xFF\xEEqB\xE6\xB3\x05\xFCY\xBEu\xE4mY\xE8\x85\xAEW\xEB\x16\f\xB7}\xAA\xB05\r\x94\xDDK\xEA\x80:(\x90\a\xC4\xB6\xB1}ym\xF3\xF2\x02+\e,\x9A\x90\x1E\x13BE|\x94je+\x97\x8C\v\x9E\x95\x19\xB1-'\xFB\x9A\xD0\x8E\x9Ex\xA2\x8F\xABy\xF4\x16\a\xCD\xEE\xCE\x9CC-\x9B\x94\x82\xCD\xDD\x0Emr\x8F\x93\x87\xC93\xB6\n\xB6\x84{\xE6jSdPv\fX@\b\xD7X\x8B\v\xA6 \xBE\xF2\xD5,\xD7\xD6@\xB6\x81\x13s\x059?\xF1\x9A\x14\xFCw|+Y\xE4^\x96\xA0\x1Ak\x0F\xA4j\x16y7\x8FWk\x16n,\xC9\r\x00>\x84b\xFB\x98\xE8\x83\xB3\xFF\xDET\xCD\xEA\xC1\x9C\x7FY\e\x9Bk_e\xC6f\xDB\x82jd\xB2-\xAC/L\x06\x8D\x80\x11\x8A0\xDDg\x06yPM\xA98$\xA2%6\xE8\x11D\xBB}\xB5\x9BY\xF8pw\xA1\xE1\x13N\xF8\x9Ak\xD8\xF0=\xA8\xB7\xB1m)o\n\xF2\x91\xCC\xEC\xEC^\x82\x01\xE2#x\x9B\xAC\x19\x12\xC1N\xAB\r \x16\x17\xA4\x9AO\xA2(\x9A\x04\x0Fb\x06,\xDAg\xA1a\v\xB9y\x88\xBCk[o\x97\v\x94hX\xA2\x10\xE2\xC4\xDE\xF3\xA1\xF8\xAD\xB7\xBEZ\x81\xC0\xD1^\x05{\xC0\xFB\xC7\xBC?\xBC\xAF\xCD\xC7\xEEkvu\xD0\xD2\xE8eN\xEF:\xDBy\x13\xDC\x86\xB6t\xB7;/\x8D\x7F\x8Ac\xDE\x8D\xA1U\x06oef \x04ol\x89\xD8\xD0\xF0\xFF[\x01\xD4\xEC7\x9F~\xFA\xE1\xD3?,q;\xFC?$\xF7\x89\xD2"
|
11
|
+
|
12
|
+
def self.latex_escape(s)
|
13
|
+
s.gsub(/\\|~|[#%&{}$_]/) do |m|
|
14
|
+
case m
|
15
|
+
when "\\"
|
16
|
+
"\\textbackslash{}"
|
17
|
+
when "~"
|
18
|
+
"\\textasciitilde{}"
|
19
|
+
else
|
20
|
+
"\\#{m}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module SequenceDiagramMixin
|
2
|
+
def htmlify(*args)
|
3
|
+
res = super
|
4
|
+
res = res.gsub(/<pre class="[^"]+? sd"><code>(.+?)<\/code><\/pre>/m, "\\1")
|
5
|
+
res
|
6
|
+
end
|
7
|
+
|
8
|
+
def html_syntax_highlight_sd(source)
|
9
|
+
lines = source.split("\n")
|
10
|
+
metadata = lines.take_while {|l| l.start_with?("%")}
|
11
|
+
source = lines[metadata.size..-1].join("\n")
|
12
|
+
|
13
|
+
metadata_h = {}
|
14
|
+
metadata.each do |line|
|
15
|
+
if line =~ /^%\s*([^\s=]+)\s*=\s*(.+)$/
|
16
|
+
key = $1.to_sym
|
17
|
+
|
18
|
+
case key
|
19
|
+
when :size
|
20
|
+
metadata_h[key] = $2
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
begin
|
26
|
+
diagram = SequenceDiagram::Diagram.new.parse(source)
|
27
|
+
img = diagram.to_png(metadata_h)
|
28
|
+
name = "images/diagrams/diagram_#{diagram.uid}.png"
|
29
|
+
options[:serializer].serialize(name, img)
|
30
|
+
|
31
|
+
return "<img src='%s' alt='Sequence diagram' />" % url_for(name)
|
32
|
+
rescue SequenceDiagram::ParseError => e
|
33
|
+
return "Error: Parsing error: #{h(e.inspect)}"
|
34
|
+
rescue => e
|
35
|
+
return "Error: #{h(e.backtrace.inspect)}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
YARD::Templates::Template.extra_includes << SequenceDiagramMixin
|
data/lib/yard-sd.rb
ADDED
metadata
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: yard-sd
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Dominik Honnef
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-02-01 00:00:00.000000000 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
description:
|
16
|
+
email:
|
17
|
+
- dominikh@fork-bomb.org
|
18
|
+
executables: []
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- LICENSE
|
23
|
+
- README.md
|
24
|
+
- Example.md
|
25
|
+
- lib/yard-sd/sequence_diagram.rb
|
26
|
+
- lib/yard-sd/sequence_diagram_mixin.rb
|
27
|
+
- lib/yard-sd/sequence_diagram/participant.rb
|
28
|
+
- lib/yard-sd/sequence_diagram/parse_error.rb
|
29
|
+
- lib/yard-sd/sequence_diagram/diagram.rb
|
30
|
+
- lib/yard-sd.rb
|
31
|
+
has_rdoc: true
|
32
|
+
homepage:
|
33
|
+
licenses: []
|
34
|
+
post_install_message:
|
35
|
+
rdoc_options: []
|
36
|
+
require_paths:
|
37
|
+
- lib
|
38
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.9.1
|
44
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
45
|
+
none: false
|
46
|
+
requirements:
|
47
|
+
- - ! '>='
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
requirements: []
|
51
|
+
rubyforge_project:
|
52
|
+
rubygems_version: 1.6.2
|
53
|
+
signing_key:
|
54
|
+
specification_version: 3
|
55
|
+
summary: A YARD plugin for embedding sequence diagrams
|
56
|
+
test_files: []
|