Le Langage de programmation Ruby est un langage interprêté fait par et
pour les Développeurs.
Son créateur, le programmeur Japonais
Yukihiro « matz » Matsumoto a commencé à le développer à partir de
1995.
Ce dernier a rassemblé certaines fonctionnalités de ses langages préférés de l’époque (principalement Perl, Smalltalk, Eiffel, Ada et Lisp), afin d’imaginer un nouveau langage qui mêlerait astucieusement programmations impérative et fonctionnelle.
Son nom est issu d'un jeu de mot avec le langage de script
Perl.
Références :
Implémentations :
- La principale est celle du créateur :
Matz's Ruby Interpreter (MRI)
Les versions actuelles : V1.8.X, V1.9.X
- Ruby Enterprise Edition (REE)
- Rubinius (Rbx)
- Il existe une version java :
JRuby
2.1) Syntaxe des fichiers :
Les fichiers Ruby ne tiennent pas compte des espaces et des tabulations, mais il est préférable pour des raisons de lisibilité de bien indenter vos fichiers.
2.2) Inclusions :
Inclus les fonctions, classes, méthodes, etc. d'un fichier source
Ruby dans un autre :
require <fichier>.rb
2.3) Test d'instructions :
- Instructions à la volée (One liner) :
Commande :
ruby -n -e <fichier>.rb
Récupération de la ligne courante (saisie à l'entrée standard) dans la variable globale :
$_
Récupération d'objet / paramètre à la volée :
<Instruction retournant un objet>
@o = _ #==> @o est affecté avec l'objet retourné par la dernière instruction
Vérification de la syntaxe :
ruby -cw <fichier>.rb
3.1) La dernière action d'un bloc renvoie sa valeur :
un = deux = trois = ""
=> ""
3.2) Tests :
- If :
Le end est toujours nécessaire;
Le then ou le ; ou le : est nécessaire si l'instruction est sur une seule ligne :
if <cond°> then <inst°> end
if <cond°> : <inst°> end
if <cond°> ; <inst°> end
if <cond°>
<inst°s>
...
end
if <cond°>
<inst°s>
...
elsif
<inst°s autre cas>
...
else
<inst°s aucun des cas précédents>
...
end
Assertions :
if <false>
=> nil ou false
if (0) then puts '0 => true' else puts '0 => false' end
0 => true
:nom == :nom
=> true
"nom" == "nom"
=> true
3.3) Sélection de cas (case):
case x
when 1
<inst°s>
...
when n
<inst°s>
...
end
3.4) Boucle for :
(1..10).each do |i|
puts i
end
3.5) Boucle loop :
3.6) Boucle while :
while <cond°>
...
end
begin
...
end while <cond°>
f=2
puts f=f+2 while f < 10
3.7) Exceptions :
L'Exception par défaut est :
begin
...
rescue ZeroDivisionError
...
exit
rescue IOError
...
exit
rescue TypeError
#Ruby n'est pas typé, mais possible (paramètres de méthode)
...
exit
rescue
#Toutes les autres
puts "Exception survenue: #{$!}"
...
exit
ensure
#Toujours executé
end
begin
...
rescue exception
#Toutes
puts "erreur : #{exception.message}"
end
Exemple de TypeError :
def factorial(n)
if n == 0
1
else
n * factorial(n-1)
end
end
numbers = [1,2,3]
begin
puts factorial(numbers)
rescue TypeError
puts "une erreur de type est arrivée : #{$!}"
end
puts(numbers.map { |n| factorial(n) })
4.1) Chaînes :
- dans les chaines à cote simple, \ et " n'ont pas besoin d'être échappés
Rien à échapper sauf : '.
- Passage continu à la ligne avec le caractère : \
- Répétition :
"Salut" * 3
=> "SalutSalutSalut"
4.2) Caractères :
- Code ASCII du charactère :
?a #Ruby 1.8
.getbyte(0) #Ruby 1.9
4.3) Encodage :
Version de Ruby >= 1.9
4.3.1) Transcodage :
latin1_resume = "Résumé"
transcoded_utf8_resume = latin1_resume.encode("UTF-8")
# now correctly changed to UTF-8
puts transcoded_utf8_resume.encoding.name # ==> UTF-8
puts transcoded_utf8_resume.bytesize # ==> 8
puts transcoded_utf8_resume.valid_encoding? # ==> true
4.3.2) Parcours :
Version de Ruby >= 1.9
- String :
each() a été retiré de String et String n'est plus Enumerable.
à la place :
utf8_resume.each_byte do |byte|
puts byte
end
utf8_resume.each_char do |char|
puts char
end
Parcours de chaque caractère :
each_codepoint #(ascii)
Parcours de chaque ligne :
each_line
On retrouve Enumérable :
p utf8_resume.bytes.first(3)
# ==> [82, 195, 169]
p utf8_resume.chars.find {
|char| char.bytesize > 1
}
# ==> "é"
p utf8_resume.codepoints.to_a
# ==> [82, 233, 115, 117, 109, 233]
Maintenant le reverse de mots marche même avec les accents :
p utf8_resume.lines.map { |line| line.reverse }
# >> ["émuséR"]
Autres :
TODO
4.4) Formats de date et d'heure :
Les dates peuvent être formatées avec l'instruction suivante :
<objet_time>.strftime(<string>) #=> <tring>
Où le paramètre chaîne peut contenir les valeurs suivantes :
%a Nom abrégé jour de semaine ('Sun')
%A Nom de jour de semaine complète ('Sunday')
%b Nom abrégé du mois ('Jan')
%B Nom complet du mois ('January')
%c Représentation locale préférée de l'heure et de la date
%c Siecle (20 en 2010)
%d Jour du mois (01..31)
%D Date (%m/%d/%y)
%e Jour du mois, complété par des blancs ( 1..31)
%H Heure de la journée, horloge 24 heures (00..23)
%I Heure de la journée, horloge 12 heures (01..12)
%j Jour de l'année (001..366)
%k Heure de la journée, horloge 24 heures, complété par des blancs ( 0..23)
%l Heure de la journée, horloge 12 heures, complété par des blancs ( 1..12)
%L Milliseconde de la seconde (000..999)
%m Mois de l'année (01..12)
%M Minute de l'heure (00..59)
%n caractère Newline (\n)
%N Fractions de secondes digits, 9 digits par défaut (nanosecondes)
%3N millisecondes (3 digits)
%6N microsecondes (6 digits)
%9N nanosecondes (9 digits)
%p Indicateur de Meridien ('am' ou 'pm')
%P Indicateur de Meridien ('AM' ou 'PM')
%r Heure, horloge 12 heures (%I:%M:%S %p)
%R Heure, horloge 24 heures (%H:%M)
%s Nombre de secondes depuis 1970-01-01 00:00:00 UTC.
%S Seconde de la minute (00..60)
%t Caractère tabulation (\t)
%T Heure, horloge 24 heures (%H:%M:%S)
%u Jour de la semaine en decimal, Lundi étant 1 (1..7)
%U Numéro de semaine, année courante (le 1er Dimanche est le 1er jour de la 1ère semaine) (00..53)
%v Date O.S. VMS (%e-%b-%Y)
%V Numéro de semaine de l'année, d'après ISO 8601 (01..53)
%W Numéro de semaine de l'année courante (le 1er Lundi est le 1er jour de la 1ère semaine) (00..53)
%w Jour de la semaine (Dimanche est 0) (0..6)
%x Représentation préférée pour la date seule, pas d'heure
%X Représentation préférée pour l'heure seul, pas de date
%y Année sans siècle (00..99)
%Y Année avec siècle
%z Fuseau horaire en décalage de UTC (p. ex. +0900)
%Z Nom du fuseau horaire
%% Caractère litéral '%'
- Ubiquité :
- Toute donnée est un objet.
- Toute fonction est une méthode.
- Toute fonction est un message :
- send
- call
- start('<nom de fonction>')
- Passage des paramètres :
Les Variables / Objets sont passés par référence de façon systématique.
- Spécificateur de portée :
C'est le premier caractère du le nom de la variable (préfixe), il doit être utilisé à la déclaration et ensuite à l'utilisation.
Voici leur liste, classés par portée croissante :
$ | Variable Globale à l'application. |
@@ | Variable de Classe. |
@ | Variable d'Instance. |
[a-z] ou _ | Variable locale. |
[A-Z] | Constante. |
Un petit schéma explicatif :

Un exemple un peu trompeur (une variable nommée comme instance mais pour une classe):
class DesY
@y = 1
def y=(p_y)
@y = p_y
end
def y
@y
end
def self.get_y
@y
end
def self.set_y(p_y)
@y = p_y
end
end
dy1 = DesY.new
dy1.y = 2
puts 'dy1.y: ' + dy1.y.to_s
dy2 = DesY.new
dy2.y = 3
puts 'dy2.y: ' + dy2.y.to_s
puts "Il existe deux types de variables @y: une pour les instances (#{dy1.y}, #{dy2.y}) et une pour la classe (#{DesY.get_y})"
DesY.set_y(4)
puts 'Input.get_y: ' + DesY.get_y.to_s
Classes :
- Détermination de la classe d'un objet :
<objet>.class
#=> son type (le nom de sa classe)
Exemple :
[].class
#=>> Array
Parents :
<objet>.class.superclass
# => son parent (toujours unique).
Exemple avec Irb :
irb(main):001:0> un = 1
=> 1
irb(main):006:0> un.class.superclass
=> Integer
irb(main):007:0> un.class.superclass.superclass
=> Numeric
irb(main):008:0> un.class.superclass.superclass.superclass
=> Object
irb(main):009:0> un.class.superclass.superclass.superclass.superclass
=> nil
Lister tous les ancêtres d'une classe : parent et parents de parents, etc. (
Mixins inclus) :
<objet>.class.ancestors
#ex:
1.class.ancestors
=> [Fixnum, Integer, Precision, Numeric, Comparable, Object, Kernel]
Constructeur / Destructeur :
def initialize(*params)
...
super(*params)
end
Destructeur :
def finalize
...
end
Constructeur de classe :
def self.initialize
...
end
Type de (is_as?) :
<objet>.is_a?(<type>)
Exemple :
{}.is_a?(Hash)
#=> true
Objets :
.object_id #Rails 3
.id #Rails 2
.__id__
Existence :
defined?
Exemple :
if defined? @@c_nombre
Apporté par ROR :
blank?
Et son contraire :
present?
Méthodes :
Les méthodes peuvent être des méthodes d'objet ou de classe.
- Vérification de l'existence d'une méthode (respond_to?) :
On peut utiliser la méthode respond_to? pour vérifier qu'une méthode existe :
if (photo.respond_to?(:commentaire) && !photo.commentaire.blank? )
Liste des Méthodes :
<objet>.methods
Les méthodes de l'objet sont retournées dans un Tableau (Array).
Pour les avoir dans l'ordre :
.sort
Publiques :
<variable>.public_methods
Modules et héritage :
À la différence de bien d’autres langages orientés objet,
Ruby ne donne accès qu’à l’héritage
unique, et ce, volontairement.
En effet, Ruby supporte par ailleurs le concept de
Modules. Ces
Modules sont des
regroupements de méthodes.
Les classes peuvent « incorporer » un module (opération dite de
mixin) afin d’en recevoir toutes les méthodes, sans plus de travail.
Par exemple :
Toute classe implémentant une méthode
each peut ensuite incorporer le module
Enumerable, lequel fournit gratuitement plusieurs méthodes utilisant
each pour faire des boucles.
class MonTableau
include Enumerable
def each
...
end
end
Symboles :
Liste :
Symbol.all_symbols
Conversions :
<symbole>.to_s
#=> <String>
<string>.to_sym
#=> <Symbole>
Mots-clé
Ne jamais mettre en mot-clé :
action
Closures (Blocs) :
When a proc or lambda is created the variables in local scope are bound and not copied.
7.1) Tableaux :
- Ils peuvent être mixtes, ils sont triables, et peuvent contenir des doublons :
tableau_mixte = ["a", 1, :c, 3.14]
Opérations :
lettres = ["a", "b", "c", "d"]
#Soustraction
lettres - ["a", "b"]
=> ["c", "d"]
lettres * 2
=> ["c", "d", "c", "d"]
lettres + ["e", "f"]
=> ["c", "d", "c", "d", "e", "f"]
Ajout d'un seul élément :
<tableau> << <un seul elt>
#exemple :
lettres << "g"
=> ["c", "d", "c", "d", "e", "f", "g"]
Sortie du tableau (comme une pile) :
lettres.pop
#=> "g"
lettres.pop
#=> "f"
lettres.pop
#=> "e"
Insertion en tête :
lettres.unshift("a")
=> ["a", "c", "d", "c", "d"]
Recherche :
lettres.empty?
=> false
lettres.include?("c")
=> true
Concaténation :
.concat(<tableau>)
Tri :
Tri alphabétique (ordre lexical) :
.sort
# Exemple fait un table de kids
kids = Array.new
# each kid is a Hash
kids << {'name'=>'Cliff', 'age'=>10}
kids << {'name'=>'Bill', 'age'=>6}
kids << {'name'=>'Andy', 'age'=>13}
# the kids sorted by name
kids.sort_by { |k| k['name'] }
# the kids sorted by age
kids.sort_by { |k| k['age'] }
Retirer les doublons :
.uniq
Parcours
Parcours avec index :
.each_with_index do |elt, i|
puts("tab[#{i}]=#{elt}")
end
.each_with_index do |array=[Array de vars], i|
...
end
Collecter :
["hi", "there"].collect{ |value|
value.capitalize
}
=> MAJ dans l'objet tableau
7.2) Hash :
.each_key
.each_value
.each do |key, value|
.invert #(clés <==> valeurs)