Comment étendre une classe en Ruby ?

Je découvre encore le monde Ruby et ce langage ne cesse de m’étonner. Je n’aime pas tout, loin de là,
mais ce qui me plaît compense de plus en plus largement ce qui me déplaît.
Dans cet article, j’explique d’abord pourquoi je n’aime pas la manière d’extraire des sous-chaînes. Puis pourquoi j’aime le mécanisme des classes ouvertes. Et enfin je montre comment plier à mes désirs une classe standard. Plus précisément comment ajouter une fonctionnalité à la classe String, sans pour autant perturber les programmes qui ne voudraient pas de cette nouvelle fonction.

Je n’aime pas : l’extraction de sous-chaîne

Pour extraire une sous-chaîne avec Ruby, on dispose, entre-autre, des deux méthodes suivantes :

str[offset, size]
str[range]

Méthode 1

> str = "Bonjour chez vous"
> str[8, 9]
=> "chez vous"

Mon problème ici est que je n’arrive pas à me mettre dans le crâne que le deuxième nombre est la longueur de la sous-chaîne. C’est purement subjectif, il se trouve simplement que mon cerveau refuse de fonctionner ainsi. Je préférerais avoir :

str[offset_début, offset_fin]

Avec de plus la possibilité pour les deux offsets d’être négatif (pour partir de la fin de la chaîne), comme en Python, par exemple.
Mais Ruby ne fonctionne pas comme ça…

Méthode 2

> str = "Bonjour chez vous"
> str[8..str.size]
=> "chez vous"

Avec un objet Range, c’est déjà mieux. Mais je n’aime pas beaucoup plus. Pourquoi ? Parce que je trouve c’est difficile à lire. Et puis il n’y a toujours pas la possibilité d’utiliser facilement les nombres négatifs.

EDIT : Comme dis plus haut, je débute avec Ruby. Et là j’ai commis une belle boulette. Les nombres négatifs fonctionnent tout à fait pour extraire une sous-chaîne avec un objet Range. Par exemple str[-4..-1] == 'vous', je n’ai donc plus de raison de me plaindre… Malgrè cela, le reste de l’article sur les classes ouvertes reste instructif.

J’aime : les classes qui restent ouvertes

En Ruby, une classe n’est jamais fermée. On peut modifier son code à loisir sans devoir la redéfinir entièrement.
Voici un exemple très simple :

> class Machin
>   def truc
>     puts "truc"
>   end
> end
>
> Machin.new.truc
=> "truc"

Maintenant j’ajoute une seconde méthode à la classe Machin :

> class Machin
>   def chose
>     puts "chose"
>   end
> end
>
> Machin.new.chose
=> "chose"
> Machin.new.truc
=> "truc"

On voit bien que la classe Machin  n’a pas été récrite, mais au contraire étendue. Une bonne pratique de la POO consiste à avoir une classe par fichier. Avec ce mécanisme de classe ouverte, on peut aller plus loin, en découpant une même classe en plusieurs fichiers.

Étendre la classe String

En guise de réconciliation, je vais me servir de ce que j’aime en Ruby (les classes ouvertes) pour améliorer un peu ce que je n’aime pas (l’extraction de sous-chaîne). Je me propose donc d’ajouter à la classe String une méthode from_to(). Cette méthode permettra d’extraire une sous-chaîne depuis un offset A, jusqu’à un offset B. A et B pouvant être négatif.

> class String
>   def from_to a, b
>     a += self.size if a < 0
>     b += self.size if a < 0
>     self[a..b]
>   end
> end
>
> "Bonjour chez vous".from_to 0, -1
=> "Bonjour chez vous"
> "Bonjour chez vous".from_to 8, 11
=> "chez"
> "Bonjour chez vous".from_to -9, -6
=> "chez"

C’est tout. Je suis toujours bluffé par la clarté du code Ruby.
Pour s’en servir, il suffira de mettre ce morceau de classe dans un fichier et de l’appeler avec require.

Conclusion

Imaginer la galère que ce serait d’implémenter une méthode de cette façon en (au hasard) Java ! En fait ce serait impossible. Il faudrait modifier directement le source de la classe String, ce qui rendrait la méthode from_to() accessible à tous les programmes (sans parler des soucis de distribution). Ou bien il faudrait écrire une nouvelle classe qui hériterait de String (et dont on oublierait bien vite de se servir).

Avec Ruby on peut réellement étendre les fonctionnalités d’une classe standard, et ce, juste pour les programmes voulus.

Références

Documentation de la classe String de Ruby
http://www.ruby-doc.org/core/classes/String.html

Publicités

, , , , ,

  1. Poster un commentaire

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s

%d blogueurs aiment cette page :