La bibliothèque standard de Ruby comporte pas mal de modules vieillissants, dont le code aurait plus sa place dans des gems à part. Mais on peut aussi y trouver quelques perles. Je vous ai déjà parlé des Set et des Struct. Aujourd'hui, je vais compléter cette liste, en y ajoutant Shellwords.
La description de Shellwords dit :
This module manipulates strings according to the word parsing rules of the UNIX Bourne shell.
Ce que l'on pourrait traduire en français par :
Ce module manipules des chaînes de caractères en respectant les règles des shells Bourne UNIX pour découper les mots.
La première utilisation de ce module est de pouvoir construire des lignes de commande pour le shell. Par exemple, si on veut compter le nombre de lignes d'un fichier, on peut faire :
filename = "/path/to/my/file"
nb_lines = `wc -l < #{filename}`.to_i
Mais, si pour une raison ou une autre, le nom de fichier comporte une espace, cela ne va plus marcher. Dans la ligne de commande, l'espace se comportera comme un séparateur de mots et le shell va chercher deux fichiers au lieu d'un. Pour corriger le problème, on peut faire appel à Shellwords de cette façon :
require "shellwords"
filename = "/path/to/my/file"
nb_lines = `wc -l < #{Shellwords.escape(filename)}`.to_i
Note : l'espace n'est pas le seul caractère à poser problème dans les lignes de commande du shell. On peut également citer les retours à la ligne, les guillemets, l'anti-slash, le point-virgule (qui sert à séparer des instructions) ou encore le dollar (pour référencer des variables).
Si vous avez un tableau, il existe également une petite méthode utilitaire
pour vous aidez, Shellwords.join
. Voici un exemple :
require "shellwords"
pattern = "foo bar"
files = %w(some files)
open('|' + Shellwords.join(['grep', pattern, *files])) { |pipe|
# ...
}
Cette méthode applique Shellwords.escape
sur chaque élément du tableau, puis
fais un join(' ')
pour construire cette partie de la ligne de commande
finale.
On a vu comment construire une ligne de commande à partir de mots, mais la réciproque est également valable : Shellwords peut aussi nous aider à découper en mots une ligne de commande. Exemple :
require "shellwords"
argv = Shellwords.split('here are "two words"')
argv #=> ["here", "are", "two words"]
Cette méthode peut s'avérer bien pratique, même en dehors du contexte du shell. Imaginer que vous ayez un système qui permette de saisir des tags séparés par des espaces :
tags = gets.split(' ')
Si l'utilisateur saisit la ligne Ruby Shell Tips
, tags
sera le tableau
avec les 3 tags : ["Ruby", "Shell", "Tips"]
. Puis, un utilisateur vous
remonte son besoin de saisir des tags avec des espaces dedans, comme Open
Source
ou Free Software
. Vous ne voulez pas changer le séparateur, juste
avoir un moyen d'indiquer si l'espace fait parti du tag ou non. Le shell a
déjà résolu ce problème pour vous. Il propose deux façons de saisir un mot
avec des espaces : soit le mettre entre des guillemets, soit utiliser le
caractère d'échappement \
. Et avec Shellwords, c'est très facile de proposer
le même mécanisme :
require "shellwords"
tags = Shellwords.split(gets)
Et maintenant, si l'utilisateur saisit la ligne
"Free Software" Open\ Source
, nous obtenons bien un tableau avec deux tags :
["Free Software", "Open Source"]
. Ne trouvez-vous pas que c'est une
utilisation bien pratique de Shellwords ?