FAQ Ruby et Ruby on Rails (RoR).
FAQ Ruby et Ruby on Rails (RoR).Consultez toutes les FAQ
Nombre d'auteurs : 6, nombre de questions : 48, dernière mise à jour : 16 juin 2021
- Comment récupérer les arguments passés en ligne de commande ?
- Comment passer des arguments facultatifs à une méthode ?
- Comment gérer les commentaires en Ruby ?
- Comment lire un fichier se trouvant sur Internet ?
- Comment faire une copie d'un fichier ?
- Comment se connecter à une base SQLite sous Ruby ?
- Comment se connecter à une base PostgreSQL sous Ruby ?
- Comment mélanger un tableau aléatoirement ?
- Quelle est la différence entre une classe et un module ? Qu'est-ce que le mixin ?
- Comment faire des espaces de nom (namespace) ?
- Comment intercepter les exceptions ?
- Comment lever une exception ?
- Comment spécifier la visibilité des méthodes d'une classe en Ruby ?
- Comment spécifier la visibilité des attributs d'une classe en Ruby ?
- Quelle est la portée d'une variable locale ?
Il suffit d'utiliser ARGV. ARGV est un tableau contenant les arguments de la ligne de commande (après ruby xxx.rb) sous forme de chaîne et séparés par un espace.
Ex : ruby mon_script.rb coucou
puts ARGV
[
0
]
Le code ci-dessus va nous renvoyer la chaîne "coucou". A noter que le tableau ARGV ne contiendra que des chaînes, il faudra donc veiller à les convertir suivant le cas.
Deux solutions :
- Définir une valeur par défaut :
def
methode_test(
x, y, z=
42
)
end
mon_objet.methode_test(
12
, 24
)
Dans ce cas, z prendra comme valeur par défaut 42 s'il est omis dans l'appel (sinon, il prend la valeur passée dans l'appel).
- Utiliser un tableau de paramètres :
Si vous ne savez pas combien de paramètres vous voulez passer, vous pouvez utiliser la syntaxe suivante :
def
methode_test2(
x, y, *
z)
end
mon_objet.methode_test2(
12
, 24
, 42
, 72
, 128
)
z sera alors un tableau contenant [42, 72, 128].
- Commentaires simple ligne :
def
test(
a, b)
# Ceci est un commentaire simple ligne
end
- Commentaires multi-lignes :
def
test2(
c, d)
=begin
ceci
est
un
commentaire
ulti-lignes
=end
end
Il y a plusieurs Methodes possibles , Utiliser net/http , net/ftp ou coder les socket en Dur !
Mais je vous explique ici la méthode la plus simple et qui est compatible HTTP/HTTPS/FTP , grâce a OPENURI.
Ici nous voulons ouvrir http://www.google.com. Nous allons en prime récupérer des informations comme l'encodage , la date de modification etc. :
require
"open-uri"
open(
"http://www.google.com"
)
do
|
f|
puts "Contenu de la ressource distante : "
f.each_line do
|
line|
puts line #on imprime chaque ligne du fichier distant
end
puts "CONTENT-TYPE:
#{
f.content_type}
"
# le content-type
puts "CHARSET:
#{
f.charset}
"
# le charset
puts "LAST_MODIFIED:
#{
f.last_modified}
"
# Derniere date de modification
end
Vous pouvez utiliser ftools ou fileutils, qui proviennent tout deux de la librairie standard de Ruby et vous apportent des méthodes toutes faites pour manipuler les fichiers.
Exemple avec ftools :
require
"ftools"
File.syscopy(
"source.file"
,"destination.file"
)
Exemple avec fileutils :
require
'fileutils'
FileUtils.cp 'source.file'
, 'destination.file'
Vous pouvez également utiliser le code suivant :
source =
File.open(
"source.file"
, "rb"
)
destination =
File.open(
"destination.file"
, "wb"
)
while
char =
source.getc
destination.putc char
end
destination.close
Tout d'abord, installez SQLite (vous pouvez télécharger SQLite sur le site officiel). Sous windows, copiez simplement le fichier "sqlite3.dll" dans le répertoire bin de ruby.
Installez maintenant les librairies SQLite pour ruby :
gem install sqlite3-ruby
J'ai choisi le deuxième choix (2. sqlite3-ruby 1.2.1 (mswin32)).
Il ne vous reste plus qu'à vous connecter à votre base :
require
'sqlite3'
include
SQLite3
db =
Database.new(
'test.db'
)
db.execute <<SQL
CREATE TABLE IF NOT EXISTS personnes (
idx INTEGER PRIMARY KEY,
nom VARCHAR(255)
);
SQL
tabl_personnes =
[
"pierre"
, "paul"
, "jacques"
]
tabl_personnes.each {
|
personne|
strSQL =
"INSERT INTO personnes (nom) VALUES ('
#{
personne}
')"
result =
db.execute(
strSQL)
}
Si vous souhaitez un outil graphique pour gérer vos bases, vous pouvez télécharger l'excellent SQLite Database Browser.
Voici un exemple de code vous permettant de vous connecter à une base PostgreSQL :
require
"postgres"
dbHost =
"localhost"
dbPort =
5432
dbName =
"maBase"
dbLogin =
"monLogin"
dbPasswd =
"monPasswd"
conn =
PGconn.connect(
dbHost, dbPort,""
,""
, dbName, dbLogin, dbPasswd)
res =
conn.exec(
"select id,nom from maTable;"
)
res.each do
|
row|
puts "id:
#{
row[
0
]}
"
puts "nom:
#{
row[
1
]}
"
end
res.clear
conn.close
tab =
[
1
, 2
, 3
, 4
, 5
]
puts tab.sort_by {
rand}
Un module ne peut pas être instancié mais peut être inclu par une classe (action appelée mixin). La classe référence alors toutes les déclarations du module.
module
M
SALUTATION =
"Je viens du module !"
def
parler
puts SALUTATION
puts "Cette classe s'appelle
#{
@nom
}
"
end
end
class
C
include
M
def
initialize
@nom
=
"C"
end
def
parler2
puts SALUTATION
puts "Je m'appelle
#{
@nom
}
"
end
end
M.new # Erreur : undefined method `new' for M:Module
# il est interdit d'instancier un module
c =
C.new
c.parler # => Je viens du module !
# => Cette classe s'appelle C
c.parler2 # => Je viens du module !
# => Je m'appelle C
Un module peut regrouper des constantes, des variables, des fonctions, des classes etc. Il aura alors le comportement d'un espace de nom pour tout ce qui n'est pas du niveau instance : constantes, classes et fonctions de module.
module
Math
CONSTANTE =
9
.81
# Math::CONSTANTE fonctionne aussi
class
CalculDivers # class Math::CalculDivers fonctionne aussi
# ...
end
def
Math::
fonctionUtilitaire(
arg)
# def self.fonctionUtilitaire(arg) fonctionne aussi
# ... def fonctionUtilitaire(arg) serait une fonction récupérée par un include (mixin)
end
end
puts Math::
CONSTANTE # => 9.81
calc =
Math::
CalculDivers.new
Math::
fonctionUtilitaire(
Math::
CONSTANTE)
En englobant le code susceptible de lever une exception avec un bloc begin...rescue...end.
begin
puts 1
/
0
rescue
puts "Erreur !"
end
# => Erreur !
# ou encore :
1
/
0
rescue
nil
# Pas d'erreur, l'instruction renvoie nil
a =
1
/
0
rescue
0
puts a # => 0
On peut spécifier quel type d'exception intercepter, les autres types remonteront donc en dehors du bloc. On peut également intercepter plusieurs types et réagir de façon différente pour chacun.
begin
puts 1
/
0
rescue
ZeroDivisionError
puts "Erreur de division"
rescue
Exception
puts "Autre erreur"
end
# => Erreur de division
Attention, le premier rescue dont le type (ou un type héritant de ce type) correspond à l'exception sera exécuté et les autres seront ignorés. Il faut donc faire attention à l'ordre des rescue, le plus général en dernier.
Ruby fournit plusieurs classes d'erreur hierarchisées, voir Exceptions mais il est possible de créer ses propres classes en héritant de StandardError. Un rescue sans type spécifié intercepte le type StandardError et tous ses descendants, mais pas les autres types.
On peut enfin utiliser l'objet d'exception qui a été levé. Les exceptions standards du langage héritent toutes de la classe Exception et fournissent donc certaines fonctions standards.
begin
puts 1
/
0
rescue
ZeroDivisionError =>
e # ou rescue => e pour intercepter toute erreur
puts e.message # ou puts e (implicitement e.to_s)
puts e.backtrace.inspect # backtrace renvoie un tableau contenant la pile d'exécution
# => divided by 0
# ["test.rb:2:in `/'", "test.rb:2:in `<main>'"]
puts e.backtrace.join(
"\n"
)
# => test.rb:2:in `/'
# test.rb:2:in `<main>'
end
On peut utiliser le mot clé retry dans une clause rescue qui relancera l'exécution du bloc begin.
On peut ajouter une clause else après les rescue qui sera exécutée uniquement si aucune exception n'est levée.
On peut ajouter en dernier une clause ensure qui sera exécutée à la fin du bloc, qu'une exception soit levée ou non.
var =
0
begin
var =
10
1
/
0
var =
20
rescue
puts var
else
puts "Aucune erreur !"
ensure
var +=
1
end
puts var
# => 10
# 11
# Si on commente la ligne avec la division par zéro, on obtient :
# => Aucune erreur !
# 21
Avec le mot clé raise, on peut lever un objet, une classe Ruby ou même rien. Par défaut le type d'exception sera RuntimeError.
raise
raise "Erreur"
raise StandardError, "Message d'erreur"
begin
raise "Erreur"
puts "Cette instruction ne sera pas exécutée"
rescue
=>
e
puts e
end
# => Erreur
Par défaut les méthodes sont publiques, sauf la méthode initialize.
On peut spécifier la visibilité des méthodes d'instance avec les mots clé public, protected et private. Soit en plaçant le mot clé avant la déclaration des méthodes, la visibilité sera appliquée à partir du mot clé jusqu'au suivant ou jusqu'à la fin de la classe. Soit en spécifiant le nom de la ou des méthodes sur lesquelles appliquer la visibilité.
class
C
# Visibilité publique par défaut
def
fonction_publique
end
def
une_fonction
end
private # Les méthodes déclarées après cette ligne seront privées
def
fonction_privee
end
def
autre_fonction_privee
end
protected # Les méthodes déclarées après cette ligne seront protégées
def
fonction_protegee
end
# On assigne une visibilité explicitement
private :une_fonction
# On rend la méthode une_fonction privée
public :autre_fonction_privee
# On rend la méthode autre_fonction_privee publique
end
c =
C.new
c.fonction_publique
c.une_fonction # Erreur, la méthode est privée
c.fonction_privee # Erreur, la méthode est privée
c.autre_fonction_privee # La méthode est bien publique !
c.fonction_protegee # Erreur, la méthode est protégée
Pour les méthodes de classe, il faut utiliser public_class_method et private_class_method, mais seule la manière explicite est effective.
class
C
def
C.fonction
end
private_class_method :fonction
end
C.fonction # Erreur, la méthode est privée
Attention : en Ruby la définition de privé et protégé est un peu différente. Une méthode privée ne peut pas être appelée à partir d'un objet explicite. C'est à dire qu'on ne peut l'appeler qu'au sein de méthodes du même objet. Une classe fille peut donc utiliser une méthode privée héritée. Une méthode protégée peut être appelée par n'importe quel objet de la même classe ou de ses classes dérivées.
class
Maman
def
privee
end
def
protegee
end
private :privee
protected :protegee
end
class
Fifille <
Maman
def
test
protegee # Ok
privee # Ok
self
.protegee # Ok
self
.privee # Erreur
end
def
test2(
objet)
objet.protegee # Ok
objet.privee # Erreur
end
end
obj =
Fifille.new
obj.test
obj2 =
Fifille.new # Le résultat serait le même avec une instance de Maman
obj.test2(
obj2)
# obj appelle les fonctions de l'instance obj2, un objet différent
Par défaut les attributs sont privés.
On fournit si on le souhaite un accès en lecture, en modification ou les deux. Pour cela on utilise respectivement les mots clé attr_reader, attr_writer, attr_accessor suivis des symboles des attributs (leur nom précédé du caractère :).
class
C
attr_reader :var1
attr_writer :var2
attr_accessor :var3
def
initialize
@var1
=
1
@var2
=
2
@var3
=
3
end
def
afficher
puts "var1 :
#{
@var1
}
\nvar2 :
#{
@var2
}
\nvar3 :
#{
@var3
}
"
end
end
c =
C.new
c.afficher # => var1 : 1
# var2 : 2
# var3 : 3
puts c.var1 # => 1
c.var1 =
10
# Erreur
puts c.var2 # Erreur
c.var2 =
20
# Ok
c.afficher # => var1 : 1
# var2 : 20
# var3 : 3
c.var3 =
30
# Ok
puts c.var3 # => 30
L'accès en lecture ou écriture devient public si on le spécifie comme ci-dessus. Pour définir un accès protégé, il faut déclarer un accès de façon normale puis spécifier explicitement la visibilité de l'attribut en protégée, qui ne sera appliquée que sur l'accès déclaré (lecture/écriture/les deux), l'accès non déclaré restant privé par défaut.
class
C
attr_reader :var
protected :var
def
test_lecture(
obj)
puts obj.var
end
def
test_ecriture(
obj)
obj.var =
0
end
end
c1 =
C.new
c2 =
C.new
c1.test_lecture(
c2)
# Ok
c2.test_ecriture(
c2)
# Erreur
puts c1.var # Erreur
c1.var =
0
# Erreur
Lien : Comment spécifier la visibilité des méthodes d'une classe en Ruby ?
La portée d'une variable locale se limite au module, la classe, la fonction ou la boucle dans lequel elle est affectée la première fois. Par contre un bloc if ne limite pas la portée.
3
.times do
i =
4
print "
#{
i}
"
end
puts # => 4 4 4
puts i # Erreur, variable non définie
if
true
j =
5
puts j # => 5
end
puts j # => 5