Introduction au langage Ruby
Introduction au langage Ruby
Yukihiro Matsumoto
Source : [Link]
Sometimes people jot down pseudo-code on
paper. If that pseudo-code runs directly on
their computers, it’s best, isn’t it? Ruby tries
to be like that, like pseudo-code that runs.
Python people say that too.
Yukihiro Matsumoto
Source : [Link]
Un petit exemple : Somme de deux tableaux
Version Ruby/PRuby
def somme_tableaux ( a , b )
c = Array . new ( a . size )
c
end
Version Java
public static int [] sommeTableaux ( int a [] , int b [] ) {
int n = a . length ;
int c [] = new int [ n ];
return c ;
}
Ruby inherited the Perl philosophy of having
more than one way to do the same thing.
Yukihiro Matsumoto
Source : [Link]
Mises en oeuvre de Ruby
Dernière version = Ruby 2.4.0 (25 décembre 2016)
Source : [Link]
Plusieurs mises en oeuvre de Ruby sont
disponibles
$ rvm list known
# MRI Rubies
[ruby-]1.8.6[-p420]
[ruby-]1.8.7[-head] # security released on head
[ruby-]1.9.1[-p431]
[ruby-]1.9.2[-p330]
[ruby-]1.9.3[-p551]
[ruby-]2.0.0[-p643]
[ruby-]2.1.4
[ruby-]2.1[.5] # GoRuby
[ruby-]2.2[.1] goruby
[ruby-]2.2-head
# Topaz
ruby-head topaz
# JRuby # MagLev
jruby-1.6.8 maglev[-head]
maglev-1.0.0
jruby[-1.7.19]
jruby-head # Mac OS X Snow Leopard Or Newer
jruby-[Link].pre1 macruby-0.10
macruby-0.11
# Rubinius macruby[-0.12]
macruby-nightly
rbx-1.4.3
macruby-head
rbx-2.4.1
rbx[-2.5.2] # IronRuby
rbx-head ironruby[-1.1.3]
ironruby-head
# Opal
opal
[Link]
4.2 Compilation et exécution de pro-
grammes Ruby
$ cat hello0 . rb
puts ’ Bonjour le monde ! ’
$ ruby hello0 . rb
Bonjour le monde !
–––––––––––––––––––––––––––––––––––––––––––––––-
$ cat hello1 . rb
# !/ usr / bin / env ruby
$ ls -l hello1 . rb
- rwxr - xr - x . 1 tremblay tremblay 46 26 jun 09:52 hello1 . rb *
$ ./ hello1 . rb
Bonjour le monde !
4.3 irb : Le shell interactif Ruby
• Première façon facile pour interagir avec Ruby
— et comprendre comment Ruby fonctionne
$ irb --prompt=simple
>> 10
= > 10
>> 2 + 4
=> 6
>> 8 * 100 / 2
= > 400
>> _ + _
= > 800
>> _ / 3
= > 266
>> _ / 3.0
= > 88.66666666666667
# On peut creer une nouvelle " session " ( interne ) qui modifie
# l ’ objet courant .
>> irb [10 , 20]
>> self
= > [10 , 20]
>> size
=> 2
>> ^ D
= > #< IRB :: Irb : @context =#< IRB :: Context :0 x0000000170a660 > ,
@signal_status =: IN_EVAL , @scanner =#< RubyLex :0 x0000000191a
>> self
= > [10 , 20]
4.4 Tableaux
Exemple Ruby 4.3 Les tableaux et leurs opérations de base.
>> # V a l e u r s l i t t e r a l e s , i n d e x a t i o n e t t a i l l e .
? > a = [10 , 20 , 30]
= > [10 , 20 , 30]
>> a [0]
= > 10
>> a [2]
= > 30
>> a [2] = 55
= > 55
>> a
= > [10 , 20 , 55]
>> a . size
=> 3
?> # V a l e u r n i l p a r d e f a u t et e x t e n s i o n de la t a i l l e .
? > a [6]
= > nil
>> a . size
=> 3
>> a [5] = 88
= > 88
>> a . size
= > ??
>> a
= > ??
?> # V a l e u r n i l p a r d e f a u t et e x t e n s i o n de la t a i l l e .
? > a [6]
= > nil
>> a . size
=> 3
>> a [5] = 88
= > 88
>> a . size
=> 6
>> a
= > [10, 20, 55, nil, nil, 88]
?> # A c c e s au ’ d e r n i e r ’ e l e m e n t .
? > a [ a . size -1]
= > 88
>> a [ -1]
= > 88
Autre forme de commentaire :
= begin
Blah blah
...
= end
Exemple Ruby 4.4 Les tableaux et leurs opérations de base (suite 1).
?> # T a b l e a u x h e t e r o g e n e s .
?> a
= > [10 , 20 , 55 , nil , nil , 88]
>> a
= > [10 , 20 , 55 , nil , nil , 88 , nil , nil , " abc " ]
?> # A j o u t d ’ e l e m e n t s .
? > a = []
= > []
>> a << 12
= > [12]
?> # T r a n c h e s de t a b l e a u x .
? > a = [10 , 20 , 30 , 40 , 50]
= > [10 , 20 , 30 , 40 , 50]
>> a [0..2]
= > [10 , 20 , 30]
>> a [3..3]
= > ??
>> a [7..7]
= > ??
?> # T r a n c h e s de t a b l e a u x .
? > a = [10 , 20 , 30 , 40 , 50]
= > [10 , 20 , 30 , 40 , 50]
>> a [0..2]
= > [10 , 20 , 30]
>> a [3..3]
= > [40]
>> a [7..7]
= > nil
?> # I n t e r v a l l e s i n c l u s i f s vs . e x c l u s i f s
>> a
= > [10 , 20 , 30 , 40 , 50]
>> a [1..3]
= > [20 , 30 , 40]
>> a [1...3]
= > [20 , 30]
>> # S t r i n g s e m b l a b l e a A r r a y .
? > s1 = ’ abc ’
= > " abc "
>> s1 . size
=> 3
>> s1
= > " abc "
>> s1
= > " abcdef "
Exemple Ruby 4.7 Les chaînes de caractères et leurs opérations de base (suite).
>> # E g a l i t e d e v a l e u r * s a n s * p a r t a g e d e r e f e r e n c e .
? > a , b = ’ abc ’ , ’ abc ’
= > [ " abc " , " abc " ]
>> a == b
= > true
>> a . equal ? b
= > false
>> a [0] = ’X ’
=> "X"
>> a
= > " Xbc "
>> b
= > " abc "
?> # E g a l i t e de v a l e u r * a v e c * p a r t a g e de r e f e r e n c e .
? > a = b = ’ abc ’
= > " abc "
>> a == b
= > true
>> a . equal ? b
= > true
>> a [0] = ’X ’
=> "X"
>> a
= > " Xbc "
>> b
= > " Xbc "
Exemple Ruby 4.8 Interpolation d’une expression dans une chaîne.
>> # I n t e r p o l a t i o n d ’ u n e e x p r e s s i o n d a n s u n e c h a i n e .
? > x = 123
= > 123
>> s
= > " abc \ ndef \ nghi \ n "
>> : a . object_id
= > 365128
>> : a . object_id
= > 365128
>> # D e f i n i t i o n d ’ u n h a s h .
? > hash = { : abc = > 3 , : de = > 2 , : ghijk = > 5 }
= > {: abc = >3 , : de = >2 , : ghijk = >5}
?> # P r i n c i p a l e s p r o p r i e t e s .
? > hash . size
=> 3
>> # I n d e x a t i o n .
? > hash [: abc ]
= > ??
>> hash [: de ]
= > ??
?> # P r i n c i p a l e s p r o p r i e t e s .
? > hash . size
=> 3
>> # I n d e x a t i o n .
? > hash [: abc ]
=> 3
>> hash [: de ]
=> 2
?> # D e f i n i t i o n d ’ u n e n o u v e l l e c l e .
? > hash . include ? " de "
= > false
?> # R e d e f i n i t i o n d ’ u n e c l e e x i s t a n t e .
? > hash [: abc ] = 2300
= > 2300
>> hash
= > {: abc = >2300 , : de = >2 , : ghijk = >5 , " de " = >55}
Exemple Ruby 4.13 Les hashes et leurs opérations de base (suite) : Création et
initialisation.
?> # C r e a t i o n d ’ un H a s h s a n s v a l e u r p a r d e f a u t .
? > h1 = {} # I d e m : h 1 = H a s h . n e w
= > {}
>> h1 [: xyz ]
= > nil
>> # C r e a t i o n d ’ u n H a s h a v e c v a l e u r p a r d e f a u t .
? > h2 = Hash . new ( 0 )
= > {}
>> h2 [: xyz ]
=> 0
>> h2 [: abc ] += 1
=> 1
>> # C r e a t i o n d ’ u n H a s h a v e c v a l e u r p a r d e f a u t .
# A t t e n t i o n : La valeur est * partagee *
# par toutes les cles !
? > h3 = Hash . new ( [] )
= > {}
>> p h3 [: x ] , h3 [: y ]
[]
[]
= > [[] , []]
>> # C r e a t i o n d ’ u n H a s h a v e c v a l e u r p a r d e f a u t ,
# definie via un bloc pour avoir
# une nouvelle valeur a chaque fois .
>> h4 = Hash . new { |h , k | h [ k ] = [] }
= > {}
>> p h4 [: x ] , h4 [: y ]
[]
[]
= > [[] , []]
>> # T o u t e v a l e u r d i f f e r e n t e d e f a l s e o u n i l e s t v r a i e .
? > true ? ’ oui ’ : ’ non ’
= > " oui "
?> # S e u l s f a l s e et n i l ne s o n t p a s v r a i e s .
? > false ? ’ oui ’ : ’ non ’
= > " non "
?> # S e u l n i l e s t n i l
? > 2. nil ? ? ’ nil ’ : ’ pas nil ’
= > " pas nil "
>? # L ’ o p e r a t e u r | | r e t o u r n e l a p r e m i e r e e x p r e s s i o n
# ’ non fausse ’, sinon retourne la derniere expression .
? > 2 || 3
= > ??
>> x
NameError : undefined local variable or method ’x ’ for main : Ob
[...]
>> x ||= 3
=> 3
>> x
=> 3
>> x ||= 8
=> 3
>> x
=> 3
Abréviations :
x += 1 # x = x + 1
x /= 2 # x = x / 2
>> # D e f i n i t i o n e t a p p e l s d e m e t h o d e .
def add ( x , y )
x + y
end
>> add ( 2 , 3 )
=> 5
>> add 20 , 30 # Les parentheses sont optionnelles .
=> 50
>> # R e s u l t a t = d e r n i e r e e x p r e s s i o n e v a l u e e .
def abs ( x )
if x < 0 then -1 * x else x end
end
>> abs ( 3 )
=> 3
>> abs ( -3 )
=> 3
>> # O n u t i l i s e r e t u r n p o u r s o r t i r ’ a v a n t l a f i n ’ .
def abs2 ( x )
return x if x >= 0
-x
end
>> abs2 ( 23 )
=> 23
>> abs2 ( -23 )
=> 23
Remarque : «;» est un séparateur!
def add ( x , y ); x + y; end
def add ( x , y )
return x + y
end
Attention : Parenthèses et appels de méthodes :
add ( 2, 3 ) # OK ,
add 2, 3 # OK ,
add ( 2, 3 ) # Pas OK /
>? # U n o p e r a t e u r e s t u n e m e t h o d e .
?> 2 + 3
=> 5
>> 2.+( 3 )
=> 5
>> 2.+ 3
=> 5
>? # U n a p p e l d e m e t h o d e e s t u n e n v o i d e m e s s a g e .
>? 2.+( 3 )
=> 5
>> 2. send ( :+ , 3 )
=> 5
4.10 Structures de contrôle
Exemple Ruby 4.20 Structures de contrôles: if.
>> # I n s t r u c t i o n c o n d i t i o n n e l l e c l a s s i q u e .
def div ( x , y )
if y == 0
fail " Oops ! Division par zero :( "
else
x / y
end
end
>> div ( 12 , 3 )
=> 4
>> div ( 12 , 0 )
RuntimeError : Oops ! Division par zero :(
from ( irb ):4:in ’ div ’
[...]
from / home / tremblay /. rvm / rubies / jruby -[Link]/ bin / irb :
>> # G a r d e ( c o n d i t i o n ) i f a s s o c i e e a u n e i n s t r u c t i o n .
def div ( x , y )
fail " Oops ! Division par zero :( " if y == 0
x / y
end
>> div ( 12 , 3 )
=> 4
Exemple Ruby 4.21 Structures de contrôles: while.
?> # I n s t r u c t i o n w h i l e .
def pgcd ( a , b )
# On doit avoir a <= b .
return pgcd ( b , a ) if a > b
while b > 0
a, b = b, a % b
end
a
end
>> pgcd ( 12 , 8 )
=> 4
>> pgcd ( 80 , 120 )
=> 40
Affectations multiples (parallèles) :
x, y = y, x
x , y , z = [10 , 20 , 30]
# x == 10 && y == 20 && z == 30
x , y = [10 , 20 , 30]
# x == 10 && y == 20
x , *y = [10 , 20 , 30]
# x == 10 && y == [20 , 30]
Exemple Ruby 4.22 Structures de contrôles : Itération sur les index avec for et
each_index.
?> # I n s t r u c t i o n f o r
def somme ( a )
total = 0
for i in 0... a . size
total += a [ i ]
end
total
end
?> # I t e r a t e u r e a c h _ i n d e x .
def somme ( a )
total = 0
a . each_index do | i |
total += a [ i ]
end
total
end
total
end
?> # I t e r a t e u r e a c h .
def somme ( a )
total = 0
a . each do | x |
total += x
end
total
end
?> # A r g u m e n t o p t i o n n e l et v a l e u r p a r d e f a u t .
def foo ( x , y = 40 )
x + y
end
>> foo ( 3 , 8 )
= > ??
>> foo ( 3 )
= > ??
?> # A r g u m e n t o p t i o n n e l et v a l e u r p a r d e f a u t .
def foo ( x , y = 40 )
x + y
end
>> foo ( 3 , 8 )
= > 11
>> foo ( 3 )
= > 43
>> # N o m b r e v a r i a b l e d ’ a r g u m e n t s .
def bar ( x , * args , y )
" bar ( #{ x } , #{ args } , #{ y } ) "
end
>> bar ( 1 , 2 , 3 , 4 , 5 )
= > ??
>> bar ( 1 , 2 )
= > ??
>> bar ( 23 )
??
??
??
??
>> # N o m b r e v a r i a b l e d ’ a r g u m e n t s .
def bar ( x , * args , y )
" bar ( #{ x } , #{ args } , #{ y } ) "
end
>> bar ( 1 , 2 , 3 , 4 , 5 )
= > " bar ( 1 , [2 , 3 , 4] , 5 ) "
>> bar ( 1 , 2 )
= > " bar ( 1 , [] , 2 ) "
>> bar ( 23 )
ArgumentError : wrong number of arguments (1 for 2+)
from ( irb ):24:in ’ bar ’
from ( irb ):27
from / home / tremblay /. rvm / rubies / ruby -2.1.4/ bin / irb
Exemple Ruby 4.25 Paramètres des méthodes : arguments par mots-clés (keyword
arguments).
>> # A r g u m e n t s p a r m o t - c l e s ( k e y w o r d a r g u m e n t s ) .
def diviser ( numerateur : , denominateur : 1 )
numerateur / denominateur
end
>> diviser 10
ArgumentError : missing keyword : numerateur
from ( irb ):31
from / home / tremblay /. rvm / rubies / ruby -2.1.4/ bin / irb :1
?> # A r g u m e n t p a r mot - c l e .
def premier_index ( a , x , res_si_absent : nil )
a . each_index do | i |
return i if a [ i ] == x
end
res_si_absent
end
x * y
end
Indiquez ce qui sera affiché par chacun des appels suivants :
# a.
puts foo ( 2 , 3 )
# b.
puts foo 2 , 3 , 5
# c.
puts foo ( " ab " , " cd " , 3 )
# d.
puts foo ( " ab " , " cd " )
m
end
# a.
puts bar
# b.
puts bar ( 123 )
# c.
puts bar ( 0 , 10 , 20 , 99 , 12 )
puts foo ( 10 , 20 , 30 )
Qu’est-ce qui sera affiché?
Exercice 4.3: Définition d’une méthode avec plusieurs
sortes d’arguments.
4.12 Définitions de classes
Exemple Ruby 4.26 Un script avec une classe (simple) pour des cours.
$ cat cours . rb
# Definition d ’ une classe ( simple !) pour des cours .
class Cours
attr_reader : sigle
def to_s
sigles_prealables = " "
@prealables . each do | c |
sigles_prealables << " #{ c . sigle } "
end
if $0 == __FILE__
# Definition de quelques cours .
inf1120 = Cours . new ( : INF1120 , ’ Programmation I ’ )
inf1130 = Cours . new ( : INF1130 , ’ Maths pour informaticien ’
inf2120 = Cours . new ( : INF2120 , ’ Programmation II ’ ,
inf1120 )
inf3105 = Cours . new ( : INF3105 , ’ Str . de don . ’ ,
inf1130 , inf2120 )
puts inf1120
puts inf3105
puts inf1120 . sigle
puts inf1120 . titre
end
Exemple Ruby 4.27 Appel du script avec une classe pour des cours.
$ ruby cours . rb
< INF1120 ’ Programmation I ’ ( ) >
< INF3105 ’ Str . de don . ’ ( INF1130 INF2120 ) >
INF1120
NoMethodError : undefined method ‘ titre ’ for #< Cours :0 x13969f
( root ) at cours . rb :34
Une «déclaration» «attr_reader :sigle» définit
un attribut accessible en lecture, équivalent à la
méthode suivante :
def sigle
@sigle
end
>> # U n e l a m b d a - e x p r e s s i o n r e p r e s e n t e u n o b j e t ,
# de c l a s s e P r o c , q u ’ o n p e u t ’ a p p e l e r ’.
# Un Proc est donc une " f o n c t i o n a n o n y m e ".
? > lambda { 0 }. call
=> 0
>> # U n e m e t h o d e p o u r e x e c u t e r d e u x f o i s d u c o d e ( s a n s a r g . )
def deux_fois ( f )
f . call
f . call
end
?> # Ici , l e s () s o n t o b l i g a t o i r e s , s i n o n e r r e u r de s y n t a x e .
?> deux_fois ( lambda do
print ’ Bonne ’
print ’ journee !\ n ’
end )
Bonne journee !
Bonne journee !
= > nil
Exemple Ruby 4.30 Les lambda-expressions, comme n’importe quel objet, peu-
vent être retournées comme résultat d’une fonction.
?> # U n e l a m b d a - e x p r e s s i o n p e u t e t r e r e t o u r n e e c o m m e r e s u l t a
? > def plus_x ( x )
lambda { | y | x + y }
end
>> x = 999
= > 999
>> inc .( 3 )
=> 4
Pour la classe Cours :
a. each_index do |i|
total += a[i]
end
a. each_index do |i|
total += a[i]
end
• mais. . .
>> deux_fois do
print ’ Bonne ’
print ’ journee !\ n ’
end
Bonne journee !
Bonne journee !
= > nil
>> deux_fois
LocalJumpError : no block given ( yield )
from ( irb ):1:in ’ deux_fois ’
from ( irb ):3
from / home / tremblay /. rvm / rubies / ruby -2.1.4/ bin / irb :
>> # M e t h o d e p o u r e x e c u t e r k f o i s d u c o d e .
def k_fois ( k )
k . times do
yield
end
end
>> k_fois ( 3 ) do
print ’ Bonne ’
print ’ journee !\ n ’
end
Bonne journee !
Bonne journee !
Bonne journee !
Exemple Ruby 4.34 Une méthode pour évaluer une expression — avec lambda,
avec bloc implicite et avec bloc explicite.
>> # M e t h o d e p o u r e v a l u e r u n e e x p r e s s i o n : a v e c l a m b d a .
def evaluer ( x , y , expr )
expr . call ( x , y )
end
–––––––––––––––––––––––––––––––––––––––––––––––-
>> # M e t h o d e p o u r e v a l u e r u n e e x p r e s s i o n : a v e c b l o c i m p l i c i t
def evaluer ( x , y )
yield ( x , y )
end
>> evaluer ( 10 , 20 ) { |a , b | a * b }
= > 200
>> # M e t h o d e p o u r e v a l u e r u n e e x p r e s s i o n : a v e c b l o c e x p l i c i t
def evaluer ( x , y , & expr )
expr . call ( x , y )
end
>> evaluer ( 10 , 20 ) { |a , b | b / a }
=> 2
>> # O n p e u t v e r i f i e r s i u n b l o c a e t e p a s s e o u n o n .
def evaluer ( x , y )
return 0 unless block_given ?
yield ( x , y )
end
>> evaluer ( 10 , 20 ) { |a , b | b / a }
=> 2
>> evaluer ( 10 , 20 )
=> 0
>> def foo ( & b )
[ b . class , b . arity , b . parameters ] if block_given ?
end
= > : foo
>> foo
= > nil
>> foo { 2 }
= > [ Proc , 0 , []]
>> foo { | x | x + 1 }
= > [ Proc , 1 , [[: opt , : x ]]]
Remarque concernant les deux formes de bloc :
Au niveau sémantique, les deux formes de blocs —
avec accolades {... } et avec do... end — sont
équivalentes.
Il existe toutefois une différence au niveau de la
priorité lors de l’analyse syntaxique :
# Équivalent
foo ( bar () { ... } )
# Équivalent
foo ( bar () ) { ... }
4.15 Portée des variables
sigil (Ésotérisme) Symbole graphique ou sceau
représentant une intention ou un être magique.
Source : [Link]
>> # U n e d e f i n i t i o n d e m e t h o d e n e v o i t p a s
# les variables non - l o c a l e s .
? > x = 22
= > 22
>> set_x
= > 88
>> x # Inchangee !
= > 22
?> # Un b l o c c a p t u r e l e s v a r i a b l e s non - l o c a l e s
# si elles existent .
? > def executer_bloc
yield
end
= > : executer_bloc
>> x = 44
= > 44
>> executer_bloc { x = 55 }
= > 55
>> x # Modifiee !
= > 55
?> # Si la v a r i a b l e n ’ e x i s t e p a s deja ,
# alors est strictement locale au bloc .
?> z
NameError : undefined local variable or method ’z ’ for main : Ob
[...]
? > executer_bloc { z = 88 }
= > 88
>> z
NameError : undefined local variable or method ’z ’ for main : Ob
[...]
>> # U n e v a r i a b l e g l o b a l e e s t a c c e s s i b l e p a r t o u t !
? > $x_glob = 99
= > 99
>> set_x_glob
= > " abc "
>> $x_glob
= > " abc "
>> $x_glob
= > [10 , 20]
>> # U n e v a r i a b l e l o c a l e e s t a c c e s s i b l e d a n s l ’ e n s e m b l e
# de la methode .
? > def foo ( x )
if x <= 0 then a = 1 else b = " BAR " end
[a , b ]
end
= > : foo
>> foo ( 0 )
= > [1 , nil ]
>> foo ( 99 )
= > [ nil , " BAR " ]
>> # M a i s u n b l o c d e f i n i t u n e n o u v e l l e p o r t e e , a v e c d e s v a r i
# strictement locales !
? > def bar ( * args )
args . each do | x |
r = 10
puts x * r
end
r
end
= > : bar
>> bar ( 10 , 20 )
100
200
NameError : undefined local variable or method ’r ’ for main : Ob
[...]
4.16 Modules
Modules are a way of grouping together meth-
ods, classes, and constants. Modules give
you two major benefits:
1. Modules provide a namespace and prevent
name clashes.
2. Modules implement the mixin facility.
Source : [Link]
Exemple Ruby 4.36 Les modules comme espaces de noms.
module M1
C1 = 0
end
module M2
C1 = ’ abc ’
end
module M3
module M4
C1 = : c1
end
end
M1 :: C1 == 0 # => true
M2 :: C1 == ’ abc ’ # => true
M3 :: M4 :: C1 == : c1 # => true
M1 :: C1 != M2 :: C1 # => true
M1 :: C1 != M3 :: M4 :: C1 # => true
...
module Module1
def self . zero
0
end
def un
1
end
def val_x
@x
end
def inc_inc ( y )
inc ( y )
inc ( y )
end
end
class C1
include Module1
def initialize ( x )
@x = x
end
def inc ( y )
@x += y
end
end
class C2
include Module1
end
Exemple Ruby 4.37 Un module mixin Module1 et son utilisation.
>> # A p p e l s u r l e m o d u l e d e l a m e t h o d e d e c l a s s e .
? > Module1 . zero
=> 0
>> # A p p e l s u r l e m o d u l e d e l a m e t h o d e d ’ i n s t a n c e .
? > Module1 . un
NoMethodError : undefined method ’ un ’ for Module1 : Module
...
>> c1 . zero
NoMethodError : undefined method ’ zero ’ for #< C1 :0 x12cf7ab @x
...
>> c1 . un
=> 1
>> c1 . val_x
= > 99
>> c1 . inc_inc ( 100 )
= > 299
>> # A p p e l s u r u n o b j e t C 2 d e s m e t h o d e s
?> # de c l a s s e et d ’ i n s t a n c e du m o d u l e .
? > c2 = C2 . new
= > #< C2 :0 x1a8622 >
>> c2 . un
=> 1
>> c2 . val_x
= > nil
>> c2 . inc_inc ( 100 )
NoMethodError : undefined method ’ inc ’ for #< C2 :0 x1a8622 >
...
NomDuModule . nom_methode
NomDuModule :: nom_methode
module Module1
def self . zero
0
end
def un
1
end
def val_x
@x
end
def inc_inc ( y )
inc ( y ); inc ( y )
end
end
? > Module1 . un
??
...
def inc_inc ( y )
inc ( y ); inc ( y )
end
end
#
? > c1 = C1 . new ( 99 )
= > #<C1:0x12cf7ab @x=99>
>> c1 . zero
??
...
>> c1 . un
= > ??
>> c1 . val_x
= > ??
def un
1
end
def val_x
@x
end
def inc_inc ( y )
inc ( y ); inc ( y )
end
end
#
? > c2 = C2 . new
= > #<C2:0x1a8622>
>> c2 . un
= > ??
>> c2 . val_x
= > ??
def un
1
end
def val_x
@x
end
def inc_inc ( y )
inc ( y ); inc ( y )
end
end
? > Module1 . un
NoMethodError: undefined method ’un’ for Module1:Module
...
def inc_inc ( y )
inc ( y ); inc ( y )
end
end
#
? > c1 = C1 . new ( 99 )
= > #<C1:0x12cf7ab @x=99>
>> c1 . zero
NoMethodError: undefined method ’zero’ for #<C1:0x12cf7ab @x=99>
...
>> c1 . un
=> 1
>> c1 . val_x
= > 99
def un
1
end
def val_x
@x
end
def inc_inc ( y )
inc ( y ); inc ( y )
end
end
#
? > c2 = C2 . new
= > #<C2:0x1a8622>
>> c2 . un
=> 1
>> c2 . val_x
= > nil
?>> # La c l a s s e A r r a y d e f i n i t la m e t h o d e e a c h et
# inclut le module Enumerable .
?> # A p p a r t e n a n c e d ’ un e l e m e n t .
? > a . include ? 20
= > true
?> # A p p l i c a t i o n f o n c t i o n n e l l e .
? > a . map { | x | x + 2 } # Synonyme = collect .
= > [12 , 22 , 32 , 42]
>> a ??
= > ??
?> # A p p l i c a t i o n i m p e r a t i v e ( m u t a b l e )!
>> a . map ! { | x | 10 * x }
= > [100 , 200 , 300 , 400]
>> a ??
= > ??
>> a
= > [10 , 20 , 30 , 40]
?> # A p p l i c a t i o n f o n c t i o n n e l l e .
? > a . map { | x | x + 2 } # Synonyme = collect .
= > [12 , 22 , 32 , 42]
?> # A p p l i c a t i o n i m p e r a t i v e ( m u t a b l e )!
>> a . map ! { | x | 10 * x }
= > [100 , 200 , 300 , 400]
>> a
= > [100 , 200 , 300 , 400]
? > a . reduce { |x , y | x + y } # S y n o n y m e = i n j e c t .
= > 1000
>> a . reduce ( :+ )
= > 1000
>> a . reduce ( :* )
= > 2400000000
>> a . map { | x | x / 10 }
= > ??
>> a . map { | x | x / 10 }
= > [10, 20, 30, 40]
>> a . group_by { | x | x % 2 }
= > {0= >[100 , 200 , 300 , 400]}
module Enumerable
def include ?( elem )
each do | x |
return true if x == elem
end
false
end
def find
each do | x |
return x if yield ( x )
end
nil
end
accum
end
end
Donnez une mise en oeuvre, dans un style fonctionnel, de la
méthode to_s de la classe Cours vue précédemment.
Exercice 4.7: Mise en oeuvre fonctionnelle de Cours#to_s.
4.17.2 Module Comparable
La figure ci-bas présente la liste des méthodes du
module Comparable, c’est-à-dire, les diverses métho-
des disponibles lorsque la méthode <=> est définie
par une classe et que le module Comparable est
inclus (avec include)!
Exemple Ruby 4.40 Tris avec Enumerable et <=>.
>> a . sort
= > [10 , 29 , 33 , 44]
class Cours
include Comparable
if $0 == __FILE__
# Definition de quelques cours .
inf1120 = Cours . new ( : INF1120 , ’ Programmation I ’ )
inf1130 = Cours . new ( : INF1130 , ’ Maths pour informaticien ’
inf2120 = Cours . new ( : INF2120 , ’ Programmation II ’ , inf1120
inf3105 = Cours . new ( : INF3105 , ’ Str . de don . ’ , inf1130 , in
# Quelques expressions
puts inf3105 < inf1120
puts inf2120 >= inf1130
cours . sort . each { | c | puts c }
end
---- ------- ------- ------- ------ -----
res
end
end
end
class Ensemble
include Enumerable
self
end
def each
@elements . each do | x |
yield ( x )
end
end
def cardinalite
count
end
def contient ?( x )
include ? x
end
def to_s
" { " << map { | x | x . to_s }. join ( " , " ) << " } "
end
end
Pourquoi la méthode << retourne-t-elle self?
Que se passe-t-il si on omet self?
Exercice 4.9: Pourquoi la méthode << retourne-t-elle self?
alias : cardinalite : count
alias : contient ? : include ?
Exemple Ruby 4.43 Quelques expressions utilisant un objet Ensemble.
?> # C r e e un e n s e m b l e a v e c d i v e r s e l e m e n t s .
? > ens = Ensemble . new << 1 << 5 << 3
def select
...
end
end
>> re = / ab .* zz$ /
=> / ab .* zz$ /
>> re . class
=> Regexp
# Autre facon .
>> re = % r { ab .* zz$ }
= > / ab .* zz$ /
Exemple Ruby 4.45 Une expression régulière peut être utilisée dans une opération
de pattern-matching avec «=˜».
>> motif . match " Tel .: 514 -987 -3000 ext . 8213 "
= > #< MatchData " 514 -987 -3000 " 1: " 514 " 2: " 987 -3000 " >
Exemple Ruby 4.48 Début/fin de chaine vs. début/fin de ligne.
>> puts $1 , $2 , $3
ab
cd
ef
= > nil
>> puts $1 , $2 , $3
ab
ef
= > nil
>> $1
= > " cccddccddcc "
>> $1
= > " ccc "
Exemple Ruby 4.51 Autre caractère spécial : frontière de mot.
>> # L e s o b j e t s M a t c h D a t a .
>> m . pre_match
= > " Tel .: "
>> m . post_match
= > " ext . 8213 "
Exemple Ruby 4.53 Les groupes avec noms et les variables spéciales «$i»
définies par la méthode «=˜».
>> m = /(? < code_reg >#{ CODE_REG }) -(? < tel >#{ TEL })/.
match " Tel .: 514 -987 -3000 ext . 8213 "
= > #< MatchData " 514 -987 -3000 " code_reg : " 514 "
tel : " 987 -3000 " >
>> m [: code_reg ]
= > " 514 "
>> m [: tel ]
= > " 987 -3000 "
m = code_permanent
. match " CP : DEFG11229988 . "
p m [1]
p m [5]
p m . pre_match
p m . post_match
Exercice 4.11: Objet MatchData.
4.20 Interactions avec l’environnement
4.20.1 Arguments du programme
Exemple Ruby 4.54 Les arguments d’un programme Ruby et les variables
d’environnement.
$ cat argv . rb
# !/ usr / bin / env ruby
i = 0
while arg = ARGV . shift do
puts " ARGV [#{ i }] = ’#{ arg } ’ (#{ arg . class }) "
i += 1
end
$ ./ argv . rb
ENV [ ’ FOO ’] = ’’
-----
$ ./ argv . rb 1234 ’ abc " " def ’ abc def " ’"
ARGV [0] = ’1234 ’ ( String )
ARGV [1] = ’ abc " " def ’ ( String )
ARGV [2] = ’abc ’ ( String )
ARGV [3] = ’def ’ ( String )
ARGV [4] = ’’’ ( String )
ENV [ ’ FOO ’] = ’’
-----
# b.
NB =2 ./ argv2 . rb [1 , 2] [3]
# c.
unset NB ; ./ argv2 . rb [1009 , 229342] [334]
Exercice 4.12: Utilisation de ARGV et ENV.
4.20.2 Écriture sur le flux de sortie stan-
dard : printf, puts, print et p
Exemple Ruby 4.55 Exemples d’utilisation de printf, sprintf et print.
>> res
= > " 123\ n "
$ cat print - et - al . rb
# !/ usr / bin / env ruby
$ ./ print - et - al . rb
*** Avec puts :
123
...
123
...
*** Avec p :
123
...
" 123 "
...
Exemple Ruby 4.57 Écriture d’un tableau d’entiers ou un tableau de chaines.
$ cat print - et - al . rb
# !/ usr / bin / env ruby
imprimer ( : puts , [123 , 456] , [ " 123 " , " 456 " ] )
puts
imprimer ( :p , [123 , 456] , [ " 123 " , " 456 " ] )
$ ./ print - et - al . rb
*** Avec puts :
123
456
...
123
456
...
*** Avec p :
[123 , 456]
...
[ " 123 " , " 456 " ]
...
Exemple Ruby 4.58 Écriture d’un objet qui n’a pas de méthodes to_s et
inspect.
$ cat print - et - al . rb
# !/ usr / bin / env ruby
class Bar
def initialize ( val ); @val = val ; end
end
$ ./ print - et - al . rb
*** Avec puts :
#< Bar :0 x000000015022a0 >
...
*** Avec p :
#< Bar :0 x00000001501f80 @val =10 >
...
Exemple Ruby 4.59 Écriture d’un objet qui a des méthodes to_s et inspect.
$ cat print - et - al . rb
# !/ usr / bin / env ruby
class Foo
def initialize ( val ); @val = val ; end
def inspect ; "#< Foo : val =#{ @val } > " ; end
end
$ ./ print - et - al . rb
*** Avec puts :
10
...
*** Avec p :
#< Foo : val =10 >
...
4.20.3 Manipulation de fichiers
Exemple Ruby 4.60 Différentes façon de lire et d’afficher sur stdout le contenu
d’un fichier texte.
$ cat cat . rb
# !/ usr / bin / env ruby
xxx
...
xxx
...
Exemple Ruby 4.60 Différentes façon de lire et d’afficher sur stdout le contenu
d’un fichier texte.
$ cat cat . rb
# !/ usr / bin / env ruby
fich . close
xxx
...
xxx
...
Exemple Ruby 4.60 Différentes façon de lire et d’afficher sur stdout le contenu
d’un fichier texte.
$ cat cat . rb
# !/ usr / bin / env ruby
xxx
...
xxx
...
Exemple Ruby 4.60 Différentes façon de lire et d’afficher sur stdout le contenu
d’un fichier texte.
$ cat cat . rb
# !/ usr / bin / env ruby
xxx
...
xxx
...
Figure 4.5: Modes d’ouverture des fichiers (source : http:
//[Link]/core-2.0.0/[Link]).
Exemple Ruby 4.61 Différentes façon de lire et d’afficher sur stdout le con-
tenu d’un fichier texte, dont une façon qui permet de recevoir les données par
l’intermédiaire du flux standard d’entrée.
$ cat cat . rb
# !/ usr / bin / env ruby
xxx
...
xxx
...
xxx
...
4.20.4 Exécution de commandes
Exemple Ruby 4.62 Exécution de commandes externes avec backticks ou %x{...}
>> # E x e c u t i o n a v e c b a c k t i c k s .
>> ext = ’ rb ’
= > " rb "
>> $ ?
= > #< Process :: Status : pid 30019 exit 0 >
>> # E m i s s i o n s u r s t d e r r v s . s t d o u t
>> % x { ls www_xx_z }
ls : impossible d’accéder à www_xx_z :
Aucun fichier ou dossier de ce type
=> ""
$ cat commandes2 . rb
require ’ open3 ’
Open3 . popen3 ( " wc - lw " ) do | stdin , stdout , stderr |
stdin . puts [ " abc def " , " " , " 1 2 3 " ]
stdin . close
$ ./ commandes2 . rb
-- stdout - -
3 5
-- stderr - -
Exemple Ruby 4.64 Exécution de commandes externes avec Open3.popen3.
$ cat commandes3 . rb
require ’ open3 ’
Open3 . popen3 ( " wc - lw xsfdf . txt " ) do |_ , out , err |
puts " -- out - - "
puts out . readlines
puts " -- err - - "
puts err . readlines
puts
end
$ ./ commandes3 . rb
-- out - -
-- err - -
wc : xsfdf . txt : Aucun fichier ou dossier de ce type
4.21 Traitement des exceptions
4.21.1 Classe Exception et sous-classes stan-
dards
NoMemoryError
ScriptError
LoadError
NotImplementedError
SyntaxError
SignalException
Interrupt
StandardError -- default for rescue
ArgumentError
IndexError
StopIteration
IOError
EOFError
LocalJumpError
NameError
NoMethodError
RangeError
FloatDomainError
RegexpError
RuntimeError -- default for raise
SecurityError
SystemCallError
Errno::*
SystemStackError
ThreadError
TypeError
ZeroDivisionError
SystemExit
fatal -- impossible to rescue
Exemple Ruby 4.65 Une méthode div qui attrape et traite diverses exceptions.
>> div 3 , 0
*** Division par 0 ( divided by 0)
[ " ( irb ):4: in ’/ ’ " ,
" ( irb ):4: in ’ div ’" , " ( irb ):14: in ’ irb_binding ’" ,
" / home / tremblay /. rvm / rubies / ruby -2.1.4/ lib / ruby /2.1.0/ irb / workspace . rb
...,
" / home / tremblay /. rvm / rubies / ruby -2.1.4/ bin / irb :11: in ’< main > ’ " ]
= > nil
f . inspect # P o u r v o i r l ’ e t a t f i n a l d e f .
end
= > : traiter_fichier
>> a = *10
= > [10]
>> a = *(1..10)
= > [1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10]
# Mais ...
>> *(1..10)
SyntaxError : ( irb ):41: syntax error , unexpected ’\ n ’ ,
expecting :: or ’[ ’ or ’. ’
...
>> *10
SyntaxError : ( irb ):33: syntax error , unexpected ’\ n ’ ,
expecting :: or ’[ ’ or ’. ’
...
Exemple Ruby 4.71 Utilisation de l’opérateur «*» du coté gauche d’une affecta-
tion parallèle (multiple).
>> # D a n s l a p a r t i e g a u c h e d ’ u n e a f f e c t a t i o n p a r a l l e l e , u n *
# << deconstruire > > un tableau . Dans ce cas , la variable
# prefixee avec * doit etre unique et va denoter un sous -
# d ’ elements .
>> # L ’ u t i l i s a t i o n d e * s ’ a p p l i q u e a u s s i a u x p a r a m e t r e s
# formels d ’ une methode , ainsi qu ’ aux arguments effectifs
# ( expressions passees en a r g u m e n t ).
>> def foo ( x , * args )
puts " x = #{ x } "
args . each_index { | k | puts " args [#{ k }] = #{ args [ k ]} " }
end
= > : foo
>> foo ( 10 )
x = 10
= > []
>> foo ( 10 , 20 )
x = 10
args [0] = 20
= > [20]
>> foo ( 10 , 20 , 30 )
x = 10
args [0] = 20
args [1] = 30
= > [20 , 30]
Exemple Ruby 4.73 Utilisation de l’opérateur «&» pour rendre explicite un bloc
comme paramètre d’une méthode.
>> # L ’ o p e r a t e u r p r e f i x e & u t i l i s e d e v a n t l e d e r n i e r p a r a m e t
# rend explicite le bloc transmis a l ’ appel de la methode
# Ce parametre est alors un objet Proc pouvant
# etre execute avec call .
>> call_yield ( 99 )
= > 99
>> call_yield ( 99 ) { | x | x + 10 }
= > [ Proc , 109 , 109]
Exemple Ruby 4.74 Utilisation de l’opérateur «&» pour transformer un objet
lambda ou Symbole en bloc.
>> # L ’ o p e r a t e u r p r e f i x e & d e v a n t u n e l a m b d a e x p r e s s i o n
# transforme l ’ objet Proc en un bloc .
# Ce bloc peut alors transmis explicitement comme
# dernier argument ( argument additionnel en plus
# des arguments non blocs e x p l i c i t e s ).
>> call_yield ( 2 ) { | x | 2 * x }
= > [ Proc , 4 , 4]
>> # : s . t o _ p r o c = = P r o c . n e w { | o | o . s } ( . . . o u p r e s q u e )
>> yield_un_arg ( 24 , &: even ?. to_proc )
= > true
def + @
puts " self = #{ self } "
end
end
= > :+ @
>> foo + 10
self = #< Foo :0 x000000019910c8 >; autre = 10
= > nil
>> + foo
self = #< Foo :0 x000000019910c8 >
= > nil
4.22.4 Un mini irb en une seule ligne
$ ruby -n -e ’p eval( $_ ) ’
10 + 30
40
:[Link]
Symbol
puts "10"
10
nil
ˆD
4.22.5 La méthode tap
class Object
def tap
yield self
self
end
end
$ cat tap . rb
p (1..10)
. tap { |x| puts " Original : #{ x }" }
. to_a
. tap { |x| puts " Array : #{ x} " }
. select { |x | x . even ? }
. tap { |x| puts " Paires : #{ x }" }
. map { |x| x * x }
. tap { |x| puts " Carres : #{ x }" }
$ ruby tap . rb
Original : 1..10
Array : [1 , 2, 3 , 4 , 5 , 6, 7, 8, 9, 10]
Paires : [2 , 4, 6 , 8 , 10]
Carres : [4 , 16 , 36 , 64 , 100]
[4 , 16 , 36 , 64 , 100]
4.A Installation de Ruby sur votre
machine
1. Obtenir la clé pour rvm et obtenir rvm :
$ gpg -- keyserver hkp :// keys . gnupg . net \
-- recv - keys 409 B6B1796C275462A1703113804BB82D39DC0
$ curl - sSL https :// get . rvm . io | bash -s stable
$ rvm list
def test_bar_est_initialement_0
assert_equal 0 , @foo . bar
end
...
end
Test dans le style «RSpec» :
describe Foo do
describe "# bar " do
before do
@foo = Foo . new
end
require_relative ’ ensemble ’
describe Ensemble do
before do
@ens = Ensemble . new
end
describe ’# contient ? ’ do
it " retourne faux quand un element n ’ est pas present " do
refute @ens . contient ? 10
end
# ...
Exemple Ruby 4.77 Une suite de tests pour la classe Ensemble (partie 2)
# ...
@ens << 10
assert @ens . contient ? 10
end
# ...
Exemple Ruby 4.78 Une suite de tests pour la classe Ensemble (partie 3)
# ...
describe ’# cardinalite ’ do
it " retourne 0 lorsque vide " do
@ens . cardinalite . must_equal 0
end
@[Link].must_equal 0 =
assert @ens . cardinalite == 0
assert_equal 0, @ens . cardinalite
Exemple Ruby 4.79 Des exemples d’exécution de la suite de tests pour la classe
Ensemble.
======================
Execution ordinaire
======================
$ ruby ensemble_spec.rb
Run options: --seed 43434
# Running:
........
-------------------------------------------------------------
======================
Execution ’verbeuse’
======================
$ ruby ensemble_spec.rb -v
Run options: -v --seed 18033
# Running:
# Running:
...FF...
1) Failure:
Ensemble::#cardinalite#test_0002_retourne 1 lorsqu’un seul et meme element est ajoute
1 ou plusieurs fois [ensemble_spec.rb:54]:
Expected: 1
Actual: 0
2) Failure:
Ensemble::#cardinalite#test_0003_retourne le nombre d’elements distincts peu importe\
le nombre de fois ajoutes [ensemble_spec.rb:62]:
Expected: 2
Actual: 0
gem ’ minitest ’
require ’ minitest / autorun ’
require ’ minitest / spec ’
describe Array do
let (: vide ) { Array . new }
before do
@singleton_10 = Array . new << 10
end
a . to_s
. must_match
/^\[\ s *10#{ virgule }20#{ virgule }30\ s *\] $ /
end
end
end
4.C Règles de style Ruby
Pourquoi des conventions sur le style de program-
mation sont importantes :
• 80% of the lifetime cost of a piece of soft-
ware goes to maintenance.
• Hardly any software is maintained for its
whole life by the original author.
• Code conventions improve the readability
of the software, allowing engineers to
understand new code more quickly
and thoroughly.
http: // www. oracle. com/ technetwork/ java/ index-135089. html
Une présentation assez complète des règles spéci-
fiques à Ruby :
[Link]
Principales règles que vous devriez respecter :
• Utilisation du snake_case vs. CamelCase :
– NomDeClasse
– NOM_DE_CONSTANTE
– nom_de_methode
– nom_de_parametre_ou_variable
• Indentation avec des (2) espaces blancs seule-
ment, pas de caractères de tabulation
# NON
une_methode_sans_arg ()
# OK
une_methode_sans_arg
• Opérateur ternaire ?: seulement pour une
expression sur une seule ligne.
# NON # OK
unless expr if expr
... si faux ... ... si vrai ...
else else
... si vrai ... ... si faux ...
end end
• Pour les blocs, on utilise {...} lorsque le corps
peut s’écrire sur une seule ligne.
# NON # OK
col . map do | x | ... end col . map { | x | ... }
# NON # OK
def m_rec ( ... ) def m_rec ( ... )
if expr return res_base if expr
return res_base
else ...
... res_rec
return res_rec end
end
end
• Dans une classe C, on utilise def self.m pour
définir une méthode de classe m.
• Pour les objets de classe Hash, on utilise des
Symbols comme clés :
hash = {
: cle1 = > defn1 ,
: cle2 = > defn2 ,
...
: clek = > defnk
}
Quelques remarques additionnelles concernant les
exemples :
• Des espaces sont mis autour des parenthèses des
définitions de méthodes :
# Style suggere dans le guide .
def methode (a , b , c )
...
end
res = []
a. map { |x | res << foo ( x) }
# OK
a. map { |x | foo (x ) }
• On utilise une instruction avec garde seulement
si l’instruction s’écrit sur une seule ligne :
instr if condition # O K s i i n s t r c o u r
# OK
(1.. n ). reduce (1.0) { | res , x | x == 0 ? res : res / x }
# et parce que
( res = v ) == v
4.D Méthodes attr_reader et attr_writer
Exemple Ruby 4.82 Une définition des méthodes attr_reader et attr_writer.
class Class
def attr_reader ( attr )
self . class_eval "
def #{ attr }
@ #{ attr }
end
"
end
class Foo
attr_reader : bar
attr_writer : bar
def initialize
self . bar = 0
end
end
class Class
def attr_reader_ ( attr )
self . class_eval do
define_method attr do
instance_variable_get " @ #{ attr } "
end
end
end
class Foo
attr_reader : bar
attr_writer : bar
def initialize
self . bar = 0
end
end
4.E Interprétation vs. compilation
Soit l’affirmation suivante : «Ruby est un langage inter-
prété».
Cette affirmation est-elle vraie ou fausse?
Exercice 4.13: Ruby, un langage interprété?
Pourquoi les performances d’un programme Ruby sont-elles
généralement moins bonnes (programme plus lent /) que
celles d’un programme Java?
Exercice 4.14: Performances de Ruby.