opentool.exe Main=umlLa configuration méthodologique comporte deux niveaux :
UML:
LABEL "UML"
{
kernel
stereo
types
systems
state_md
diagrams
ooa
uml
code
methods
menus
methsuml
accesooa
refatooa
methsooa
rules
uiuml
ui
form_cmt
forms
formsuml
form_cod
cpp
stk
o2
docs
form_ref
};
Ce fichier déclare, sans précision de suffixe, les fichiers
de configuration .ml et .br à lire au lancement de
l'outil.
Une déclaration peut correspondre à 2 fichiers: la déclaration cpp provoque la prise en considération de cpp.ml et cpp.br; d'autres ne correspondent qu'à un fichier .ml ou un fichier .br.
La configuration de ce fichier permet de mettre de côté des éléments inutiles à l'utilisateur. Un utilisateur ne travaillant qu'en C++ éliminera la déclaration stk des spécificités Smalltalk par exemple.
L'ordre de prise en compte des fichiers est d'autre part fondamental
pour la compilation lors du lancement de l'outil: il faut toujours
que la définition d'une méthode précède son
utilisation. L'appel d'un fichier contenant du code utilisant la
méthode A doit être ultérieur à l'appel
du fichier contenant la définition de la méthode A.
Dans les fichiers de configuration .br, l'utilisation de la barre verticale | permet de saisir les chaînes de caractères en Anglais et en Français de la manière suivante:
Class : TypingObject // Class hérite de TypingObject
{attributes: Attribute [0..*] INVERSE class
// l'attribut attributes est issu d'une association,
// reconnaissable au mot-clé INVERSE, avec Attribute;
// sa cardinalité va de 0 à l'infini;
// l'attribut pendant (rôle opposé) du lien est
// class dans Attribute, mentionné dans la
// description de la classe Attribute ci-dessous
}
Attribute : AbstractAttribute {
class: Class INVERSE attributes (id)
// l'attribut class est issu d'une association avec Class;
// sa cardinalité (non explicitement mentionnée) est 1;
}
TYPE Name : String // Name est synonyme de String
options est optionnel.
Seul l'héritage simple est supporté.
Un attribut identifiant n'a pas besoin de règles écrites pour que son caractère identifiant soit vérifié: l'outil gère de base les identifiants; ainsi, par exemple, si deux classes (instances de la classe Class du méta-modèle) portent le même nom, cette anomalie est immédiatement signalée par l'outil car l'attribut name de Class est déclaré comme identifiant.
Class : TypingObject
{
is_type: Boolean LABEL "is a type"|"est un type";
abstract: Boolean LABEL "abstract"|"abstraite";
...
} LABEL "Class"|"Classe";
System {
LABEL "System"|"Système";
LABEL subsystems "domains"|"domaines";
}
RootSystem {
LABEL "Domain"|"Domaine";
}
SubSystem {
LABEL "SubSystem"|"SousSystème";
}
Action_Activity {
LABEL "Process"|"Processus";
}
TYPE Access : ENUM {read_write LABEL "read/write"|"lecture/écriture", read_only LABEL "read only"|"lecture seule", write_only LABEL "write only"|"écriture seule"} LABEL ""|"Accès";
TYPE Visibility : ENUM {public, protected LABEL ""|"protégé", private LABEL ""|"privé"} LABEL ""|"Visibilité";
TYPE CollectionKind : ENUM {none LABEL ""|"néant", ordered LABEL ""|"ordonné", sorted LABEL ""|"trié", keyed LABEL ""|"par clé"} LABEL ""|"GenreCollection";
// Entity : superclass of any meta-model class
Entity -abstract
// classe racine abstraite
{
} LABEL ""|"Entité";
// TypingObject : abstract class for classes and atomic types
TypingObject : Type -abstract
{
name: Identifier -id LABEL "name"|"nom";
typed_services: Service [0..*] INVERSE type LABEL "typed operations"|"opérations typées";
// collection of services using the type instance
typed_parameters: Parameter [0..*] INVERSE type LABEL "typed parameters"|"paramètres typés";
// collection of parameters using the type instance
typed_attributes: Attribute [0..*] INVERSE type LABEL "typed attributes"|"attributs typés";
// collection of attributes using the type instance
} LABEL "Typing Object"|"Objet Typant";
Class : TypingObject
{
is_type: Boolean LABEL "is a type"|"est un type";
abstract: Boolean LABEL "abstract"|"abstraite";
// if a class must not be instanciated, then this flag must be true
is_utility: Boolean LABEL "is utility"|"est utilitaire";
// must be true for a dummy class that encapsulates attributes and operations that are not part of a class, such as global variables and procedures
is_persistent: Boolean LABEL "persistent"|"persistante";
inst_card_min: Integer LABEL "inst card min"|"nb min inst";
// min number of instances for the class
inst_card_max: Integer LABEL "inst card max"|"nb max inst";
// max number of instances for the class (* for infinity)
last_update: Integer LABEL "last update"|"dernière mise à jour";
attributes: Attribute [0..*] INVERSE class LABEL ""|"attributs";
// collection of attributes not coming from associations
// l'attribut attributes est issu d'une association,
// reconnaissable au mot-clé INVERSE, avec Attribute;
// sa cardinalité va de 0 à l'infini;
// l'attribut pendant (role opposé) du lien est
// class dans Attribute, mentionné dans la
// description de la classe Attribute ci-dessous
services: Service [0..*] INVERSE class;
// collection of methods in the class
specializations: Inheritance [0..*] INVERSE superclass LABEL "subclasses inheritance links"|"liens d'héritage sous-classes";
// collection of inheritance objects leading to subclasses
generalizations: Inheritance [0..*] INVERSE subclass LABEL "superclass(es) inheritance link(s)"|"lien(s) d'héritage superclasse(s)";
// collection of inheritance objects leading to superclasses
acquaintances: Acquaintance [0..*] INVERSE class LABEL ""|"accointances";
// collection of attributes issued from associations
associative_association: AssAssoc [0..1] INVERSE associative_class LABEL "associative association"|"association associative";
} LABEL "Class"|"Classe";
...
Attribute : AbstractAttribute
{
meta: Boolean LABEL "class attribute"|"attribut de classe";
// true for class variable; false for instance variable
is_derived: Boolean LABEL "is derived"|"est dérivé";
derivation_expression: Text LABEL "derivation expression"|"expression de dérivation";
class: Class INVERSE attributes -id LABEL "class"|"classe";
// class the attribute belongs to
// l'attribut class est issu d'une association avec Class;
// sa cardinalité (non explicitement mentionnée) est 1;
// il constitue un identifiant (id) pour la classe Attribute;
type: TypingObject INVERSE typed_attributes LABEL "type"|"type";
// attribute type
qualifies: Acquaintance [0..*] INVERSE qualifiers;
} LABEL ""|"Attribut";
...


Sur la base des éléments exprimés dans ces extraits du méta-modèle TNI, voici un petit exemple de classes avec attributs, méthodes et associations, qui sont donc des instances de classes du méta-modèle TNI.

Voici maintenant quelques expressions OTScript et leur résultat :
Un principe fondamental est qu'il n'est jamais renvoyé 2 fois le même élément dans un ensemble: il s'agit donc bien de manipulation ensembliste.
Dans le méta-modèle TNI sont définies les deux énumérations:
Format:
BROWSER RootSystem::System_browser_UML : ...
{...
attributes :
// expression de type Attribute dans le méta-modèle TNI
LABEL "Attributes"|"Attributs"
PRINT print_UML
CREATE {class := A1;
CHECKID(THIS); ASK name;
ASK type: $SORT(ALL AtomicType
$+ (ALL Class)[is_type * (visibility=#public)]);
};
...
}
Si un éditeur présente une expression, et qu'il n'est précisé
aucun CREATE après cette expression, cela signifie qu'on ne peut
instancier le type de l'expression à cet endroit de la configuration.
L'ordre CREATE peut être limité à une ou plusieurs sous-classes du type de l'expression: on précise alors la sous-classe juste après le mot-clé CREATE, puis le code de création, et ceci autant de fois qu'il y a de sous-classes que l'on veut pouvoir instancier.
BROWSER RootSystem::System_browser_UML : ...
{...
servers_diagram $+ system_diagram
$+ class_diagrams $+ interaction_diagrams :
// expression de type Diagram dans le méta-modèle TNI,
// car c'est la super-classe commune à l'union de ces diagrammes
LABEL "Diagrams"|"Diagrammes"
PRINT print_br_UML
CREATE UMLSystemDiagram {system := A1; ASK name;}
CREATE UMLClassDiagram {system := A1; ASK name;}
CREATE UML_OID {system := A1; ASK name;}
...
}
Format:
BROWSER RootSystem::System_browser_UML : ...
{...
used_systems :
...
INSERT (ALL System $- THIS $- used_systems):
// les systèmes potentiellement utilisés sont à prendre
// parmi toutes les instances de System MOINS
// le système courant, MOINS ceux déjà utilisés
// par le système courant
{users += NEW Use;
$LAST(users).user_system := A1;};
// le code permet la mise à jour d'autres pointeurs
...
}
Contrairement au CREATE, l'insertion dans les formulaires est proposée
par défaut si elle n'est pas explicitée dans la configuration:
pour empêcher une insertion dans la configuration, il faut le dire
explicitement par INSERT NONE.
Une propriété remarquable est qu'un groupe de ASK consécutifs provoque l'ouverture d'une seule boîte de dialogue demandant les valeurs de l'ensemble des attributs.
Format:
BROWSER RootSystem::System_browser_UML : ...
{...
acquaintances.association :
LABEL "Associations"
CREATE
{...
ASK $FIRST(roles).name;
// demande du nom du premier rôle
ASK $FIRST(roles).card_max;
// demande de la cardinalité du premier rôle
ASK $LAST(roles).name;
// demande du nom du 2ème rôle
ASK $LAST(roles).class: system.visibleClasses
CREATE {system := A3;};
// permet de créer éventuellement une classe à cet endroit
// si elle n'existe pas dans le domaine de définition:
// elle devra satisfaire aux restrictions
// du domaine de définition
ASK $LAST(roles).card_max;
// une seule boîte de dialogue s'ouvrira pour
// l'ensemble de ces requêtes consécutives
...
}
Le calcul se fait sur la base d'un nom par défaut, auquel on ajoute un nombre incrémenté jusqu'à ce qu'il devienne un identifiant
Exemple:
DIAGRAM UMLStateDiagram::theDiagram -dblclick :
LABEL "UML State Diagram"|"Diagramme d'états UML"
{...
{...
transitions INVERSE (source $+ target) :
DISPLAY ...
CREATE{CLICK source; CLICK target;}
// permet de demander à l'utilisateur
// de cliquer sur l'état source, puis
// sur l'état cible pour créer une transition
...
};
...
};
Exemple:
Attribute {
FORM MainUML : LABEL "General"|"Général" WIDTH 12
{...
is_derived WIDTH 2+1;
derivation_expression WHEN is_derived WIDTH 9 HEIGHT 2;
...
};
}
La configuration des formulaires se fait généralement dans des fichiers .br appropriés; dans la configuration TNI, les noms des fichiers de formulaire commencent par form ou fref....
L'ordre de présentation des onglets est fonction de leur identificateur.
Format général :
classe {
FORM identifiant1 :
LABEL titre onglet
WIDTH entier donnant la largeur totale
{form_expression11 ...
// définit le 1er champ
form_expression12 ...
// définit le 2ème champ
form_expression13 ...
// définit le 3ème champ
...
};
FORM identifiant2 :
LABEL titre onglet
WIDTH entier donnant la largeur totale
{form_expression21 ...
// définit le 1er champ
...
};
}
form_expression peut être (exp est une expression OTScript
quelconque) :
L'aspect des zones de saisie dépend du type de l'expression présentée:
Des menus contextuels accessibles par le bouton 2 de la souris sont associés à certaines de ces zones de saisie:
Les principaux noms des fichiers .br contenant les browsers commencent par ui...
BROWSER Service::br_service -dblclick :
// mot réservé BROWSER
// suivi du nom de la classe du méta-modèle
// sur laquelle le browser est défini (Service),
// suivi du nom identifiant le browser (br_service)
// suivi éventuellement de -dblclick signifiant
// l'utilisation par défaut de ce browser
// sur double-clic sur une instance de service si plusieurs
// éditeurs existent sur la classe Service
LABEL "Operations Browser" | "Browser d'Opération"
// titre du browser
{parameters : LABEL "Parameters"|"Paramètres"
// éléments présentés dans la 1ère liste:
// les paramètres de l'instance de Service
// sur laquelle le browser a été ouvert
PRINT name + " : " + type.printType
// optionnel; permet de préciser la présentation
// textuelle dans le browser du paramètre
CREATE {service := A1;};
// optionnel; permet d'exécuter du code
// à la création d'un paramètre: ici, on relie
// le nouveau paramètre à l'instance courante de
// Service, représentée par A1
};
BROWSER classe::identifiant : LABEL titre
{expression1 : ...
// définit les éléments du 1er onglet
// de la 1ère zone de liste
{expression11 : ...;
// définit les éléments du 1er onglet
// de la 2ème zone de liste
expression12 : ...
// définit les éléments du 2ème onglet
// de la 2ème zone de liste
{expression121 : ...;
// définit les éléments du 1er onglet
// de la 3ème zone de liste
...
};
};
expression2 : ...;
// définit les éléments du 2ème onglet
// de la 1ère zone de liste
...
};
Chaque expression peut être suivie par :
expression : LABEL titre onglet PRINT expression retournant une chaîne // optionnel COLOR #couleur prédéfinie dans opentool.ini // optionnel CREATE ... // optionnel INSERT ... // optionnelLe nombre de listes d'un browser n'est pas limité: chaque indentation supplémentaire se fait par l'ouverture d'une accolade; les expressions après l'accolade ouvrante sont relatives à une instance de classe de l'expression figurant avant l'accolade ouvrante.
Un exemple de browser sur la classe System, conséquent et commenté, est présenté dans Exemples Administrateur
Les principaux noms des fichiers .br contenant les diagrammes commencent par ui...
Chaque entité graphique (vue, boîte, champ, lien, ...) :
La représentation exhaustive a l'avantage d'assurer à
l'utilisateur qu'il a bien sous les yeux la totalité des entités
sémantiques existantes présentées dans son diagramme;
la représentation partielle a l'avantage de pouvoir rendre plus
lisible certains diagrammes, surtout lorsqu'il s'agit de faire une sortie
documentaire.
DIAGRAM UMLStateDiagram::theDiagram -dblclick :
// Diagramme d'état UML: UMLStateDiagram est la classe
// du méta-modèle qui permet de décrire graphiquement
// une instance de StateModel à laquelle elle est associée
LABEL "UML State Diagram"|"Diagramme d'états UML"
{state_model.states:
// l'expression de navigation fournit l'ensemble
// des états du modèle d'état, mais tous ne sont pas
// forcément représentés graphiquement dans l'instance
// courante de UMLStateDiagram sur laquelle travaille
// l'utilisateur;
// l'utilisateur va pouvoir "Créer", "Détruire"
// des états dans l'éditeur de diagramme,
// mais aussi "Montrer" graphiquement des états
// pré-existants (créés dans un browser par exemple),
// ou en "Cacher" d'autres.
// state_model est l'accointance qui relie une
// vue d'état (instance de UMLStateDiagram)
// à son modèle d'état (instance de StateModel)
DISPLAY BoxWithLists(
#Round $+ #Opt2
$+ (state_kind IF #normal: #Default ELSE: #Thick)
$+ (isActive
IF TRUE: #Filled $+ #Color5
IF FALSE: #Default),
name)
// dit comment on dessine un état dans ce diagramme:
// BoxWithLists est une boîte pouvant contenir
// des zones de champs;
// #Round précise que les coins sont arrondis
// #Opt2 précise de centrer le titre lorsqu'il
// n'y a pas de champ dans la boîte;
// #Thick dessine un bord gras pour un état
// initial ou final
// #Filled $+ #Color5 pour un état possédant
// des sous-états le signale en remplissant
// l'état de la couleur Color5 définie dans
// le fichier "opentool.ini";
// name est ce qui est affiché comme titre
// de l'état
CREATE {state_model := A1.state_model;
CHECKID(THIS);}
// sur création d'un état, on le relie au state_model
// associé à la vue (A1 ici)
{
transitions INVERSE (source $+ target) :
// transitions est une méthode de la classe
// State du méta-modèle (définie dans methods.br) qui
// renvoie les transitions entrantes et sortantes
// d'un état;
// la relation INVERSE fournit les parents graphiques
// d'une transition, à savoir l'état source (source)
// et l'état cible (target): elle permet une
// optimisation de l'éditeur
DISPLAY Link(#Default, VOID String, #Default, #OpenArrowTip)
// dit comment la transition est dessinée:
// #Default : trait fin plein
// VOID String : pas de label
// #Default : pas de flèche côté source
// #OpenArrowTip : flèche simple ouverte côté cible
CREATE {CLICK source; CLICK target; }
// pour créer une transition, il est demandé à
// l'utilisateur de cliquer d'abord sur l'état
// source graphique (CLICK source),
// puis sur l'état cible graphique (CLICK target)
{trigger INVERSE trans_firing_on_event:
// trigger est l'événement porté
// par une transition; son parent graphique
// est ici la transition graphique
EXHAUSTIVE TRUE
// si une transition porte un evt,
// il doit être obligatoirement affiché
DISPLAY SimpleName(#Bold, name) -linked
// exprime que l'evt est affiché comme un champ
// (SimpleName), en gras (#Bold),
// accroché au lien (-linked)
CREATE Event {CLICK trans_firing_on_event;
receiver := A3.state_model.on_class;
CHECKID(THIS);}
// pour créer, un evt, il faut que l'utilisateur
// clique sur une transition (CLICK trans_firing_on_event);
// le récepteur de l'evt est connu: c'est
// la classe sur laquelle on décrit l'automate
// d'états, obtenue par A3.state_model.on_class,
// où A3 est une v. contextuelle qui à ce niveau,
// contient le diagramme
INSERT THIS.source.on_class.received_events;
// permet d'insérer un evt existant sur une
// transition, en le choisissant parmi
// les evts reçus par la classe dont on décrit
// l'automate d'états
};
actions INVERSE state :
// fournit les actions/activités définies
// sur un état; le parent graphique
// d'une action/activité est l'état
LABEL "Actions/Activities"|"Actions/Activités"
DISPLAY SimpleName(#Default, print) -inbox -vspace
// affiche l'action comme un champ (SimpleName),
// à l'intérieur de son parent (-inbox),
// en laissant un espace / titre (-vspace),
CREATE{CLICK state;
CHECKID(THIS);};
// pour créer une action, l'utilisateur sélectionne
// un état; CHECKID(THIS) crée un nom identifiant
// valide
};
notes :
// permet d'introduire des remarques textuelles
// non sémantiques dans la zone graphique
// sous forme de rectangles éditables
EXHAUSTIVE TRUE
DISPLAY BoxWithLists(#Sheet $+ #Gray $+ #Filled $+ #Color1 $+ #Left, comment)
// BoxWithLists dessine une boîte;
// ses arguments précisent l'affichage:
// #Sheet pour une boîte avec un coin replié,
// #Gray pour exprimer que le tour est en gris,
// #Filled $+ #Color1 pour exprimer
// que le fond est rempli par la couleur Color1
// définie dans le fichier "opentool.ini",
// #Left pour justifier le texte à gauche;
// comment fournit le texte affiché
CREATE {diagram := A1; };
// relie la "note" au diagramme
};
DIAGRAM classe::identifiant : LABEL titre
// classe est une sous-classe de la classe
// abstraite Diagram du méta-modèle
{expression1 : ...
// définit le 1er ensemble de fils potentiels
// graphiques du diagramme;
// la relation INVERSE n'est pas précisée
// car on sait à ce niveau que le parent
// graphique est le diagramme
{expression11 INVERSE exp_inv11 : ...;
// définit le 1er ensemble de fils potentiels
// graphiques d'un élément de expression1;
// exp_inv11 est la relation inverse qui,
// à partir d'un élément de expression11,
// fournit le ou les parents graphiques ce
// cet élément; exp_inv11 peut fournir
// un surensemble
expression12 INVERSE exp_inv12 : ...
// définit le 2ème ensemble de fils potentiels
// graphiques d'un élément de expression1;
{expression121 INVERSE exp_inv121 : ...;
// définit le 1er ensemble de fils potentiels
// graphiques d'un élément de expression12;
...
};
};
expression2 : ...;
// définit le 2ème ensemble de fils potentiels
// graphiques du diagramme
...
};
Chaque expression peut être suivie par :
expression : LABEL label du bouton de création // optionnel EXHAUSTIVE expression booléenne // optionnel: // permet de définir un ensemble d'entité // qui doivent obligatoirement apparaître // sur le diagramme DISPLAY expression de dessin // voir ci-après // les méthodes de dessin PRINT expression retournant une chaîne // optionnel: // est utilisé pour présenter textuellement les éléments // dans la boîte de dialogue issue de "Montrer" CREATE ... // optionnel INSERT ... // optionnelUn exemple commenté complexe, concernant le diagramme des paquetages UML, est présenté dans Exemples Administrateur.
DISPLAY SimpleBox ( attributs, label ) DISPLAY BoxWithLists ( attributs, label ) attributs : Couleur: #Red ... Forme: #Square #Round #Circle #Hexagon #Folder #Sheet Style: #Thick #Dash DISPLAY SimpleName ( attributs, label ) attributs : Couleur: #Red ... DISPLAY Link ( attributs trait, label milieu, attributs début, attributs fin, label début, label fin ) attributs trait : Couleur: #Red ... Style: #Thick #Dash attributs début/fin : Couleur: #Red ... Forme: #OpenArrowTip #ClosedArrowTip #BallTip #BoxTip #PegTip #DiamondTip Style: #Thick #Dash #Filled #Small #Large
La commande "Tout Vérifier" permet d'autre part de déclencher toutes les règles, immédiates et différées, sur toutes les instances concernées.
Il est parfois nécessaire que, sur une transaction utilisateur, il faille spécifier le déclenchement d'une règle pour une instance non "touchée" dans la transaction: par exemple, une règle vérifiant la non circularité dans l'héritage est définie sur la classe Class du méta-modèle, mais si une instance de la classe Inheritance qui relie 2 classes est modifiée, il faut bien déclenchée cette même règle: une méta-règle est alors définie; elle permet d'appeler une ou plusieurs règles déjà existantes sur d'autres instances.
Les noms des fichiers .br contenant les règles commencent par rules...
<classe> {
RULE <ruleName1> <options> :
<ruleExpression1>
LABEL "<label11>"
EXPLAIN <explainExpression>
LABEL "<label12>" ;
RULE <ruleName2> <options> :
<ruleExpression2>
LABEL "<label21>"
REPAIR <repairExpression> ;
...
}
RULE Class::inheritance_circularity -now -e1 :
// déclaration de règle sur la classe Class du méta-modèle
// inheritance_circularity est l'identifiant de la règle
// -now indique que la règle doit être immédiatement
// vérifiée
// -e1 indique que la transaction en cours est annulée
// si la règle n'est pas vérifiée
NOT(THIS $<
generalizations.superclass.*(generalizations.superclass))
// expression devant être constamment vérifiée
LABEL "Inheritance cannot be circular"
|"L'héritage ne peut pas être circulaire"
// information textuelle lorsque la règle n'est pas vérifiée
EXPLAIN
generalizations.superclass.*(generalizations.superclass);
// éléments fournis lorsque la règle n'est pas vérifiée
RULE Acquaintance::aggregation_on_one_side_only -now :
NOT(aggregation)
+ (aggregation * NOT(other.aggregation))
LABEL "Aggregation can only be on one side"
|"L'agrégation ne peut être exprimée que d'un côté"
// pour une règle à réparation automatique (REPAIR),
// l'explication textuelle n'est utile que si la règle
// n'est toujours pas vérifiée après réparation
REPAIR {BEEP(); aggregation := FALSE;};
// code automatiquement exécuté lorsque
// la règle n'est pas vérifiée
Les méta-règles permettent d'élargir à des instances non "touchées" par une transaction utilisateur le déclenchement des règles immédiates.
// META Rule
RULE Inheritance::inheritance_circularity -now -e1 : {
subclass.inheritance_circularity;
// fait appel à la règle définie plus haut pour la
// "sous-classe" du lien d'héritage
TRUE;
} LABEL "inheritance circularity"|"circularité dans l'héritage";
METHOD Entity::findServices -menu :
// findServices est une méthode
// définie dans la classe Entity;
// -menu indique qu'elle est définie pour un menu
// de la barre de menus OpenTool
{
TMP A1: String;
A1 := INPUTLINE("*", "Search pattern"|"Motif de recherche");
SHOWLIST(ALL Service[STRMATCH(name,A1)],
"Operations"|"Opérations");
}
LABEL "Outils,Chercher,Opération...";
// findServices est une méthode qui peut être
// déclenchée par l'item Outils de la barre de menus
// via le sous-menu Chercher sous lequel se trouve
// la commande Opération
L'item Outils existe déjà de base dans la barre de
menus; mais si l'on spécifie un nouvel item, il est alors
ajouté dans la barre de menus.
METHOD Toto::mth_exemple1(A1: Integer, A2: Integer):
{TMP A3: Integer; A3 := 0;
A3 := A1 * A2;
(3 * A3) + (2 * A2) + A1;
};
METHOD Toto::mth_exemple2:
{TMP A1: String; A1 := "";
...
};
Class
{
METHOD initialize: {
// A chaque création d'une instance de la classe
// Class du méta-modèle, cette méthode sera exécutée
categories := (ALL Category[name = "unclassified"])
DEFAULT (NEW Category).initialize ;
THIS;};
METHOD print: {
// Pour toute présentation textuelle non redéfinie
// d'une instance de Class, cette méthode eest appelée
STR(number) + "." + name
+ " (" + key_name + ")"; };
METHOD create_key_name: {
key_name := $FIRST(SUBSTR(name,1 ,
$INTERVAL(1 $+ STRCNT(name)))
[NOT(EACH $< THIS.system.classes.key_name)]);
};
// 1 $+ STRCNT(name) donne l'ensemble
// {1, nameSize}
// $INTERVAL(1 $+ STRCNT(name))
// complète l'ensemble {1, nameSize}
// de tous les elts absents
// entre son min et son max,
// soit A = {1, 2, ..., nameSize}
// SUBSTR(name,1 , A) [cond] renvoie
// alors toutes les combinaisons de
// chaînes de 1, 2, ..., nameSize caractères
// vérifiant la condition cond
// $FIRST(...) extrait la 1ère chaîne Str1
// de cet ensemble
// key_name := Str1 provoque
// l'affectation de Str1 dans key_name
METHOD create_number: {
number := FIRST( INTERVAL(system.base_num
+ ( CNT(system.classes) + system.base_num))
[NOT(EACH $< THIS.system.classes.number)]);
};
METHOD create: {
// lors d'un dialogue de création d'une instance de Class,
// la cloture positive de ce dialogue provoque l'exécution
// de cette méthode
create_key_name;
create_number;
// les méthodes create_key_name et create_number
// ont dû être définies avant la méthode create,
// sans quoi la compilation provoquerait une erreur
};
}
METHOD Association::print:
{$FIRST(roles).class.name
+ "(" + $FIRST(roles).name + ")-"
+ $LAST(roles).class.name
+ "(" + $LAST(roles).name + ")"; };
...
Les méthodes de documentation ne se distinguent des autres méthodes que par le fait qu'elles contiennent des ordres de génération de documentation. Elles peuvent faire appel à n'importe quelle méthode OTScript.
METHOD RootSystem::doc_header: {
\set("f1", name);
// affecte le nom du RootSystem name
// à la zone f1 de la première page
\set("f2", author);
// affecte l'auteur du RootSystem author
// à la zone f2 de la première page
\set("f3", date);
\set("t1", name + " System");
// affecte le nom du RootSystem name
// concatené à " System" à la zone à gauche
// de l'en-tête de page
\set("t3", project.name + " Project ");
// affecte le nom du projet project.name
// concatené à " Project" à la zone à droite
// de l'en-tête de page
\set("b1", date);
\set("b3", release);
// affecte la version release du RootSystem
// à la zone à droite du pied de page
};
METHOD Attribute::docIn(A1: Class): {
\par;
// début de paragraphe
\bold;
// début de fonte bold
\text(name + " : " + type.printType);
\bold_;
// fin de fonte bold
A1 = class IF FALSE: docInheritance;
// appel à la méthode de doc docInheritance
\par_;
// fin de paragraphe
class = A1 IF TRUE: doc_par(comment);
// appel à la méthode de doc doc_par
// avec l'argument comment
};
METHOD Class::doc -doc : {
TMP A1: Class, A2: Stereotype;
A1 := all_superclasses;
\sect(""|"Classe " + name + " class"|"");
\par;
\italic;
\text(" Inherits from: "|" Hérite de : ");
\italic_;
\bold;
\text($STR(superclasses.name));
\bold_;
\par_;
doc_par_title(comment, "Description");
$CNT(A1) > 0 IF TRUE: {
\sect("Inherited attributes"|"Attributs hérités");
A1.attributes.docIn(THIS);
\sect_;
};
\sect("Attributes"|"Attributs");
$CNT(attributes.stereotype)=0
IF TRUE: attributes.docIn(THIS)
IF FALSE: attributes.stereotype.{
A2 := EACH;
// EACH est ici un stéréotype
\sect(EACH.name);
THIS.attributes[EACH.stereotype = A2].docIn(THIS);
\sect_;};
\sect_;
\sect_;
} LABEL "Class"|"Classe";
METHOD Diagram::doc : {
FIG(THIS, scale, name);
// ordre de sortie de diagramme
\par; \text(comment); \par_;
};
METHOD System::doc : {
\sect(""|"Système " + name + " system"|"");
system_diagram.doc;
// appel de la méthode doc sur tous les
// diagrammes de système
class_diagrams.doc;
// appel de la méthode doc sur tous les
// diagrammes de classe
classes.doc;
// appel de la méthode doc sur toutes les
// classes
\sect_;
} LABEL "System"|"Système";
METHOD RootSystem::doc_final_report -menu : {
// point d'entrée de la documentation
// accessible par la barre de menu de l'outil
// grâce à l'option -menu
doc_header;
THIS.*System::(subsystems).doc;
// appel de la méthode doc sur l'instance
// de RootSystem courante (THIS) et tous ses
// sous-systèmes, récursivement
} LABEL "Tools,Doc,Final report"|"Outils,Doc,Rapport final";
// le point d'entrée de la documentation
// est accessible par l'item Tools/Outils
// de la barre de menu,
// sous-menu Doc,
// commande Final report/Rapport final
Ce répertoire contient les fichiers:
1 RootSystem {
name "mwoven" // String dans le méta-modèle
type "application" // symbole de l'enum SystemType
// du méta-modèle
currentPhase 0 // Integer dans le méta-modèle
subsystems 2 // référence à l'objet no 2
project 55 // référence à l'objet no 55
}
2 SubSystem {
name "ovenDesc"
ocm 3
type "application"
currentPhase 0
predefined_types 40
classes 5,9,38 // références aux objets no 5,9 et 38
supersystem 1
}
3 ObjectCommunicationModel {
name "OCM ovendesc"
system 2
coms 4,10,37
}
4 Communication {
sender 5
receiver 9
trigger 32
ocm 3
}
5 Class {
name "Oven"
abstract 0 // Boolean dans le méta-modèle
isPersistent 0
referential_attributes 6,43
out_coms 4,10,37
keyName "O"
number 1
stateModel 14
receivedEvents 26,21,30,53
visibility "public"
system 2
}
6 LinkAttribute {
name "light"
visibility "public"
access "readWrite"
cardMin 1
cardMax 1
collectionKind "ordered"
aggregation 0
mutable 0
class 5
relation 7
}
7 Association {
label ""
isDerived 0
roles 6,8
}
...
1 {
sem 9 // l'entité graphique n°1 est rattachée
// à l'entité sémantique n°9.
// comme aucun parent graphique n'est fourni,
// il s'agit d'une instance de diagramme.
box 0,0,80,14
}
2 {
sem 1 // l'entité graphique n°2 est rattachée
// à l'entité sémantique n°1
par 1 // et a pour parent graphique
// l'entité graphique n°1
box 42,17,122,77
// coordonnées du rectangle dans le diagramme
}
3 {
sem 12 // l'entité graphique n°3 est rattachée
// à l'entité sémantique n°12
par 5,2 // et a pour parents graphiques
// les entités graphiques n°5 et n°2
link 218,51,122,51
// coordonnées des points du lien dans le diagramme
}
4 {
sem 22
par 6,2
link 219,179,85,179,85,77
}
5 {
sem 11
par 1
box 218,20,303,80
}
6 {
sem 21
par 1
box 219,149,307,209
}
...
Un programme OTShell typique permet de désigner un fichier de travail (Select), de l'ouvrir (Open), d'exécuter des requêtes OTScript grâce à la notation { }, et éventuellement de quitter OpenTool (Quit).
La liste des instructions OTShell est la suivante :
Select("gps")
Open
{
DOCOPENW(SAVEDIR+"docSpec.tps", "ileaf");
docSpec;
DOCCLOSE;
}
Close
Echo("End of generation")
Quit
[Actions]
StartUp=Select("gps") Open
Si le programme est long, il est recommandé de le mettre dans un
fichier et de soumettre ce fichier grâce à l'instruction Exec
:
[Actions]
StartUp=Exec("C:\example\gps.osh")
Auteurs: Didier Simoneau, Jean-Marie Lions