Sunday, December 6, 2009

Pharo et documentation des packages

Voici quelques expérimentations faites alors que je voulais explorer les documentations contenues dans Pharo. Dans ce billet nous verrons comment ressortir les commentaires des classes d'un package donné. Puis je décrirai le codage d'une application Seaside minimaliste pour visualiser cette documentation depuis un navigateur Web.

1. Voyage au centre du package

Les classes sont regroupées dans des packages gérées par Monticello. On peut faire l'analogie avec les gems du monde Ruby ou les gestionnaires de paquets des distributions Linux.

Chaque package étant une instance de la classe MCPackage, on peut en sortir la liste. Ouvrez un Workspace et affichez le résultat du code suivant (via click-droit, print it)

MCPackage allInstances



Cela devrait vous retourner une longue liste de packages:



Comptons en le nombre en évaluant la taille du tableau retourné:

MCPackage allInstances size.

Sur mon image je trouve 155 packages.

Chaque package a un nom via l'accesseur name. On peut ainsi en sortir la liste:

MCPackage allInstances collect: [:p| p name]

En triant par ordre alphabétique:

(MCPackage allInstances collect: [:p| p name]) sort

Affichons le tout dans un Transcript. Ouvrez-le via le menu World > Tools > Transcript.



Puis évaluez le code suivant dans le Workspace:

|packageNames|
packageNames := MCPackage allInstances collect: [:p| p name].
packageNames sort do:[:name| Transcript show:name; cr]





Les objects PackageInfo référencent toutes les classes d'un package. Chaque objet MCPackage est associé à un objet PackageInfo.

Prenons par exemple le premier package et affichons toutes les classes qu'il contient via l'accesseur classes:

MCPackage allInstances first packageInfo classes




Pour extraire toutes les classes d'un package donné, une petite sélection fait l'affaire. Le code suivant renvoie toutes les classes du package System-Tools:

|systemTools|
systemTools := (MCPackage allInstances select: [:p| p name = 'System-Tools']) first.
systemTools packageInfo classes.





On peut accéder au commentaire de chaque classe via l'accesseur comment. Affichons le commentaire de la classe SpaceTally dans un Transcript:

Transcript show:SpaceTally comment



De là à afficher toutes les classes d'un package avec leurs commentaires, il n'y a qu'un pas:

|systemTools|
systemTools := (MCPackage allInstances select: [:p| p name = 'System-Tools']) first.
systemTools packageInfo classes do:[:c|
    Transcript show: '***',c name; cr.
    Transcript show: c comment; cr; cr]






2. Application Seaside pour consulter les commentaires

Rajoutons maintenant un peu de bling-bling à tout ça. Un Transcript c'est bien, une page web c'est plus rigolo.

Créons le package SimpleWebDoc qui contiendra une application Seaside minimaliste permettant de parcourir les commentaires des classes des packages.

Quelques précisions pour commencer. J'utilise ici l'image Pharo 1.0 RC1 09.11.04 avec Seaside et Pier, téléchargeable sur le site de Pharo à l'heure où j'écris ces lignes.
Le navigateur de classes utilisé par défaut est Browser (pour des raisons de performances et stabilité), or je vais utiliser le Package Browser. Pour changer le navigateur par défaut, ouvrez le navigateur de classe et dans le menu de la fenêtre sélectionnez Choose new default Browser.



Ici sélectionnez O2PackageBrowserAdaptator.



Lancez un nouveau navigateur de classe, vous devriez obtenir le Package Browser.



Ajoutons maintenant le package SimpleWebDoc: click droit, create package.



Nouveau clic droit sur le package et choisissez various > add to smart groups pour le rajouter dans l'onglet groups du Package Browser.





Créer application Seaside nécessite d'hériter WAComponent et de l'enregistrer comme application. Voici la déclaration de la classe SWDocView:

WAComponent subclass: #SWDocView
 instanceVariableNames: ''
 classVariableNames: ''
 poolDictionaries: ''
 category: 'SimpleWebDoc'

Pour afficher un composant, Seaside lui envoie le messager renderContentOn: en lui passant un objet WARenderCanvas sur lequel dessiner notre page web (en utilisant des brosses/brush). Nous allons ici construire un formulaire affichant tous les packages:

renderContentOn: html
 html form: [
  html select 
   list: (MCPackage allInstances collect: [:p| p name])
 ].

Améliorons la lisibilité du code en créant allPackageNames qui retourne les noms de tous les packages, dans l'ordre alphabétique:

allPackageNames 
 ^ (MCPackage allInstances collect: [:p| p name]) sort

et ajustons renderContentOn: en conséquence:

renderContentOn: html
 html form: [
  html select 
   list: self allPackageNames;
 ].

Testons ce que donne ce premier code. Déclarez le composant SWDocView comme application en évaluant ce qui suit dans un Workspace:

SWDocView registerAsApplication: 'simple-web-doc'

Pointez ensuite votre navigateur Web à l'adresse: http://localhost:8080/seaside/simple-web-doc



Ajoutons un bouton pour valider le formulaire:

renderContentOn: html
 html form: [
  html select 
   list: self allPackageNames;
  html submitButton with:'show'
 ].

Maintenant la partie intéressante: lorsqu'on valide le formulaire, on affiche la documentation du package. Pour cela nous stockons le nom sélectionné dans la variable d'instance selectedPackage en utilisant le callback de la brosse WASelectTag:

renderContentOn: html
 html form: [
  html select 
   list: self allPackageNames;
   callback: [:value| selectedPackage := value].
  html submitButton with:'show'
 ].

Si selectedPackage est définit, affichons la documentation:

renderContentOn: html
 html form: [
  html select 
   list: self allPackageNames;
   callback: [:value| selectedPackage := value].
  html submitButton with:'show'
 ].
 
 selectedPackage ifNotNil: [
   self renderPackage:selectedPackage On:html.
 ]

La méthode SWDocView>>renderPackage:On: qui reprends l'exemple précédent:

renderPackage:packageName On:html
  |package|
  package := (MCPackage allInstances select: [:p| p name = packageName]) first.
  package packageInfo classes do: [:c| 
    html heading level:2; with: c name.
      html break.
      html text: c comment.
      html horizontalRule.
  ]

et voici le résultat:



Amenons un peu de lisibilté en écrivant une méthode qui retourne toutes les classes d'un package:

classesOfPackageNamed: packageName
 |package|
 package := (MCPackage allInstances select: [:p| p name = packageName]) first.
 ^ package packageInfo classes

d'où une mise à jour de renderPackage:On:

renderPackage:packageName On:html
 (self classesOfPackageNamed:packageName) do: [:c| 
  html heading level:2; with: c name.
  html break.
  html text: c comment.
  html horizontalRule.
  ]


Bon nombre de choses sont à réaliser pour avoir une navigation correcte. Pour aller plus loin, consultez Dynamic Web Development with Seaside.

No comments:

Post a Comment