[skateinmars ] okay
[skateinmars ] donc bonsoir les gens qui sont la :-)
[skateinmars ] on va aborder la dernière partie de la série de cours consacrée à l'initiation à la programmation avec ruby
[skateinmars ] une fois terminée on pourra lancer d'autres cours plus spécifiques, par exemple sur ruby on rails
[illovae ] yeah!
[skateinmars ] donc :
[skateinmars ] Programmation avec Ruby #3
[skateinmars ] ==========================
[skateinmars ] on va commencer par décrire 2 classes qui sont souvent utilisées et que j'ai plus ou moins "zappé" auparavant : les hashes et les symboles
[skateinmars ] Hashes to hashes
[skateinmars ] ----------------
[skateinmars ] Voila un type de donnée (une classe donc :-)) que nous n'avons pas encore abordé bien qu'il soit très répandu en ruby : les hashs (classe Hash).
[skateinmars ] Un hash (appelé dictionnaire en python, ou array associatif en php), est une sorte de tableau à la différence près qu'il permet de stocker des informations sous la forme clé => valeur.
[skateinmars ] Un exemple assez parlant :
[skateinmars ] notes = {"jean" => 20, "paul" => 12, "eric" => "dix"}
[skateinmars ] Comme pour un array on peut accéder aux éléments d'un hash avec [] :
[skateinmars ] notes["jean"] #=> 20
[skateinmars ] Notez par contre que les éléments d'un hash ne sont pas ordonnés (pas de premier élément, d'index etc). Une boucle sur un hash ne respectera donc pas forcément l'ordre dans lequel on a défini ses éléments.
[skateinmars ] des questions ?
[skateinmars ] (:
[illovae ] au poil
[skateinmars ] ok on enchaîne
[skateinmars ] Les hashs sont assez souvent utilisés comme arguments d'une fonction, ce qui est très utile si l'on a de nombreux arguments optionnels.
[skateinmars ] def affiche_prix(centimes, options = {})
[skateinmars ] end
[skateinmars ] affiche_prix(450) #=> "$4.5"
[skateinmars ] (je précise que cette fonction est très mal écrite, il faudrait utiliser printf pour la virgule et les centimes, ne pas assumer la position de la devise à gauche, etc...)
[skateinmars ] c'est donc juste un exemple d'utilisation d'un hash dans les paramètres d'une fonction
[skateinmars ] des questions sur les hashs ?
[illovae ] no
[skateinmars ] passons aux symboles alors :)
[skateinmars ] Les symboles
[skateinmars ] ------------
[skateinmars ] On à déjà aperçu sans les expliquer des symboles dans le cours précédent. Il s'agit assez simplement de chaînes de caractères qui ont quelques particularités, la première étant qu'ils commencent par deux points ":"
[skateinmars ] mon_symbole = :symbole
[skateinmars ] Un symbole dans sa forme la plus connue peut comporter les mêmes caractères qu'une variable et en suit les mêmes règles (mis à part le fait qu'il puisse commencer par une majuscule).
[skateinmars ] On peut toutefois également écrire un symbole comme ceci :
[skateinmars ] mon_autre_symbole = :"42, salut le monde"
[skateinmars ] Contrairement aux strings un symbole n'est pas destiné à être modifié.
[skateinmars ] Comme vous pouvez l'imaginer la grande force du symbole est sa simplicité, c'est pourquoi on l'utilise souvent la ou on voudrait un "texte" assez statique. Le meilleur exemple est dans les hashes :
[skateinmars ] options = {:devise => "euro", :separateur => ","}
[skateinmars ] options[:devise] #=> "euro"
[skateinmars ] C'est tout de même plus beau qu'un tas de guillemets :-) !
[illovae ] clair
[skateinmars ] ok pour les symboles ?
[illovae ] une question
[skateinmars ] (ahhh ! :p)
[illovae ] à part le fait que le symbole n'a jamais a être modifié, je vois pas l'intérêt par rapport à un string
[illovae ] si tu définis un string devise => "euro"
[illovae ] a priori tu chagneras jamais ce string, non ?
[illovae ] à quoi ça sert d'en faire un symbole ?
[skateinmars ] avec un symbole on en est "plus sur"
[skateinmars ] et il y a aussi un autre interêt
[illovae ] ok ça sert à éviter les possible connerie du programmeur donc ?
[skateinmars ] au niveau mémoire, un symbole répété ne prendra qu'un seul emplacement mémoire
[illovae ] ah ok d'accord
[skateinmars ] si on fait sym1 = :symbole
[skateinmars ] et sym2 = :symbole
[skateinmars ] le :symbole est identique
[illovae ] oui oui je pige
[skateinmars ] alors qu'avec "chaine" et "chaine" on aurait 2 emplacements mémoire pris
[skateinmars ] on continue ? :)
[illovae ] (:
[skateinmars ] illovae: enfin surtout c'est plus joli un symbole en fait :)
[illovae ] huh moi je trouve que "ça prend moins de mémoire" est plus intéressant :P
[skateinmars ] héhé
[skateinmars ] bon, on enchaine avec les "blocs de code"
[skateinmars ] Bloc party
[skateinmars ] ----------
[skateinmars ] Alors la accrochez-vous, ca va envoyer du lourd. Les notions abordées sont, je pense, plutôt méconnues de programmeurs PHPs par exemple. C'est tout de même un des aspects de ruby qui rend le langage si dynamique et permet d'utiliser des techniques de programmations avancées (tels que les DSLs - Domain Specific Language - et la métaprogrammation).
[skateinmars ] Bref, essayez bien de comprendre ce qui arrive car vous vous en servirez tout le temps :-)
[skateinmars ] En ruby, on est souvent amené à utiliser des blocs de code lors de l'écriture de nos programmes. On peut même dire que je vous ai caché la vérité depuis le début.
[skateinmars ] En effet, si vous avez suivi mon cours comme de bons élèves sans vouloir trop en savoir à l'avance vous allez vous rendre compte que c'est une énorme partie du langage que j'ai mis de côté.
[skateinmars ] Mais enchaînons donc. Qu'est-ce qu'un bloc en ruby. Il s'agit tout simplement d'une série d'instructions (du code donc) qui est "encadré", et donc contenu dans ledit bloc.
[skateinmars ] Mais à quoi cela peut-il bien servir ?
[skateinmars ] Un exemple vous éclaira sûrement :
[skateinmars ] 10.times {
[skateinmars ] }
[skateinmars ] Et voila un peu de magie. Ce code ne peut être plus clair : on va faire 10 fois «Afficher "salut !"».
[skateinmars ] `times` est une méthode de la classe Integer qui demande un bloc et "l'exécute" le nombre de fois égal à la valeur de notre objet `10`.
[skateinmars ] Le bloc lui-même est ici contenu entre accolades `{}`.
[skateinmars ] okay ?
[illovae ] c'est un peu comme un def, sauf que ça s'exécute quoi ?
[skateinmars ] illovae: c'est un peu comme une méthode sans nom oui
[illovae ] arf
[skateinmars ] c'est pas clair ? ^^
[illovae ] si si, arf means okay here :p
[skateinmars ] d'acc :-)
[skateinmars ] Un autre exemple qui va vous montrer la "vraie" manière d'utiliser une boucle en ruby (sans utiliser `for`) :
[skateinmars ] ['un', 'deux', 'trois'].each do |i|
[skateinmars ] end
[skateinmars ] Each signifie "chaque" en anglais. Ce genre de boucle s'appele un itérateur, elle parcourt notre tableau et exécute notre bloc pour chaque élément accédé.
[illovae ] haha nice
[skateinmars ] Il y a deux syntaxes possible pour écrire un bloc : avec les accolades, ou avec `do` et `end`. Ces deux façons sont strictement équivalentes, mais les accolades sont préférés lorsque l'on veut écrire un bloc sur une seule ligne.
[skateinmars ] Un bloc peut prendre des arguments, en utilisant `|argument1, argument2|` et ainsi de suite (il n'y a actuellement pas d'arguments optionnels).
[skateinmars ] des questions sur les blocs ?
[Sp4rKy ] non
[illovae ] ouai tu veux dire quoi par pas d'arguments optionels ?
[illovae ] qu'il en faut un aboslument ?
[skateinmars ] illovae: dans les méthodes on peut faire def mamethode(argument = 'x')
[skateinmars ] et ensuite appeler mamethode('y') ou mamethode()
[illovae ] ah d'accord
[skateinmars ] ici on peut pas, ce qui est assez logique vu que l'on doit connaitre a l'avance le nombre de parametres necessaires
[skateinmars ] ok ? :)
[illovae ] ouai
[skateinmars ] donc
[skateinmars ] Il y a d'autres manières d'utiliser des blocs que dans des méthodes : les lambdas et les Procs.
[skateinmars ] ###Procs
[skateinmars ] Comme on peut se dire en voyant le nom, Proc est bien une classe qui permet de créer des procs (soit des blocs).
[skateinmars ] On peut donc créer un objet comme ceci :
[skateinmars ] trois_fois = Proc.new {|i| i * 3 }
[skateinmars ] trois_fois.call(2) #=> 6
[skateinmars ] On "exécute" donc un Proc en appelant sa méthode `call`.
[skateinmars ] questions ?
[lone-house ] nope
[skateinmars ] Le fait qu'un proc soit un objet permet d'imaginer toute sortes de choses plus ou moins tordues :
[skateinmars ] (attention ca fait mal la)
[skateinmars ] def lance_des(faces)
[skateinmars ] return Proc.new { |n|
[skateinmars ] end
[skateinmars ] d6 = lance_des(6)
[skateinmars ] d6.call(2) # je lance 2D6 !
[skateinmars ] Un peu de détails sur cette incantation vaudou :
[skateinmars ] Notre méthode lance_des retourne un Proc. Ce proc prend un argument `n`.
[skateinmars ] `0.upto(n)` créée un "Range" qui va de 0 à n. On avait vu les ranges lors du premier cours sur les boucles, il s'agit d'un intervalle de nombres sur lequel on peut itérer.
[skateinmars ] La méthode `inject` est appelée sur notre range. Cette méthode prend en argument une valeur initiale (ici 0), et un bloc. Elle va ensuite itérer sur ce bloc sur chaque valeur de notre range (notez qu'on peut également utiliser inject avec un tableau, ou même un hash) en lui donnant à chaque fois la valeur de l'élément actuel de notre objet énuméré, et la valeur "collectée" courante. Cette valeur est récupérÃ
[skateinmars ] En pratique on va donc créer un objet, ici `d6` en appelant notre fonction en lui donnant le nombre de `faces` (ici, on veut donc un dé standard à 6 faces).
[skateinmars ] Notre objet étant un Proc on peut l'appeler avec call en lui précisant le nombre `n` de lançers voulus.
[illovae ] putain ouai c'est tordu
[skateinmars ] Vous pouvez donc voir que l'on a créé une fonction sur mesure ! Pas mal ruby non ? :-)
[skateinmars ] alors la j'attends des questions si vous en avez :p
[illovae ] le i et le val tu le sors d'où ?
[skateinmars ] illovae: c'est la méthode inject qui s'occupe de ca
[niko ] l'interet du proc c'est de faire des functions en partie préremplie ?
[illovae ] ouai mais je pige pas comment il s'occupe du i et du val
[skateinmars ] en fait ya 0.upto(n) qui créé un range
[skateinmars ] par exemple 0..2
[illovae ] ok pour le range
[skateinmars ] niko: oui (me rappele plus du nom de ce concept ?)
[skateinmars ] illovae: après ya inject
[skateinmars ] on lui donne une valeur 0 de départ
[skateinmars ] et un bloc
[niko ] des methodes contextuel un peu
[illovae ] oui ça c'est ok
[skateinmars ] et inject passe a chaque fois a ce bloc i, qui est la valeur actuelle dans le range
[skateinmars ] donc i sera 0, puis 1 puis 2 (mais on s'en sert pas)
[illovae ] ok donc i prend la valeur que l'on a à un pasasge
[skateinmars ] puis il passe val
[illovae ] et val c'est quoi alors ?
[skateinmars ] val au debut est egal a la valeur donnée a inject
[skateinmars ] donc 0
[skateinmars ] puis il est égal a la valeur renvoyée par le bloc
[skateinmars ] donc au premier passage ca sera 0 + rand(6) par exemple
[skateinmars ] si rand(6) fait 5, val sera egal a 5
[illovae ] et ?
[skateinmars ] au deuxième passage on fera 5 + rand(6) et ainsi de suite
[illovae ] je relis :>
[skateinmars ] niko: c'est le currying
[niko ] skateinmars: donc le call fait un sum de plusieurs appels ?
[skateinmars ] non la c'est le inject qui gère ca
[illovae ] skateinmars: ouai mais si tu fais 5 + rand(6) et si rand(6) est égal à disons 6, on alors 5 + 6 = 11 ; ça va pas pour un dés à 6 faces ?
[skateinmars ] illovae: si si, parce que la tu le lance 2 fois
[skateinmars ] (ton n est egal a 2)
[illovae ] ah ok c'est un double lancé, j'ai pas vu
[niko ] tordu
[illovae ] ah oui call 2
[illovae ] ok la vache, c'est plus que tordu même
[skateinmars ] en fait [1, 2, 3].inject(0) {|i, val| val + 1}
[skateinmars ] c'est égal à 6
[niko ] en fait y a qu'un call(2) qui est valable :)
[illovae ] ouai ^^
[skateinmars ] niko: ben tu peut lancer 1d6 par exemple :)
[skateinmars ] ou 3d6, etc etc
[niko ] pas avec ta methode on dirait
[niko ] vu que tu peux tomber sur un 12
[niko ] enfin 11
[skateinmars ] d6.call(3)
[skateinmars ] ca peut faire 6 + 6 +6 maxi
[illovae ] oui parce qu'il y a qu'un seul passage
[skateinmars ] (vu que ca fait 0 + rand(6) + rand(6) + rand(6) )
[illovae ] comme on part de 0 on ajoute le rand(6) et ça fait au max 6
[skateinmars ] enfin la c'est 6 mais on peut faire
[skateinmars ] d12 = lance_des(12)
[illovae ] si y'a un second passage, il reprend la valeur précedente qu'il avait et re-rajoute un rand(6) c'est ça ?
[skateinmars ] illovae: oui
[illovae ] la vache, faut l'écrire quoi quand même :]
[skateinmars ] regarde mon exemple de inject tout seul en fait
[illovae ] le mec qui a sorti ça, il s'est creusé la tee
[illovae ] tête*
[skateinmars ] [1, 2, 3].inject(0) {|i, val| val + 1} #=> 6
[skateinmars ] illovae: bah euh c'est moi qui l'ait fait ^^'
[illovae ] et bah
[skateinmars ] on enchaine ? :)
[illovae ] yup
[skateinmars ] ###lambdas
[skateinmars ] Les lambdas sont une méthode alternative de création d'un Proc :
[skateinmars ] afficheur = lambda {|x| puts x}
[skateinmars ] afficheur.call("salut")
[skateinmars ] (Un lambda est bien un Proc mais il présente quelques différences concernant l'utilisation de return à l'intérieur du bloc ainsi que des arguments du bloc.)
[skateinmars ] (Pour en apprendre plus je vous redirige sur http://eli.thegreenplace.net/2006/04/18/understanding-ruby-blocks-procs-and-methods/ (en anglais) qui explique bien la différence.)
[skateinmars ] pas trop de questions je pense :)
[illovae ] o
[illovae ] no*
[skateinmars ] au final on se sert assez peu des lambdas et procs, par rapport aux itérateurs comme each
[skateinmars ] continuons donc
[skateinmars ] ###Blocs et méthodes
[skateinmars ] Nous avons vu que l'on peut utiliser des blocs dans une méthode, et qu'il s'agit même d'une façon de faire extrèmement courante.
[skateinmars ] Nous savons donc que certaines méthodes prennent en argument des blocs, mais comment écrire la notre ?
[skateinmars ] Rien de plus simple ! En fait on ne précise pas explicitement que notre méthode demande un bloc en argument. On peut donc faire :
[skateinmars ] def vide
[skateinmars ] end
[skateinmars ] vide { puts "yay" }
[skateinmars ] Et rien ne se produira, mais il n'y aura aucune erreur.
[skateinmars ] Pour exécuter un bloc dans notre méthode on devra utiliser le mot-clé `yield` :
[skateinmars ] def repeteur(n)
[skateinmars ] n.times do
[skateinmars ] end
[skateinmars ] repeteur(2) do
[skateinmars ] end
[skateinmars ] On peut donner des arguments à yield comme à une méthode normale, et ceux-ci seront passés au bloc. Pour utiliser plusieurs blocs différents, on devra passer par des arguments traditionnels (qui seront des procs/lambdas).
[skateinmars ] Pour récupérer un résultat renvoyé par yield on utilisera simplement `variable = yield`.
[skateinmars ] (questions ?)
[illovae ] nop
[skateinmars ] En plus de yield, il est utile de noter l'existence de la méthode block_given? qui renvoie false ou true selon la présence ou non d'un bloc.
[skateinmars ] def repeteur(n)
[skateinmars ] else
[skateinmars ] puts "Je veux un bloc !"
[skateinmars ] end
[skateinmars ] end
[skateinmars ] (utile pour renvoyer une erreur par exemple)
[skateinmars ] Notez que l'on peut tout de même donner un nom à notre bloc en le précisant comme dernier argument de la méthode, précédé d'un `&` :
[skateinmars ] def appeleur(argument, &mon_bloc)
[skateinmars ] end
[illovae ] arf
[skateinmars ] Cela marche aussi en appelant une méthode (utile si on veut réutiliser un proc)
[skateinmars ] salueur = Proc.new { puts "Salut" }
[skateinmars ] repeteur(3, &salueur)
[skateinmars ] (au passage voyez que c'est repeteur que j'utilise et pas appeleur)
[skateinmars ] Cette utilisation de "&" arrive assez peu couramment en pratique.
[skateinmars ] des questions ?
[illovae ] easy, suffit de mettre &salueur pour qu'elle s'exec, pratique
[skateinmars ] :)
[skateinmars ] continuons
[skateinmars ] ###Tu débloques ?
[skateinmars ] Vous voila donc maintenant armés de la connaissance des blocs en ruby, en en apprenant au passage sur les boucles et les itérateurs.
[skateinmars ] Ces concepts sont très importants en programmation et encore plus en ruby ou l'on en use et abuse comme vous vous en apercevrez certainement !
[skateinmars ] changeons a présent de sujet
[skateinmars ] Exécuter des commandes système
[skateinmars ] ------------------------------
[skateinmars ] Avant de passer à la suite de la POO, un peu de fun avec les commandes systèmes.
[skateinmars ] Par commande système, j'entends simplement tout programme exécutable extérieur à ruby.
[skateinmars ] Il est donc possible depuis votre code de lancer une commande et récupérer son résultat en sortie.
[skateinmars ] La méthode la plus simple, proche du shell, est d'utiliser `` (les "backticks") :
[skateinmars ] `echo 'hello'`
[skateinmars ] (au fait pour les gens qui n'ont pas suivi les cours précedents vous pouvez utilisez la console ruby irb pour exécuter les exemples)
[skateinmars ] Le résultat renvoyé sera retourné sous forme de string. Les curieux noteront que l'on peut utiliser les redirections telles que '>' ('2>&1' par exemple).
[illovae ] y'a aussi le fameux $() bashien ?
[skateinmars ] illovae: non
[illovae ] ukay
[skateinmars ] par contre
[skateinmars ] On peut également utiliser la méthode system :
[skateinmars ] system("ls", "-l", "-h")
[skateinmars ] system("ls -l -h")
[skateinmars ] Les deux commandes étant équivalentes ici.
[illovae ] ok question :p
[skateinmars ] oui ?
[illovae ] admettons URL = "http://www.google.fr" ; comment tu écrirais wget ?
[illovae ] un wget*
[skateinmars ] ah oui
[illovae ] (avec comme argument URL
[skateinmars ] tu peut faire `wget #{URL}`
[skateinmars ] en utilisant #{} donc, comme dans un string
[illovae ] d'accord, même si j'ai des ? dans mon URL çapasse sans souci avec #{} ?
[skateinmars ] avec system aussi vu qu'on lui donne carrément un string
[skateinmars ] illovae: la j'avoue que je n'ai pas testé
[illovae ] ok je verrais
[skateinmars ] (ca semble passer)
[illovae ] autre question de noob
[illovae ] si on fait des petits scripts qui demande de faire du parsage etc, on fait des appels système sur sed/grep etc, ou y'a des choses toutes prêtes dans ruby ?
*illovae qui se foule pas et profite du cours pour avoir ses réponses :]
[skateinmars ] non on peut utiliser les expressions regulieres et tout un tas de methodes pour traiter les chaines de caractères en ruby
[illovae ] ouai c'est ce quej e pensais, merci
[skateinmars ] d'ailleurs on peut ne pas utiliser wget mais open-uri par exemple :)
[illovae ] ah cay mieux
[illovae ] c'est vrai j'ai déjà vu dans dans du python en plus...
[skateinmars ] héhé
[skateinmars ] bon je continue :p
[skateinmars ] donc, sur la différence entre `` et system
[skateinmars ] La différence avec les backticks est que `system` affiche directement la sortie de la commande. La méthode renvoie ensuite true ou false selon que l'exécution de la commande soit réussie ou non. La méthode renvoie ensuite un booléen selon l'état de réussite de la commande.
[skateinmars ] a = `echo a` ne renverra rien donc
[illovae ] mais puts.a oui ?
[skateinmars ] mais la variable a contiendra "a\n" (le retour a la ligne de echo)
[illovae ] (en plus je veux dire)
[skateinmars ] illovae: puts a
[illovae ] okay
[skateinmars ] ou puts(a)
[skateinmars ] et avec system
[skateinmars ] a = system("echo a")
[skateinmars ] on verra le resultat de la commande
[skateinmars ] et a contiendra true
[skateinmars ] pour finir
[skateinmars ] Les deux méthodes présentées ci-dessus étant assez limitées, sachez que vous pouvez également utiliser `IO.popen`, mais je n'en parlerai pas ici. Pour en savoir plus reportez-vous à la doc officielle !
[skateinmars ] on passe a la suite ?
[illovae ] yep
[skateinmars ] Plus d'objet
[skateinmars ] ------------
[skateinmars ] Revenons à présent à la Programmation Orientée Objet, en présentant quelques concepts supplémentaires très utiles.
[skateinmars ] ###Visibilité
[skateinmars ] La visibilité est un attribut qui concerne les méthodes d'une classe. Elle peut avoir 3 "états" qui détermineront la possibilité d'y accéder et depuis quel endroit dans le code.
[skateinmars ] Ces trois états sont public, protégé (protected) et privé (private).
[skateinmars ] Un exemple sera bien plus parlant :
[skateinmars ] class Oiseau
[skateinmars ] def vole
[skateinmars ] fatiguer 10
[skateinmars ] end
[skateinmars ] def marche
[skateinmars ] fatiguer 5
[skateinmars ] end
[skateinmars ] protected
[skateinmars ] def fatiguer(val)
[skateinmars ] @niveau_fatigue -= val
[skateinmars ] rale if @niveau_fatigue <= 0
[skateinmars ] end
[skateinmars ] private
[skateinmars ] def rale
[skateinmars ] puts "Je suis fatigué !"
[skateinmars ] end
[skateinmars ] end
[skateinmars ] (un lien gist arrive)
[skateinmars ] http://gist.github.com/128169
[skateinmars ] Cet exemple est assez nul, avouons-le, mais il est assez difficile d'expliquer le principe de visibilité sans être trop compliqué, il faudra donc faire avec :-)
[skateinmars ] Nous pouvons utiliser notre classe Oiseau comme ceci :
[skateinmars ] oiseau = Oiseau.new
[skateinmars ] 19.times {
[skateinmars ] oiseau.marche
[skateinmars ] }
[skateinmars ] oiseau.vole
[skateinmars ] (ok ?)
[illovae ] ouai
[skateinmars ] Cette dernière instruction entrainera l'affichage du message "Je suis fatigué !" (la variable niveau_fatigue étant de valeur -5).
[skateinmars ] Toutefois la chose à remarquer ici est l'utilisation des méthodes `protected` et `private`. Ils servent à marquer les méthodes dont la définition suit leur utilisation.
[skateinmars ] Dans ce cas la, on peut donc voir que `fatiguer` est marqué comme "protected", et `rale` est "private".
[skateinmars ] La visibilité est par défaut "public" si aucun mot-clé n'est présent (on peut tout de même spécifier "public" si on a auparavant utilisé private ou protected).
[Pythack ] Ca a l'air simple le ruby.
[skateinmars ] :-)
[Pythack ] Et utile.
[skateinmars ] Tentons d'utiliser ces méthodes protégées :
[skateinmars ] oiseau.rale
[skateinmars ] Ruby se plaint : «NoMethodError: private method `rale' called for #» (il lance une exception).
[skateinmars ] oiseau.fatiguer(5)
[skateinmars ] Le résultat est similaire.
[skateinmars ] Voila donc l'explication de cette histoire de visibilité : les méthodes protected et private ne peuvent pas être appelées en dehors de notre objet (elles fonctionnent bien dans nos méthodes `marche` et `vole`).
[skateinmars ] Vous vous demandez sûrement l'utilité de cette restriction. Contrairement à Java on n'applique pas la notion de visibilité aux variables d'instance (on utilise attr_accessor), et l'héritage (que l'on verra juste après) n'a pas de rapport avec la visibilité.
[skateinmars ] Mais ce concept reste utile lors de la programmation de bibliothèques qui seront utilisées par d'autres développeurs.
[skateinmars ] En effet le fait de marquer une fonction comme privée est un avertissement aux utilisateurs de notre classe : «N'utilisez pas cette fonction car je souhaite pouvoir modifier son comportement comme bon me semble».
[skateinmars ] Dans notre exemple on pourrait par exemple rajouter l'utilisation d'une méthode `dormir` si le niveau de fatigue est trop élevé. Mais les autres développeurs n'ont pas à savoir cela, comme il n'ont par exemple ici pas besoin d'utiliser la variable niveau_fatigue.
[skateinmars ] (petite pause questions)
[illovae ] (aucune ici)
[skateinmars ] ok :)
[skateinmars ] Voyons maintenant la différence entre protected et private. Pour cela déclarons une nouvelle méthode à notre classe :
[skateinmars ] class Oiseau
[skateinmars ] end
[skateinmars ] Et utilisons-la après réinitialisation de notre oiseau :
[skateinmars ] oiseau = Oiseau.new
[skateinmars ] oiseau2 = Oiseau.new
[skateinmars ] oiseau.suivre(oiseau2)
[skateinmars ] "protected" est donc une petite subtilité par rapport à "private" : une méthode peut être appelée depuis l'extérieur de notre objet (`oiseau.fatiguer(5)`) mais uniquement si l'objet qui l'appele est de la même classe (ici ce sont 2 objets Oiseau).
[skateinmars ] (donc ici la fatigue est bien modifiée sur les 2 oiseaux)
[skateinmars ] ok ?
[illovae ] yep
[skateinmars ] Vous pouvez essayer le résultat avec private en modifiant dynamiquement la visibilité de la méthode `suivre` :
[skateinmars ] class Oiseau
[skateinmars ] end
[skateinmars ] En effet private, public et protected sont des méthodes qui peuvent prendre un nom de méthode en argument.
[skateinmars ] Une fois cette modification faite la méthode suivre ne fonctionnera plus correctement.
[skateinmars ] (remarquez l'utilisation d'un symbole comme argument à private :) on aurait pu utiliser une chaine de caractères)
[skateinmars ] Enfin, sachez que si vous avez besoin d'utiliser une méthode privée ou protégée (bien que cela soit déconseillé !), vous pouvez utiliser la méthode `send` :
[skateinmars ] oiseau.send :fatiguer, 10
[skateinmars ] Qui ne tient pas compte de la visibilité de la méthode (elle agit dans le "scope" de l'objet).
[skateinmars ] des questions sur la visibilité ?
[illovae ] juste le send outrepasse la visibilité en fait simplement ?
[skateinmars ] oui
[skateinmars ] continuons :)
[skateinmars ] ###Héritage
[skateinmars ] L'héritage est un concept très utilisé en POO.
[skateinmars ] Cela consiste à créer des classes dites "parentes", dont les attributes seront ensuite repris par des classes "filles" (ou sous-classes).
[skateinmars ] La encore un exemple est plus utile que des mots :
[skateinmars ] class Animal
[skateinmars ] class Reptile < Animal
[skateinmars ] REPRODUCTION = "ovipare"
[skateinmars ] def avance
[skateinmars ] puts "Ca rampe !"
[skateinmars ] end
[skateinmars ] end
[skateinmars ] class Mammifere
[skateinmars ] REPRODUCTION = "vivipare"
[skateinmars ] end
[skateinmars ] class Ornithorynque < Mammifere
[skateinmars ] REPRODUCTION = "ovipare"
[skateinmars ] end
[skateinmars ] class HomoSapiens < Mammifere
[skateinmars ] def avance
[skateinmars ] puts "Ca marche !"
[skateinmars ] end
[skateinmars ] end
[skateinmars ] homme = HomoSapiens.new
[skateinmars ] homme.avance #=> "Ca marche !"
[skateinmars ] HomoSapiens::REPRODUCTION #=> "vivipare"
[skateinmars ] ou plutot http://gist.github.com/128175
[skateinmars ] Peu d'explications sont finalement nécessaires : on déclare une classe fille en utilisant < Parent dans la définition de la classe. Il est possible "d'imbriquer" les classes indéfiniment.
[illovae ] héhé ça me rappelle quelque chose ^^
[skateinmars ] lors de la redéfinition d'une méthode, on peut également utiliser `super`, qui appele la méthode parente. Elle peut être pratique si la méthode à surcharger comprend des arguments :
[skateinmars ] illovae: ouais hein :)
[skateinmars ] class Habitation
[skateinmars ] def initialize(jardin)
[skateinmars ] super(0, jardin)
[skateinmars ] end
[skateinmars ] end
[skateinmars ] (un exemple avec super donc)
[skateinmars ] questions ?
[illovae ] aucune ici
[skateinmars ] Sachez que la plupart des classes que vous définirez ont déjà des parents. Vous pouvez retrouver les parents avec la méthode de classe `ancestors` :
[skateinmars ] HomoSapiens.ancestors #=> [HomoSapiens, Mammifere, Animal, Object, Kernel]
[skateinmars ] Object est l'objet le plus "basique" qui soit, et Kernel est un module inclus dans Object.
[skateinmars ] (Les curieux seront ravis d'apprendre que cette organisation avec Kernel et object est actuellement revue dans les versions de développement de Ruby.)
[illovae ] ah pas mal, en plus tu met de l'humour dans le code :D
[skateinmars ] ^^
[skateinmars ] ok pour l'héritage ?
[illovae ] c'est ok pour moi
[skateinmars ] continuons
[skateinmars ] ###Modules
[skateinmars ] Les modules en Ruby ont typiquement deux types d'utilisations.
[skateinmars ] ####Mixin
[skateinmars ] La première façon d'utiliser un module est assez similaires au concept d'héritage. Ruby contrairement au C++ par exemple ne peut créer de classe héritant de plusieurs classes à la fois.
[skateinmars ] Les modules permettent plus ou moins cela : ils peuvent être inclus dans une classe et donnent ainsi accès à leurs méthodes. Cette faculté de "récupération" de méthodes et propriétés est parfois appelée "mixin".
[skateinmars ] module HasDoors
[skateinmars ] class Voiture
[skateinmars ] include HasDoors
[skateinmars ] end
[skateinmars ] class Maison
[skateinmars ] include HasDoors
[skateinmars ] end
[skateinmars ] Maison.new.portes? #=> true
[skateinmars ] Un exemple plus pertinent sont les classes Array et Hash, qui toutes deux incluent le module Enumerable. Enumerable se sert de la méthode `each` pour créer d'autres méthodes telles que find, select, any etc...
[skateinmars ] Plus d'infos ici : http://www.ruby-doc.org/core/classes/Enumerable.html (dans l'intro en haut de page)
[illovae ] ça devient de la gymnastique lÃ
[skateinmars ] ca me semble encore assez clair ?
[illovae ] ouai ça va, par contre je comprend pas à quoi ça sert
[illovae ] à part pour créer des librairies quoi
[skateinmars ] illovae: c'est pour éviter de copier/coller du code dans des classes
[skateinmars ] la on a une seule méthode portes? par exemple
[skateinmars ] pas besoin de la définir 2 fois
[illovae ] ah yes ouai
[illovae ] j'avais loupé ça
[illovae ] ah bah ouai ok ok
[illovae ] my mistake
[skateinmars ] héhé
[skateinmars ] donc :)
[skateinmars ] Sachez aussi qu'il existe des possibilités plus avancées de contrôle de l'inclusion d'un module dans une classe (ou même un objet avec extended), avec par exemple la méthode included?.
[skateinmars ] Ttoutefois, ces utilisations étant assez avancées, je n'en parlerai pas ici.
[skateinmars ] *Toutefois
[skateinmars ] passons aux namespaces :)
[skateinmars ] ####Namespaces
[skateinmars ] Le deuxième type d'utilisation des modules permet de mieux organiser son code. En effet les modules permettent la création de "namespaces" (ou "espaces de noms").
[skateinmars ] Un problème courant en PHP, un langage ne comportant pas de namespaces (la prochaine version en proposera bien un support mais ceci est une autre histoire) est la "collision" de classes et méthodes.
[skateinmars ] Imaginons que vous ecriviez un site de vente en ligne, qui comprend une classe Categorie (pour organiser vos produits). Mais vous souhaitez ajouter un module de blog, qui comprend lui aussi des catégories.
[skateinmars ] Une solution serait de créer une classe ProduitCategorie pour le magasin en ligne, et une classe BlogCategorie. Cela est toutefois assez peu joli. Les modules vont donc vous permettre d'améliorer cela :
[skateinmars ] module Blog
[skateinmars ] class Billet
[skateinmars ] end
[skateinmars ] end
[skateinmars ] module Magasin
[skateinmars ] class Categorie
[skateinmars ] end
[skateinmars ] class Produit
[skateinmars ] end
[skateinmars ] end
[skateinmars ] Vous pouvez maintenant utiliser vos classes comme ceci :
[skateinmars ] blog_cat_1 = Blog::Categorie.new('Web')
[skateinmars ] charbon = Magasin::Produit.new
[skateinmars ] Un module peut bien sur contenir d'autres modules, permettant une organisation encore plus précise.
[skateinmars ] Notez qu'ici les namespaces sont Blog et Magasin
[skateinmars ] des questions sur les namespaces ?
[illovae ] non
[skateinmars ] et bien c'est la fin :)
[illovae ] lol
[illovae ] c'est chaud à maîtriser quand mêem ces histoires de module
[skateinmars ] j'ai pas écrit de conclusion à l'avance, donc ben bah voila :)
[skateinmars ] illovae: oui au début c'est un peu tordu
[illovae ] bah surtout que je m'imagine écrire du code
[skateinmars ] mais après quand on s'en sert pas mal on saisit mieux la chose
[illovae ] j'écris mon code pour la boutique en ligne comme tu dis
[illovae ] sans utiliser de module
[illovae ] si je veux rajouter, les catégories pour le blog, j'aurai tendance à réécrire un truc
[illovae ] anéfé c'est pratique avec les modules, mais ça chamboule tout quoi
[skateinmars ] illovae: honnetement avec rails on se sert pas trop trop des modules
[skateinmars ] on ferait plutot BlogCategorie et ProduitCategorie
[skateinmars ] au final les modules c'est plutot pour ecrire des librairiies
[skateinmars ] -i
[skateinmars ] pour que les gens qui utilisent notre lib n'aient pas de soucis de conflit avec d'autres librairires
[illovae ] ça fait un code bien propre, masi j'imagine qu'à la lecture du code ça aide pas :P (pour un noob j'entend)
[skateinmars ] illovae: ah ben après on peut faire
[skateinmars ] module Blog
[skateinmars ] end
[skateinmars ] end
[skateinmars ] dans un fichier
[illovae ] ouai directement
[skateinmars ] et dans l'autre pareil avec la classe Billet
[illovae ] ça sent le truc bien poussé poru les librairies en effet
[skateinmars ] yep
[illovae ] ça va mériter quelques relecture quand même :>
[illovae ] merci skateinmars \o/
[skateinmars ] :)
[skateinmars ] merci les gens ^^
[skateinmars ] je ferais un transcript propre avec la synthèse des cours
[illovae ] alors rubyonrails prochainement :P ?
[illovae ] skateinmars: ah ouai kewl, merci
[skateinmars ] ror ca serait la suite logique oui :)
[illovae ] en fait tu fais tout ça pour montrer à gpocentek à quel point c'est bien pour qu'il le mette sur le serveur hein ;) ?
*illovae hides
[skateinmars ] ahaha
[skateinmars ] démasqué :))
[skateinmars ] bon hop on coupe les logs :)