Menu
Coddy logo textTech

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 lui 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 duck typing : 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 également. Une méthode qui utilise uniquement << fonctionne avec un tableau, une chaîne ou n’importe quel objet à vous 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

Sortie :

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

respond_to?(:name) vérifie si un objet possède une méthode publique, sans l’appeler. Utilisez-le lorsqu’un objet peut prendre en charge, ou non, 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 lève NoMethodError, dont le message indique la méthode et 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

Sortie :

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

Défi

Facile

Complétez les classes Printer et LineCounter ainsi que la fonction auxiliaire export(items, target) dans functions.rb. export envoie chaque élément vers 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 doit être placé 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 : le garder 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