CCTsvg #2 – l’heure des choix

Voulant au départ à la fois me calquer sur Processing (Java) et P5 (Javascript), et dans le même temps respecter des conventions de programmation propres, je suis confronté à des problèmes, et donc des choix à faire.

Car Python n’est pas Java ni Javascript…

Au delà de ce projet précis, se pose les questions d’un portage de projet d’un langage à un autre…

Les évidences

Du fait de la nature même du projet (générer des SVG statiques), j’ai pris le parti de rapidement supprimer toute la partie interactive et animée.

Pour les connaisseurs de Processing (et P5js, qui en est le portage JavaScript), cela signifie donc l’absence des fonctions setup() et draw()

Notons pour l’anecdote que si vous avez besoin de ces interactions, il existe un « mode Python » dans l’éditeur Processing, mais je désire que mon outil soit autonome, pouvant devenir (peut-être) une Rest API par exemple.

Il existe également un Py5, qui permet de piloter Processing Java.

Nommage des fonctions

Par convention, Java et JavaScript suivent une convention camelCase là ou Python suit une snake_case (snake, comme un serpent, si, si…).

Pour la plupart des fonctions, des primitives de dessin (circle, rectangle, arc…) les choix sont vites fait, les fonctions sont les mêmes. Car elles tiennent en un mot.

Pour d’autres, que j’ai ajouté et qui n’existent pas dans Processing, telle que color_gradient() ou polygon_regular(), j’ai suivi une convention Python.

Et bim, on mélange deux styles ?

Par contre, se pose le choix de certaines, telles que strokeWeight() ou noFill(). Si on conserve la convention camelCase, cela revient à mélanger les conventions de nommage au sein d’un même projet… Beurk.

Au départ, je me disais que cela simplifierait le portage du code (pour l’utilisateur de CCTsvg). Prendre un script Processing serait plus simple.

Après quelques essais, le portage nécessite forcément des adaptations. Ne serait-ce que les boucles for donc la syntaxe Python est fondamentalement différente…

Donc: on pythonne !

Bien sûr, cette interrogation s’étant posée en cours de route, il a fallu faire fonctionner la machine à chercher/remplacer…

Et modifier les tests. Et ajuster les tests.

Et modifier la doc…

Dans le même ordre d’idée, la fonction map() – qui en python renvoie un itérateur qui applique une fonction à chaque élément d’itérable (au passage, une fonction technique qui à ce jour n’a pas été traduite en français sur la doc officielle de python…).

Dans Processing elle sert à passer d’un nombre d’une plage à une autre (de une valeur comprise entre 0 et 255 à une valeur comprise entre 0 et 100 par exemple). Obligé là encore de s’éloigner des modèles, et donc de nommer la fonction autrement. Ici, remap()….

Nommage des paramètres (et passage des paramètres)

Destiné au SVG, et donc une forte probabilité d’être utilisé dans un contexte Web, j’ai ajouté la possibilité de préciser des id à chaque forme dessinée.

Cela rajoute un attribut à la fonction. Ce qui, en Python n’est guère grave, puisque l’on peut nommer nos paramètres.

Ainsi en va-t-il du carré:

def square(x, y, size, rx=0, ry=0, id=""):

En usage courant, on utilise les 3 premiers paramètres square(150,200, 20) pour un carré positionné à 150 en x, 200 en y, et 20 de côté. Et on ajoute les autres si besoin, square(150,200, 20, id="myCircle")

Rapidement, j’ai voulu y ajouter la possibilité de mettre des classes également. Problème, le mot class est réservé en Python (et autres d’ailleurs), rendant impossible cette définition:

def square(x, y, size, rx=0, ry=0, id="", class=""):

D’où nommage du paramètre css. Car les classes sont associées au css… et la ligne svg générée sera bien avec le mot clef class.

def square(x, y, size, rx=0, ry=0, id="", css=""):

Cela reste clair, surtout si documenté

Portage, et ajout de fonctionnalités…

Bien sûr, porter un projet avec obligation de réécrire beaucoup de chose, peut être l’occasion de faire évoluer le produit initial.

Surtout dans un cas comme celui-ci, ou il ne s’agit pas d’un portage avec nécessité de fidélité. On reste dans l’esprit général

Exemple, dans Processing, on doit jongler avec le crayon. C’est à dire changer de crayon avant chaque dessin. Une sorte de crayon « global ».

J’ai gardé cet esprit, mais ajouté la possibilité de crayon « local », en ajoutant les paramètres à mes fonctions.

def square(x, y, size, rx=0, ry=0, id="", css="",
           fill=None, stroke=None, stroke_weight=None):

Si ces paramètres restent à None, on utilise le crayon global, sinon le local.

Cela complique le code interne, mais rend l’utilisation pratique.

Je ne suis pas (pas encore?) entré dans la logique à fond pour les paramètres secondaires (dash, line_cap…) car d’un usage plus rares à mon sens. Ceux là resteront globaux…

 

A suivre!

Laisser une réponse