Ventury Networks’ Blog

“If it walks like a duck and quacks like a duck, I would call it a duck.”

Créer un fichier avec VisualWorks Smalltalk


On souhaite créer un fichier, et y écrire du contenu. Le code suivant permet de créer le NOUVEAU fichier “test.txt” et d’y écrire un mot :

| file |
file := 'test.txt' asFilename.
file exists ifFalse:
	[ | ws |
	ws := file writeStream.
	ws nextPutAll: 'coucou'.
	ws close.]

Pour lire le contenu, on peut faire :

| file contenu |
file := 'test.txt' asFilename.
file exists ifTrue: [ | rs |
	rs := file readStream.
	contenu := rs contents.
	rs close.].
^contenu
Tags :

Smalltalk et les blocs multi-paramétrés


La problématique est la suivante : comment passer trois paramètres à un bloc, provenant d’une collection (Array, OrderedCollection, ou tout autre …).

monTab := #(1 2 'add').
monBloc := [:op1 :op2 :op3 | duCode. ^unResultat].

Je veux executer monBloc avec le contenu de monTab comme paramètres. L’utilisation de do: n’est ici pas appropriée : do: est un message compris par une collection, pas par un bloc. Et pourtant, la réponse est dans cette réponse : un bloc est un objet, comme tout en smalltalk. Il existe donc un message permettant de donner un paramètre à un bloc. Ce message est value: :

monBloc := [:op1 :op2 :op3 | duCode. ^unResultat].
monBloc value: 1 value: 2 value: 'add'.

Pour obtenir les éléments de monTab, je propose l’utilisation d’un ReadStream. Cependant, un acces direct aux éléments est aussi possible. Voici les deux solutions :

monTab := #(1 2 'add').
monBloc := [:op1 :op2 :op3 | duCode. ^unResultat].
" Accès direct aux éléments "
monBloc value: (monTab first) value: (monTab at: 2) value: (monTab last).
" Une seconde solution : "
monStream := monTab readStream.
monBloc value: monStream next value: monStream next value: monStream next.

Et voilà !

Tags :

Un serveur express en perl


Il arrive des fois où l’on a besoin de tester une application, et que pour cela un serveur logiciel est necessaire. Le cas s’est présenté récement : j’avais besoin d’un serveur qui écoutait sur un port, et affichait sur la sortie standard les paquets qu’on lui envoyait.

L’application client que je voulais tester était en Java. J’aurrais pu faire un serveur approprié en Java, mais … c’est tellement long. J’ai préféré utiliser un petit serveur bidon écrit en perl, qui réalise pleinement ce que j’attends, dont je vous donne ici le code source :

#!/usr/bin/perl
use strict;use warnings;
use IO::Socket;

my $serveur = IO::Socket::INET->new(LocalPort => 12345,
                                    Type      => SOCK_STREAM,
                                    Reuse     => 1,
                                    Listen    => 10)
or die "Impossible serveur tcp sur le port 12345 : $@\n";

while(my $client = $serveur->accept())
{
	while( my $rep = <$client>) {
	    print $rep;
	}
}

Il s’agit d’une version simplifiée d’un exemple trouvé sur internet il y a de cela quelques temps. Dans la doc Perl probablement ? Quoi qu’il en soit, la modif apporté fait que le serveur ne fork pas lors de l’arrivée d’un nouveau client : il s’agit là d’un serveur monoclient. Mais franchement, c’était largement suffisant !
Je vais sans doute utiliser ce serveur pour tester BOSS sur une connection TCP.

Tags :

Binary Object Stream Service


VisualWorks propose un Parcel nommé BOSS, pour Binary Object Stream Service. Celui ci permet le stockage d’instances sous la forme d’un fichier binaire. Ce parcel est normalement chargé dans l’image de départ de VW 7.5, mais le cas échéant, il peut être chargé via le parcel manager (”System” -> “Parcel Manager”). Il se trouve dans l’onglet suggestion, et le dossier “Application Developpement”.

Le code suivant permet d’utiliser BOSS :

myWriteStream := 'monFichier.dat' asFilename writeStream.
bos := BinaryObjectStorage onNew: myWriteStream.
"on suppose qu'il existe anObject, une instance de classe quelconque..."
[bos nexPut: anObject] ensure: [bos close].

On pourrait tout aussi bien utiliser le message “nextPutAll: aCollection” pour stocker un ensemble d’instances. La construction [aBlockClosure] ensure: [anAction] retourne la valeur retournée par le premier block, mais, avant cela, évalue le second bloc.

Pour récupérer des instances d’objets, le problème n’est pas plus compliqué :

myReadStream := 'monFichier.dat' asFilename readStream.
bos := BinaryObjectStorage onOldNoScan: myReadStream.
[myObjects := bos contents] ensure: [bos close].

Il est également possible de stocker des définitions de classes, avec le message “nextPutClasses: anArray” (anArray doit contenir les classes à enregistrer). Pour les récupérer depuis la sauvegarde, le message nextClasses fera l’affaire ;-)

BOSS est capable de détecter les changements dans la définition des classes lors du chargement d’instances depuis un fichier BOSS. Ainsi, vous pouvez diffuser un patch contenant les nouvelles classes oou les modifications apportées à votre logiciel, tout en assurant la rétro-compatibilité des sauvegardes des utilisateurs. Il suffit pour cela de définir deux méthodes dans la nouvelle version de la classe : une méthode d’instance nommée “binaryRpresentationVersion”, qui retourne la version de la classe (1, 2, 3… etc), et une méthode “binaryReaderBlockForVersion: oldVersion format: oldFormat” qui se charge de convertir l’anciene instance objet sous sa nouvelle forme. Le reste est fait automatiquement par BOSS.

BOSS est largement décrit dans le guide du développeur d’applications VisualWorks (AppDevGuide.pdf) situé dans le repertoire “doc” de votre installation VisualWorks. Ce billet en est d’ailleurs largement inspiré.

Avec un tel outils, imaginez la quantité de difficultés levées lors du developpement d’applications : sauvegarde aisée des éléments produits par l’applications, et mise à jour facile … Un bonheur.

Je crois (mais je n’en suis pas certain) qu’il est possible d’utiliser BOSS sur autre chose qu’un Stream sur un fichier. Une connexion TCP par exemple ? Je vérifierais, mais je n’ai pas encore en tête “l’application qui tue” d’une telle possibillité. Si vous avez des idées …

Tags :