initial commit
This commit is contained in:
BIN
misc/uml/main.pdf
Normal file
BIN
misc/uml/main.pdf
Normal file
Binary file not shown.
104
misc/uml/main.typ
Normal file
104
misc/uml/main.typ
Normal file
@ -0,0 +1,104 @@
|
||||
#import "uml.typ"
|
||||
|
||||
#set page(width: auto, height: auto, margin: 1cm)
|
||||
|
||||
#uml.diagram({
|
||||
import uml: *
|
||||
|
||||
class("Person", abstract, {
|
||||
attr("name", "str")
|
||||
attr("phoneNumber", "str")
|
||||
attr("emailAddress", "str")
|
||||
method("purchaseParkingPass")
|
||||
})
|
||||
class("Address", {
|
||||
attr("street", "str")
|
||||
attr("city", "str")
|
||||
attr("state", "str")
|
||||
attr("postalCode", "int")
|
||||
attr("country", "str")
|
||||
method("validate", "bool", private)
|
||||
method("outputAsLabel", "str")
|
||||
})
|
||||
class("Student", {
|
||||
attr("studentNumber", "int")
|
||||
attr("averageMark", "int")
|
||||
method("isEligibleToEnroll", "bool", ("str",))
|
||||
method("getSeminarsTaken", "int")
|
||||
})
|
||||
class("Professor", {
|
||||
attr("salary", "int", package)
|
||||
attr("staffNumber", "int", protected)
|
||||
attr("yearsOfService", "int", private)
|
||||
attr("numberOfClasses", "int")
|
||||
})
|
||||
})
|
||||
|
||||
#pagebreak()
|
||||
|
||||
#uml.diagram({
|
||||
import uml: *
|
||||
|
||||
class("Pageable", interface, {
|
||||
attr("UNKNOWN_N_OF_PAGES", "int", default: -1)
|
||||
})
|
||||
|
||||
class("SQLStatement", {
|
||||
method("executeQuery", "ResultSet", (sql: "String"))
|
||||
method("isPoolable", "Boolean")
|
||||
method("getQueryTimeout", "int")
|
||||
method("clearWarnings")
|
||||
})
|
||||
|
||||
class("SearchService", {
|
||||
attr("config", "Configuration", private)
|
||||
attr("engine", "SearchEngine", private)
|
||||
method("search", "SearchResult", (query: "SearchRequest"))
|
||||
method("createEngine", "SearchEngine", private, static)
|
||||
})
|
||||
|
||||
class("SearchService", grouped: true, {
|
||||
attr("config", "Configuration", private)
|
||||
attr("engine", "SearchEngine", private)
|
||||
method("search", "SearchResult", (query: "SearchRequest"))
|
||||
method("createEngine", "SearchEngine", private, static)
|
||||
})
|
||||
})
|
||||
|
||||
#pagebreak()
|
||||
|
||||
#import "parser.typ": parse
|
||||
#parse(```
|
||||
@class-grouped=true
|
||||
class Button {
|
||||
-theController : Controller*
|
||||
+press() : void
|
||||
+setTheController(p : Controller*) : void
|
||||
}
|
||||
|
||||
abstract class Controller {
|
||||
-theLight : Light*
|
||||
-lampState : boolean
|
||||
+evButtonPressed() : void
|
||||
+setTheLight(p : Light*) : void
|
||||
-toggle() : void
|
||||
}
|
||||
|
||||
class Light {
|
||||
+on() : void
|
||||
+off() : void
|
||||
}
|
||||
```)
|
||||
|
||||
#pagebreak()
|
||||
|
||||
#parse(```
|
||||
class City {
|
||||
+resources: HashMap[ResourceType, Int]
|
||||
+globalHappiness: Double
|
||||
}
|
||||
|
||||
abstract class Building {
|
||||
+getResourcesOnBuilt(): HashMap[ResourceType, Int]
|
||||
}
|
||||
```)
|
94
misc/uml/parser.typ
Normal file
94
misc/uml/parser.typ
Normal file
@ -0,0 +1,94 @@
|
||||
#import "uml.typ"
|
||||
|
||||
#let parse-args(data) = {
|
||||
let args = data.split(",").map(a => a.trim()).filter(a => a.len() != 0)
|
||||
let res
|
||||
if ":" in data {
|
||||
res = (:)
|
||||
} else {
|
||||
res = ()
|
||||
}
|
||||
|
||||
for arg in args {
|
||||
let parts = arg.split(":")
|
||||
let arg-name = none
|
||||
let arg-type
|
||||
if parts.len() == 1 {
|
||||
if type(res) == dictionary {
|
||||
panic("Cannot mix named and unnamed arguments")
|
||||
}
|
||||
arg-type = parts.first().trim()
|
||||
res.push(arg-type)
|
||||
} else {
|
||||
arg-name = parts.first().trim()
|
||||
arg-type = parts.slice(1).join(":").trim()
|
||||
res.insert(arg-name, arg-type)
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
#let parse(data) = {
|
||||
let elements = ()
|
||||
|
||||
if type(data) == raw or type(data) == content {
|
||||
data = data.text
|
||||
}
|
||||
|
||||
let classes = data.matches(regex("(?ms)(abstract class|class|interface) (.*?)\s*\{(.*?)\}"))
|
||||
|
||||
for class in classes {
|
||||
let family-name = class.captures.first()
|
||||
let family = (
|
||||
class: none,
|
||||
"abstract class": uml.abstract,
|
||||
"interface": uml.interface,
|
||||
"enum": uml.enum,
|
||||
).at(family-name)
|
||||
|
||||
let name = class.captures.at(1)
|
||||
let class-data = class.captures.last().trim()
|
||||
|
||||
let members = class-data.matches(regex("(?m)^\s*(.*?)\s*(:\s*([^:]*?))?$")).filter(m => m.text.len() != 0)
|
||||
let attributes = ()
|
||||
let methods = ()
|
||||
for member in members {
|
||||
let member-name = member.captures.first()
|
||||
let val-type = member.captures.last()
|
||||
let visibility = none
|
||||
|
||||
if member-name.starts-with(regex("\+|-|~|#")) {
|
||||
let vis = member-name.first()
|
||||
member-name = member-name.slice(1)
|
||||
visibility = (
|
||||
"+": uml.public,
|
||||
"-": uml.private,
|
||||
"~": uml.package,
|
||||
"#": uml.protected
|
||||
).at(vis)
|
||||
}
|
||||
|
||||
if member-name.ends-with(")") {
|
||||
let func = member-name.match(regex("^(.*?)\((.*)\)$"))
|
||||
member-name = func.captures.first()
|
||||
let args = parse-args(func.captures.last())
|
||||
methods += uml.method(member-name, visibility, val-type, args)
|
||||
} else {
|
||||
attributes += uml.attr(member-name, visibility, val-type)
|
||||
}
|
||||
}
|
||||
|
||||
elements += uml.class(name, family, attributes + methods)
|
||||
}
|
||||
|
||||
let defaults = (:)
|
||||
let params = data.matches(regex("(?m)^\s*@\s*(.*?)\s*=\s*(.*)\s*$"))
|
||||
for param in params {
|
||||
let key = param.captures.first()
|
||||
let value = eval(param.captures.last(), scope: (uml: uml))
|
||||
defaults.insert(key, value)
|
||||
}
|
||||
|
||||
return uml.diagram(elements, defaults)
|
||||
}
|
569
misc/uml/uml.typ
Normal file
569
misc/uml/uml.typ
Normal file
@ -0,0 +1,569 @@
|
||||
#import "@preview/cetz:0.2.2": canvas, draw
|
||||
|
||||
#let class-counter = counter("uml-class")
|
||||
|
||||
#let class-colors = (
|
||||
rgb("#C02B22"),
|
||||
rgb("#D4721C"),
|
||||
rgb("D3BC2F"),
|
||||
rgb("60CB12"),
|
||||
rgb("#2ECC40"),
|
||||
rgb("#39CCA5"),
|
||||
rgb("#38B4DA"),
|
||||
rgb("#0074d9"),
|
||||
rgb("#450DC9"),
|
||||
rgb("#890DC9"),
|
||||
)
|
||||
|
||||
#let visibility(vis, symbol) = (type: "visibility", visibility: vis, symbol: symbol)
|
||||
|
||||
#let public = visibility("public", "+")
|
||||
#let private = visibility("private", "-")
|
||||
#let protected = visibility("protected", "#")
|
||||
#let package = visibility("package", "~")
|
||||
|
||||
#let class-family(family, prefix: none) = (
|
||||
type: "class-family",
|
||||
family: family,
|
||||
prefix: prefix
|
||||
)
|
||||
#let abstract = class-family("abstract")
|
||||
#let interface = class-family("interface", prefix: "interface")
|
||||
#let trait = class-family("trait")
|
||||
#let enum = class-family("enum")
|
||||
#let utility = class-family("utility", prefix: "utility")
|
||||
|
||||
#let staticity(static) = (type: "staticity", static: static)
|
||||
#let static = staticity(true)
|
||||
#let non-static = staticity(false)
|
||||
|
||||
#let class(name, ..args, grouped: none) = {
|
||||
let attributes = ()
|
||||
let methods = ()
|
||||
let visibility = none
|
||||
let family = none
|
||||
|
||||
let args = args.pos()
|
||||
if args.len() != 0 {
|
||||
for arg in args {
|
||||
if type(arg) == dictionary {
|
||||
if arg.type == "visibility" {
|
||||
visibility = arg
|
||||
} else if arg.type == "class-family" {
|
||||
family = arg
|
||||
}
|
||||
} else if type(arg) == array {
|
||||
for elmt in arg {
|
||||
if type(elmt) == dictionary {
|
||||
if elmt.type == "visibility" {
|
||||
visibility = elmt
|
||||
} else if elmt.type == "attribute" {
|
||||
attributes.push(elmt)
|
||||
} else if elmt.type == "method" {
|
||||
methods.push(elmt)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ((
|
||||
type: "class",
|
||||
name: name,
|
||||
visibility: visibility,
|
||||
family: family,
|
||||
attributes: attributes,
|
||||
methods: methods,
|
||||
color: rgb(184, 84, 80),
|
||||
grouped: grouped
|
||||
),)
|
||||
}
|
||||
|
||||
#let attr(name, default: none, ..args) = {
|
||||
let visibility = none
|
||||
let staticity = none
|
||||
let val-type = none
|
||||
for arg in args.pos() {
|
||||
if type(arg) == dictionary {
|
||||
if arg.type == "visibility" {
|
||||
visibility = arg
|
||||
} else if arg.type == "type" {
|
||||
val-type = arg
|
||||
} else if arg.type == "staticity" {
|
||||
staticity = staticity
|
||||
}
|
||||
} else if type(arg) == str {
|
||||
val-type = arg
|
||||
}
|
||||
}
|
||||
return ((
|
||||
type: "attribute",
|
||||
name: name,
|
||||
visibility: visibility,
|
||||
staticity: staticity,
|
||||
val-type: val-type,
|
||||
default: default
|
||||
),)
|
||||
}
|
||||
|
||||
#let method(name, ..args) = {
|
||||
let visibility = none
|
||||
let staticity = none
|
||||
let parameters = none
|
||||
let return-type = none
|
||||
|
||||
for arg in args.pos() {
|
||||
if type(arg) == dictionary {
|
||||
if "type" in arg {
|
||||
if arg.type == "visibility" {
|
||||
visibility = arg
|
||||
} else if arg.type == "staticity" {
|
||||
staticity = arg
|
||||
}
|
||||
} else {
|
||||
parameters = arg
|
||||
}
|
||||
} else if type(arg) == str {
|
||||
return-type = arg
|
||||
} else if type(arg) == array {
|
||||
parameters = arg
|
||||
}
|
||||
}
|
||||
return ((
|
||||
type: "method",
|
||||
name: name,
|
||||
visibility: visibility,
|
||||
staticity: staticity,
|
||||
parameters: parameters,
|
||||
return-type: return-type
|
||||
),)
|
||||
}
|
||||
|
||||
#let render-attr(attr, defaults, show-visibility: true) = {
|
||||
let visibility = if attr.visibility == none {
|
||||
defaults.attr-visibility
|
||||
} else {
|
||||
attr.visibility
|
||||
}
|
||||
let staticity = if attr.staticity == none {
|
||||
defaults.attr-staticity
|
||||
} else {
|
||||
attr.staticity
|
||||
}
|
||||
|
||||
let name = attr.name
|
||||
if staticity.static {
|
||||
name = underline(name)
|
||||
}
|
||||
let txt = name
|
||||
if show-visibility {
|
||||
txt = visibility.symbol + txt
|
||||
}
|
||||
|
||||
if attr.val-type != none {
|
||||
txt += ": " + attr.val-type
|
||||
}
|
||||
if attr.default != none {
|
||||
txt += " = " + str(attr.default)
|
||||
}
|
||||
return txt
|
||||
}
|
||||
|
||||
#let render-method(method, defaults, show-visibility: true) = {
|
||||
let visibility = if method.visibility == none {
|
||||
defaults.method-visibility
|
||||
} else {
|
||||
method.visibility
|
||||
}
|
||||
let staticity = if method.staticity == none {
|
||||
defaults.method-staticity
|
||||
} else {
|
||||
method.staticity
|
||||
}
|
||||
let params = ()
|
||||
|
||||
if type(method.parameters) == array {
|
||||
params = method.parameters
|
||||
} else if type(method.parameters) == dictionary {
|
||||
params = method.parameters
|
||||
.pairs()
|
||||
.map(((n, t)) => n + ": " + t)
|
||||
}
|
||||
|
||||
let name = method.name
|
||||
if staticity.static {
|
||||
name = underline(name)
|
||||
}
|
||||
let txt = name
|
||||
if show-visibility {
|
||||
txt = visibility.symbol + txt
|
||||
}
|
||||
txt += "(" + params.join(", ") + ")"
|
||||
if method.return-type != none {
|
||||
txt += ": " + method.return-type
|
||||
}
|
||||
|
||||
return txt
|
||||
}
|
||||
|
||||
#let get-attributes-by-visibility(class, defaults) = {
|
||||
let by-vis = (:)
|
||||
for attr in class.attributes {
|
||||
let visibility = if attr.visibility == none {
|
||||
defaults.attr-visibility
|
||||
} else {
|
||||
attr.visibility
|
||||
}
|
||||
if not visibility.visibility in by-vis {
|
||||
by-vis.insert(visibility.visibility, ())
|
||||
}
|
||||
by-vis.at(visibility.visibility).push(attr)
|
||||
}
|
||||
return by-vis
|
||||
}
|
||||
|
||||
#let get-methods-by-visibility(class, defaults) = {
|
||||
let by-vis = (:)
|
||||
for method in class.methods {
|
||||
let visibility = if method.visibility == none {
|
||||
defaults.method-visibility
|
||||
} else {
|
||||
method.visibility
|
||||
}
|
||||
if not visibility.visibility in by-vis {
|
||||
by-vis.insert(visibility.visibility, ())
|
||||
}
|
||||
by-vis.at(visibility.visibility).push(method)
|
||||
}
|
||||
return by-vis
|
||||
}
|
||||
|
||||
#let render-class-attributes(class, defaults) = {
|
||||
let grouped = if class.grouped == none {
|
||||
defaults.class-grouped
|
||||
} else {
|
||||
class.grouped
|
||||
}
|
||||
let cells = ()
|
||||
|
||||
if not grouped {
|
||||
for attr in class.attributes {
|
||||
cells.push(render-attr(attr, defaults, show-visibility: true))
|
||||
}
|
||||
} else {
|
||||
let by-vis = get-attributes-by-visibility(class, defaults)
|
||||
for (vis, attrs) in by-vis {
|
||||
cells.push(table.cell(vis + ":"))
|
||||
cells += attrs.map(attr => {
|
||||
let txt = render-attr(attr, defaults, show-visibility: false)
|
||||
pad(left: 1em, txt)
|
||||
})
|
||||
}
|
||||
}
|
||||
return cells
|
||||
}
|
||||
|
||||
#let render-class-methods(class, defaults) = {
|
||||
let grouped = if class.grouped == none {
|
||||
defaults.class-grouped
|
||||
} else {
|
||||
class.grouped
|
||||
}
|
||||
let cells = ()
|
||||
|
||||
if not grouped {
|
||||
for method in class.methods {
|
||||
cells.push(render-method(method, defaults, show-visibility: true))
|
||||
}
|
||||
} else {
|
||||
let by-vis = get-methods-by-visibility(class, defaults)
|
||||
for (vis, attrs) in by-vis {
|
||||
cells.push(table.cell(vis + ":"))
|
||||
cells += attrs.map(method => {
|
||||
let txt = render-method(method, defaults, show-visibility: false)
|
||||
pad(left: 1em, txt)
|
||||
})
|
||||
}
|
||||
}
|
||||
return cells
|
||||
}
|
||||
|
||||
#let render-class(class, defaults) = context {
|
||||
let family = if class.family == none {
|
||||
defaults.class-family
|
||||
} else {
|
||||
class.family
|
||||
}
|
||||
|
||||
let cells = ()
|
||||
cells += render-class-attributes(class, defaults)
|
||||
|
||||
cells.push(table.hline())
|
||||
|
||||
cells += render-class-methods(class, defaults)
|
||||
|
||||
let name = [*#class.name*]
|
||||
let family = class.family
|
||||
if family == abstract {
|
||||
name = emph(name)
|
||||
}
|
||||
if family != none and family.prefix != none {
|
||||
name = [*«#family.prefix»*\ #name]
|
||||
}
|
||||
let class-i = class-counter.get().first()
|
||||
let col = class-colors.at(calc.rem(class-i, class-colors.len()))
|
||||
|
||||
set table.hline(stroke: col)
|
||||
table(
|
||||
inset: (top: 0.5em, bottom: 0.5em, left: 0.5em, right: 0.5em),
|
||||
stroke: (x, y) => {
|
||||
let s = (left: col, right: col)
|
||||
if y == 0 {
|
||||
s.insert("top", col)
|
||||
s.insert("bottom", col)
|
||||
}
|
||||
return s
|
||||
},
|
||||
align: (x, y) => {
|
||||
if y == 0 {
|
||||
return center + horizon
|
||||
}
|
||||
return left + horizon
|
||||
},
|
||||
fill: (x, y) => if y == 0 {
|
||||
col.lighten(75%)
|
||||
} else {
|
||||
none
|
||||
},
|
||||
table.header(name),
|
||||
..cells,
|
||||
table.hline()
|
||||
)
|
||||
class-counter.step()
|
||||
}
|
||||
|
||||
#let diagram(..args) = {
|
||||
class-counter.update(0)
|
||||
|
||||
let args = args.pos()
|
||||
|
||||
let defaults = (
|
||||
class-family: none,
|
||||
class-grouped: false,
|
||||
attr-visibility: public,
|
||||
attr-staticity: non-static,
|
||||
method-visibility: public,
|
||||
method-staticity: non-static,
|
||||
)
|
||||
let elements = ()
|
||||
if args.len() != 0 {
|
||||
for arg in args {
|
||||
if type(arg) == dictionary {
|
||||
defaults += arg
|
||||
} else if type(arg) == array {
|
||||
elements = arg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let cells = ()
|
||||
for element in elements {
|
||||
if element.type == "class" {
|
||||
cells.push(render-class(element, defaults))
|
||||
}
|
||||
}
|
||||
box(
|
||||
stroke: black,
|
||||
inset: 1em,
|
||||
grid(
|
||||
columns: 2,
|
||||
column-gutter: 1em,
|
||||
align: center + horizon,
|
||||
row-gutter: 1em,
|
||||
..cells
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
#let render-attr2(pos, id, attr, defaults, show-visibility: true) = {
|
||||
let visibility = if attr.visibility == none {
|
||||
defaults.attr-visibility
|
||||
} else {
|
||||
attr.visibility
|
||||
}
|
||||
let staticity = if attr.staticity == none {
|
||||
defaults.attr-staticity
|
||||
} else {
|
||||
attr.staticity
|
||||
}
|
||||
|
||||
let name = attr.name
|
||||
if staticity.static {
|
||||
name = underline(name)
|
||||
}
|
||||
let txt = name
|
||||
if show-visibility {
|
||||
txt = visibility.symbol + txt
|
||||
}
|
||||
|
||||
if attr.val-type != none {
|
||||
txt += ": " + attr.val-type
|
||||
}
|
||||
if attr.default != none {
|
||||
txt += " = " + str(attr.default)
|
||||
}
|
||||
|
||||
draw.content(pos, txt, name: id)
|
||||
}
|
||||
|
||||
#let render-method2(method, defaults, show-visibility: true) = {
|
||||
let visibility = if method.visibility == none {
|
||||
defaults.method-visibility
|
||||
} else {
|
||||
method.visibility
|
||||
}
|
||||
let staticity = if method.staticity == none {
|
||||
defaults.method-staticity
|
||||
} else {
|
||||
method.staticity
|
||||
}
|
||||
let params = ()
|
||||
|
||||
if type(method.parameters) == array {
|
||||
params = method.parameters
|
||||
} else if type(method.parameters) == dictionary {
|
||||
params = method.parameters
|
||||
.pairs()
|
||||
.map(((n, t)) => n + ": " + t)
|
||||
}
|
||||
|
||||
let name = method.name
|
||||
if staticity.static {
|
||||
name = underline(name)
|
||||
}
|
||||
let txt = name
|
||||
if show-visibility {
|
||||
txt = visibility.symbol + txt
|
||||
}
|
||||
txt += "(" + params.join(", ") + ")"
|
||||
if method.return-type != none {
|
||||
txt += ": " + method.return-type
|
||||
}
|
||||
|
||||
draw.content((), txt)
|
||||
}
|
||||
|
||||
#let render-class-attributes2(class, defaults) = {
|
||||
let grouped = if class.grouped == none {
|
||||
defaults.class-grouped
|
||||
} else {
|
||||
class.grouped
|
||||
}
|
||||
let cells = ()
|
||||
let prev = ()
|
||||
|
||||
if not grouped {
|
||||
for (i, attr) in class.attributes.enumerate() {
|
||||
let id = "class-"+class.name+"-attr-"+str(i)
|
||||
let txt = render-attr(attr, defaults, show-visibility: true)
|
||||
draw.content((rel: (0, -0.4em), to: prev), name: id, anchor: "north-west", txt)
|
||||
prev = id + ".south-west"
|
||||
}
|
||||
} else {
|
||||
let by-vis = get-attributes-by-visibility(class, defaults)
|
||||
for (vis, attrs) in by-vis {
|
||||
cells.push(table.cell(vis + ":"))
|
||||
let vis-id = "class-"+class.name+"-attrs-"+vis
|
||||
draw.content((rel: (0, -0.4em), to: prev), name: vis-id, anchor: "north-west", vis + ":")
|
||||
prev = vis-id + ".south-west"
|
||||
|
||||
for (i, attr) in attrs.enumerate() {
|
||||
let txt = render-attr(attr, defaults, show-visibility: false)
|
||||
txt = pad(left: 1em, txt)
|
||||
let id = vis-id + "-" + str(i)
|
||||
draw.content((rel: (0, -0.4em), to: prev), name: id, anchor: "north-west", txt)
|
||||
prev = id + ".south-west"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#let render-class-methods2(class, defaults) = {
|
||||
|
||||
}
|
||||
|
||||
#let render-class2(class, defaults) = {
|
||||
let attr-group = render-class-attributes2(class, defaults)
|
||||
let method-group = render-class-methods2(class, defaults)
|
||||
|
||||
let family = if class.family == none {
|
||||
defaults.class-family
|
||||
} else {
|
||||
class.family
|
||||
}
|
||||
let name = [*#class.name*]
|
||||
let family = class.family
|
||||
if family == abstract {
|
||||
name = emph(name)
|
||||
}
|
||||
if family != none and family.prefix != none {
|
||||
name = [*«#family.prefix»*\ #name]
|
||||
}
|
||||
let class-i = class-counter.get().first()
|
||||
let col = class-colors.at(calc.rem(class-i, class-colors.len()))
|
||||
|
||||
draw.group(name: "class-"+class.name, {
|
||||
draw.group(name: "class-"+class.name+"-name", padding: 5pt, {
|
||||
draw.content((), name)
|
||||
})
|
||||
draw.on-layer(-1, {
|
||||
draw.rect("class-"+class.name+"-name.north-west", "class-"+class.name+"-name.south-east", fill: col.lighten(75%), stroke: col, layer: -1)
|
||||
})
|
||||
draw.group(name: "class-"+class.name+"-attrs", padding: 0.2em, {
|
||||
attr-group
|
||||
})
|
||||
method-group
|
||||
})
|
||||
draw.rect("class-"+class.name+".north-west", "class-"+class.name+".south-east", stroke: col)
|
||||
}
|
||||
|
||||
#let render-class3(class, defaults) = {
|
||||
let id = "class-" + class.name
|
||||
return draw.content((rel: (3, 0), to: ()), render-class(class, defaults), name: id)
|
||||
}
|
||||
|
||||
|
||||
#let diagram2(..args) = context {
|
||||
class-counter.update(0)
|
||||
|
||||
let args = args.pos()
|
||||
|
||||
let defaults = (
|
||||
class-family: none,
|
||||
class-grouped: false,
|
||||
attr-visibility: public,
|
||||
attr-staticity: non-static,
|
||||
method-visibility: public,
|
||||
method-staticity: non-static,
|
||||
)
|
||||
let elements = ()
|
||||
if args.len() != 0 {
|
||||
for arg in args {
|
||||
if type(arg) == dictionary {
|
||||
defaults += arg
|
||||
} else if type(arg) == array {
|
||||
elements = arg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let cells = ()
|
||||
canvas({
|
||||
for element in elements {
|
||||
if element.type == "class" {
|
||||
render-class3(element, defaults)
|
||||
}
|
||||
}
|
||||
draw.line("class-Test", "class-Essai", mark: (end: "diamond", scale: 2))
|
||||
})
|
||||
}
|
Reference in New Issue
Block a user