yard-sd 0.0.1
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.
- 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: []
|