Menu
CoddyTech

Typage canard

Fait partie de la section Programmation orientée objet du Journey Ruby de Coddy. Leçon 33 sur 57.

Ruby ne vérifie pas la classe d’un objet avant d’appeler une méthode ; il suffit que l’objet possède cette méthode. « S’il marche comme un canard et cancane comme un canard, c’est un canard. » C’est le typage canard : des classes qui ne partagent aucune superclasse peuvent tout de même être utilisées au même endroit :

class Duck
  def speak
    "Quack"
  end
end

class Robot
  def speak
    "Beep"
  end
end

class Radio
  def speak
    "...news..."
  end
end

[Duck.new, Robot.new, Radio.new].each { |thing| puts thing.speak }

Sortie :

Quack
Beep
...news...

Les classes intégrées participent aussi. Une méthode qui utilise uniquement << fonctionne avec un tableau, une chaîne ou n’importe quel objet à toi qui définit << :

class Tally
  attr_reader :count

  def initialize
    @count = 0
  end

  def <<(_item)
    @count += 1
    self
  end
end

def export(items, target)
  items.each { |item| target << item.to_s }
  target
end

p export([1, 2], [])
p export([1, 2], +"")
puts export([1, 2, 3], Tally.new).count

Résultat :

["1", "2"]
"12"
3

respond_to?(:name) demande si un objet possède une méthode publique, sans l’appeler. Utilisez-le lorsqu’un objet peut ou non prendre en charge une fonctionnalité facultative :

class Printer
  def print_page(text)
    "printing #{text}"
  end
end

class Scanner
end

[Printer.new, Scanner.new].each do |device|
  if device.respond_to?(:print_page)
    puts device.print_page("report")
  else
    puts "#{device.class} cannot print"
  end
end

Sortie :

printing report
Scanner cannot print

Lorsque l’objet ne possède pas la méthode, l’appel déclenche une NoMethodError, dont le message indique le nom de la méthode et de l’objet. Le typage canard repose sur le fait que chaque objet transmis réponde aux méthodes qui lui sont envoyées :

def loudest(things)
  things.map(&:speak).max_by(&:size)
end

class Cat
  def speak
    "Meow"
  end
end

puts loudest([Cat.new, Cat.new])
begin
  loudest([Cat.new, 42])
rescue NoMethodError => e
  puts e.message
end

Résultat :

Meow
undefined method `speak' for an instance of Integer
challenge icon

Défi

Facile

Complétez les classes Printer et LineCounter, ainsi que l’assistant export(items, target) dans functions.rb. export envoie chaque élément à la cible avec target << item.to_s et renvoie la cible. Printer#<< affiche le texte avec un numéro de ligne, 1: text, et renvoie l’imprimante. LineCounter#<< compte les lignes et les caractères et renvoie le compteur ; son to_s renvoie 3 lines, 12 chars.

Le code fourni lit les éléments, les exporte vers un tableau (affiché avec p), vers une nouvelle chaîne (affichée avec p), vers un Printer et vers un LineCounter (affiché avec puts).

Votre code va dans printer.rb, line_counter.rb et functions.rb. main.rb contient le code d’entrée/sortie fourni et ne peut pas être modifié.

Essayez vous-même

require_relative 'printer'
require_relative 'line_counter'
require_relative 'functions'

# Code d’entrée/sortie fourni : conservez-le tel quel
input = []
while (line = gets)
  input << line.chomp
end
p export(input, [])
p export(input, +"")
export(input, Printer.new)
puts export(input, LineCounter.new)
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation orientée objet

Entraînez-vous par vous-même : Compilateur Ruby en ligne