Class diagram can be rendered as object diagram textual syntax, and parsed back, without information loss

This commit is contained in:
Joeri Exelmans 2024-10-03 17:01:13 +02:00
parent f45872d3f7
commit 175edb64d9
14 changed files with 505 additions and 249 deletions

View file

@ -52,11 +52,6 @@ class OD:
return object_node
# def read_slot_boolean(self, obj_node: str, attr_name: str):
# slot = self.get_slot(obj_node, attr_name)
# if slot != None:
# return Boolean(slot, self.bottom.state).read()
def get_class_of_object(self, object_name: str):
object_node, = self.bottom.read_outgoing_elements(self.model, object_name) # get the object
return self._get_class_of_object(object_node)
@ -73,9 +68,10 @@ class OD:
class_name = self.get_class_of_object(object_name)
attr_link_name = get_attr_link_name(class_name, attr_name)
# An attribute-link is indistinguishable from an ordinary link:
return self.create_link(
slot_id = self.create_link(
get_attr_link_name(object_name, attr_name),
attr_link_name, object_name, target_name)
return slot_id
def get_slot(self, object_node: UUID, attr_name: str):
# I really don't like how complex and inefficient it is to read an attribute of an object...
@ -86,8 +82,23 @@ class OD:
if type_edge in self.bottom.read_outgoing_elements(outgoing_edge, "Morphism"):
slot_ref = self.bottom.read_edge_target(outgoing_edge)
return slot_ref
# slot_node = UUID(self.bottom.read_value(slot_ref))
# return slot_node
def get_slots(self, object_node):
attrlink_node = get_scd_mm_attributelink_node(self.bottom)
slots = []
outgoing_links = self.bottom.read_outgoing_edges(object_node)
for l in outgoing_links:
for type_of_link in self.bottom.read_outgoing_elements(l, "Morphism"):
for type_of_type_of_link in self.bottom.read_outgoing_elements(type_of_link, "Morphism"):
if type_of_type_of_link == attrlink_node:
# hooray, we have a slot
attr_name = get_attr_name(self.bottom, type_of_link)
slots.append((attr_name, l))
return slots
def read_slot(self, slot_id):
tgt = self.bottom.read_edge_target(slot_id)
return read_primitive_value(self.bottom, tgt, self.type_model)
def create_integer_value(self, name: str, value: int):
from services.primitives.integer_type import Integer
@ -99,6 +110,16 @@ class OD:
self.create_model_ref(name, "Integer", int_node)
return name
def create_boolean_value(self, name: str, value: bool):
from services.primitives.boolean_type import Boolean
bool_node = self.bottom.create_node()
bool_service = Boolean(bool_node, self.bottom.state)
bool_service.create(value)
# name = 'int'+str(value) # name of the ref to the created integer
# By convention, the type model must have a ModelRef named "Integer"
self.create_model_ref(name, "Boolean", bool_node)
return name
def create_string_value(self, name: str, value: str):
from services.primitives.string_type import String
string_node = self.bottom.create_node()
@ -132,10 +153,10 @@ class OD:
i += 1
type_edge, = self.bottom.read_outgoing_elements(self.type_model, assoc_name)
link_id = self._create_link(link_name, type_edge, src_obj_node, tgt_obj_node)
return link_id
return self._create_link(link_name, type_edge, src_obj_node, tgt_obj_node)
def _create_link(self, link_name: str, type_edge: str, src_obj_node: UUID, tgt_obj_node: UUID):
def _create_link(self, link_name: str, type_edge: UUID, src_obj_node: UUID, tgt_obj_node: UUID):
# the link itself is unlabeled:
link_edge = self.bottom.create_edge(src_obj_node, tgt_obj_node)
# it is only in the context of the model, that the link has a name:
@ -146,6 +167,33 @@ class OD:
def get_objects(self, class_node):
return get_typed_by(self.bottom, self.model, class_node)
def get_all_objects(self):
scd_mm = get_scd_mm(self.bottom)
class_node = get_scd_mm_class_node(self.bottom)
all_classes = OD(scd_mm, self.type_model, self.bottom.state).get_objects(class_node)
result = {}
for class_name, class_node in all_classes.items():
objects = self.get_objects(class_node)
result[class_name] = objects
return result
def get_all_links(self):
scd_mm = get_scd_mm(self.bottom)
assoc_node = get_scd_mm_assoc_node(self.bottom)
all_classes = OD(scd_mm, self.type_model, self.bottom.state).get_objects(assoc_node)
result = {}
for assoc_name, assoc_node in all_classes.items():
links = self.get_objects(assoc_node)
m = {}
for link_name, link_edge in links.items():
src_node = self.bottom.read_edge_source(link_edge)
tgt_node = self.bottom.read_edge_target(link_edge)
src_name = get_object_name(self.bottom, self.model, src_node)
tgt_name = get_object_name(self.bottom, self.model, tgt_node)
m[link_name] = (link_edge, src_name, tgt_name)
result[assoc_name] = m
return result
def get_object_name(self, obj: UUID):
for key in self.bottom.read_keys(self.model):
for el in self.bottom.read_outgoing_elements(self.model, key):
@ -224,6 +272,10 @@ def get_object_name(bottom: Bottom, model: UUID, object_node: UUID):
if el == object_node:
return key
def get_type2(bottom: Bottom, mm: UUID, object_node: UUID):
type_node, = bottom.read_outgoing_elements(object_node, "Morphism")
return type_node, get_object_name(bottom, mm, type_node)
def find_outgoing_typed_by(bottom, src: UUID, type_node: UUID):
edges = []
for outgoing_edge in bottom.read_outgoing_edges(src):

View file

@ -43,7 +43,7 @@ class SCD:
_c_node = self.bottom.create_node(str(_c_model)) # store UUID of primitive value model
self.bottom.create_edge(self.model, _c_node, f"{name}.{bound}_cardinality") # link to model root
_c_link = self.bottom.create_edge(class_node, _c_node) # link class to attribute
self.bottom.create_edge(self.model, _c_link, f"{name}.{bound}_cardinality_link") # link attr link to model root
self.bottom.create_edge(self.model, _c_link, f"{name}_{bound}_cardinality") # link attr link to model root
# retrieve types from metamodel
_scd_node, = self.bottom.read_outgoing_elements(self.scd_model, "Integer")
_scd_link, = self.bottom.read_outgoing_elements(self.scd_model, f"Class_{bound}_cardinality")
@ -63,7 +63,7 @@ class SCD:
abstract_node = self.bottom.create_node(str(abstract_model))
self.bottom.create_edge(self.model, abstract_node, f"{name}.abstract")
abstract_link = self.bottom.create_edge(class_node, abstract_node)
self.bottom.create_edge(self.model, abstract_link, f"{name}.abstract_link")
self.bottom.create_edge(self.model, abstract_link, f"{name}_abstract")
scd_node, = self.bottom.read_outgoing_elements(self.scd_model, "Boolean")
scd_link, = self.bottom.read_outgoing_elements(self.scd_model, "Class_abstract")
self.bottom.create_edge(abstract_node, scd_node, "Morphism")
@ -110,7 +110,7 @@ class SCD:
_c_node = self.bottom.create_node(str(_c_model))
self.bottom.create_edge(self.model, _c_node, f"{name}.{bound}_cardinality")
_c_link = self.bottom.create_edge(assoc_edge, _c_node)
self.bottom.create_edge(self.model, _c_link, f"{name}.{bound}_cardinality_link")
self.bottom.create_edge(self.model, _c_link, f"{name}_{bound}_cardinality")
_scd_node, = self.bottom.read_outgoing_elements(self.scd_model, "Integer")
_scd_link, = self.bottom.read_outgoing_elements(self.scd_model, f"Association_{bound}_cardinality")
self.bottom.create_edge(_c_node, _scd_node, "Morphism")
@ -193,7 +193,7 @@ class SCD:
name_node = self.bottom.create_node(str(name_model))
self.bottom.create_edge(self.model, name_node, f"{source}_{name}.name")
name_link = self.bottom.create_edge(assoc_edge, name_node)
self.bottom.create_edge(self.model, name_link, f"{source}_{name}.name_link")
self.bottom.create_edge(self.model, name_link, f"{source}_{name}_name")
scd_node, = self.bottom.read_outgoing_elements(self.scd_model, "String")
scd_link, = self.bottom.read_outgoing_elements(self.scd_model, "AttributeLink_name")
self.bottom.create_edge(name_node, scd_node, "Morphism")
@ -205,7 +205,7 @@ class SCD:
optional_node = self.bottom.create_node(str(optional_model))
self.bottom.create_edge(self.model, optional_node, f"{source}_{name}.optional")
optional_link = self.bottom.create_edge(assoc_edge, optional_node)
self.bottom.create_edge(self.model, optional_link, f"{source}_{name}.optional_link")
self.bottom.create_edge(self.model, optional_link, f"{source}_{name}_optional")
scd_node, = self.bottom.read_outgoing_elements(self.scd_model, "Boolean")
scd_link, = self.bottom.read_outgoing_elements(self.scd_model, "AttributeLink_optional")
self.bottom.create_edge(optional_node, scd_node, "Morphism")
@ -278,7 +278,7 @@ class SCD:
code_node = self.bottom.create_node(code)
self.bottom.create_edge(self.model, code_node, f"{element}.constraint")
code_link = self.bottom.create_edge(element_node, code_node)
self.bottom.create_edge(self.model, code_link, f"{element}.constraint_link")
self.bottom.create_edge(self.model, code_link, f"{element}_constraint")
scd_node, = self.bottom.read_outgoing_elements(self.scd_model, "ActionCode")
scd_link, = self.bottom.read_outgoing_elements(self.scd_model, "Element_constraint")
self.bottom.create_edge(code_node, scd_node, "Morphism")