Ejemplo: Servicios de Gaphor¶
In this example we’re doing something a little less trivial. In Gaphor, services are defined as entry points. Each service is a class, and takes parameters with names that match other services. This allows services to depend on other services.
Es algo parecido a esto:
# entry point name: my_service
class MyService:
...
# entry point name: my_other_service
class MyOtherService:
def __init__(self, my_service):
...
Carguemos primero los puntos de entrada.
from gaphor.entrypoint import load_entry_points
entry_points = load_entry_points("gaphor.services")
entry_points
{'auto_layout': gaphor.plugins.autolayout.pydot.AutoLayoutService,
'component_registry': gaphor.services.componentregistry.ComponentRegistry,
'console_window': gaphor.plugins.console.consolewindow.ConsoleWindow,
'diagram_align': gaphor.ui.diagramalign.DiagramAlign,
'diagram_export': gaphor.plugins.diagramexport.export.DiagramExport,
'diagrams': gaphor.ui.diagrams.Diagrams,
'element_dispatcher': gaphor.core.modeling.elementdispatcher.ElementDispatcher,
'element_editor': gaphor.ui.elementeditor.ElementEditor,
'element_factory': gaphor.core.modeling.elementfactory.ElementFactory,
'event_manager': gaphor.core.eventmanager.EventManager,
'export_menu': gaphor.ui.menufragment.MenuFragment,
'file_manager': gaphor.ui.filemanager.FileManager,
'html_report': gaphor.plugins.htmlreport.report.HtmlReportExport,
'main_window': gaphor.ui.mainwindow.MainWindow,
'model_browser': gaphor.ui.modelbrowser.ModelBrowser,
'model_changed': gaphor.ui.modelchanged.ModelChanged,
'modeling_language': gaphor.services.modelinglanguage.ModelingLanguageService,
'properties': gaphor.services.properties.Properties,
'recent_files': gaphor.ui.recentfiles.RecentFiles,
'recovery': gaphor.storage.recovery.Recovery,
'sanitizer': gaphor.UML.sanitizerservice.SanitizerService,
'toolbox': gaphor.ui.toolbox.Toolbox,
'tools_menu': gaphor.ui.menufragment.MenuFragment,
'undo_actions': gaphor.ui.undoactions.UndoActions,
'undo_manager': gaphor.services.undomanager.UndoManager}
Ahora vamos a crear un componente en nuestro modelo para cada servicio.
from gaphor import UML
from gaphor.core.modeling import ElementFactory
element_factory = ElementFactory()
def create_component(name):
c = element_factory.create(UML.Component)
c.name = name
return c
components = {name: create_component(name) for name in entry_points}
components
{'auto_layout': <gaphor.UML.uml.Component element 08c7ab2e-6710-11f1-910c-f688066edcb5>,
'component_registry': <gaphor.UML.uml.Component element 08c7aed0-6710-11f1-910c-f688066edcb5>,
'console_window': <gaphor.UML.uml.Component element 08c7b09c-6710-11f1-910c-f688066edcb5>,
'diagram_align': <gaphor.UML.uml.Component element 08c7b1dc-6710-11f1-910c-f688066edcb5>,
'diagram_export': <gaphor.UML.uml.Component element 08c7b33a-6710-11f1-910c-f688066edcb5>,
'diagrams': <gaphor.UML.uml.Component element 08c7b45c-6710-11f1-910c-f688066edcb5>,
'element_dispatcher': <gaphor.UML.uml.Component element 08c7b574-6710-11f1-910c-f688066edcb5>,
'element_editor': <gaphor.UML.uml.Component element 08c7b682-6710-11f1-910c-f688066edcb5>,
'element_factory': <gaphor.UML.uml.Component element 08c7b786-6710-11f1-910c-f688066edcb5>,
'event_manager': <gaphor.UML.uml.Component element 08c7b88a-6710-11f1-910c-f688066edcb5>,
'export_menu': <gaphor.UML.uml.Component element 08c7b984-6710-11f1-910c-f688066edcb5>,
'file_manager': <gaphor.UML.uml.Component element 08c7ba88-6710-11f1-910c-f688066edcb5>,
'html_report': <gaphor.UML.uml.Component element 08c7bb82-6710-11f1-910c-f688066edcb5>,
'main_window': <gaphor.UML.uml.Component element 08c7bc7c-6710-11f1-910c-f688066edcb5>,
'model_browser': <gaphor.UML.uml.Component element 08c7beac-6710-11f1-910c-f688066edcb5>,
'model_changed': <gaphor.UML.uml.Component element 08c7c06e-6710-11f1-910c-f688066edcb5>,
'modeling_language': <gaphor.UML.uml.Component element 08c7c190-6710-11f1-910c-f688066edcb5>,
'properties': <gaphor.UML.uml.Component element 08c7c29e-6710-11f1-910c-f688066edcb5>,
'recent_files': <gaphor.UML.uml.Component element 08c7c3ac-6710-11f1-910c-f688066edcb5>,
'recovery': <gaphor.UML.uml.Component element 08c7c4d8-6710-11f1-910c-f688066edcb5>,
'sanitizer': <gaphor.UML.uml.Component element 08c7c5f0-6710-11f1-910c-f688066edcb5>,
'toolbox': <gaphor.UML.uml.Component element 08c7c6ea-6710-11f1-910c-f688066edcb5>,
'tools_menu': <gaphor.UML.uml.Component element 08c7c7f8-6710-11f1-910c-f688066edcb5>,
'undo_actions': <gaphor.UML.uml.Component element 08c7c8f2-6710-11f1-910c-f688066edcb5>,
'undo_manager': <gaphor.UML.uml.Component element 08c7c9e2-6710-11f1-910c-f688066edcb5>}
Con todos los componentes mapeados, podemos crear dependencias entre esos componentes, basándonos en los nombres de los parámetros del constructor.
import inspect
for name, cls in entry_points.items():
for param_name in inspect.signature(cls).parameters:
if param_name not in components:
continue
dep = element_factory.create(UML.Usage)
dep.client = components[name]
dep.supplier = components[param_name]
Con todos los elementos en el modelo, podemos crear un diagrama. Vamos a soltar los componentes y las dependencias en el diagrama y dejar que el diseño automático haga su magia.
Para que la dependencia se vea bien, tenemos que añadir una hoja de estilo. Si crea un diagrama nuevo a través de la interfaz gráfica de usuario, este elemento se añade automáticamente.
from gaphor.core.modeling import StyleSheet
from gaphor.diagram.drop import drop
element_factory.create(StyleSheet)
diagram = element_factory.create(UML.Diagram)
for element in element_factory.lselect():
drop(element, diagram, x=0, y=0)
El último paso consiste en maquetar y dibujar el diagrama.
from gaphor.extensions.ipython import auto_layout, draw
auto_layout(diagram)
draw(diagram, format="svg")
Eso es todo. Como puede ver en el diagrama, muchos servicios dependen de EventManager.