Menu
CoddyTech

Collections personnalisées

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

Une classe de collection combine plusieurs méthodes spéciales : each avec Enumerable, << pour ajouter, size, et to_s et inspect pour afficher. each devrait également fonctionner sans bloc, en renvoyant un énumérateur avec to_enum, comme le font les tableaux :

class TodoList
  include Enumerable

  def initialize
    @items = []
  end

  def <<(item)
    @items << item
    self
  end

  def each
    return to_enum(:each) unless block_given?

    @items.each { |item| yield item }
    self
  end
end

list = TodoList.new << "wash" << "shop" << "cook"
list.each.with_index(1) { |item, n| puts "#{n}. #{item}" }
p list.select { |i| i.include?("o") }

Sortie :

1. wash
2. shop
3. cook
["shop", "cook"]

block_given? indique si l’appelant a transmis un bloc. L’énumérateur renvoyé sans bloc permet d’enchaîner des méthodes comme each.with_index, each_slice ou next :

class Countdown
  include Enumerable

  def initialize(from)
    @from = from
  end

  def each
    return to_enum(:each) unless block_given?

    @from.downto(1) { |n| yield n }
  end
end

e = Countdown.new(3).each
puts e.next
puts e.next
p Countdown.new(5).each_slice(2).to_a

Résultat :

3
2
[[5, 4], [3, 2], [1]]

to_s est le texte convivial destiné aux utilisateurs et inspect un bref résumé destiné aux programmeurs. Pour une collection, inspect affiche généralement la classe et la taille plutôt que chaque élément :

class TodoList
  include Enumerable

  def initialize(*items)
    @items = items
  end

  def each(&block)
    @items.each(&block)
  end

  def size
    @items.size
  end

  def to_s
    map.with_index(1) { |item, n| "#{n}. #{item}" }.join("\n")
  end

  def inspect
    "#<TodoList #{size} items>"
  end
end

list = TodoList.new("wash", "shop")
puts list
p list

Résultat :

1. wash
2. shop
#<TodoList 2 éléments>

Enumerable fournit count, mais pas size, empty?, << ni [] : ceux-ci appartiennent à la classe, car elle seule sait comment les éléments sont stockés. Les définir donne à la collection l’apparence d’un tableau pour ceux qui l’utilisent :

def size
  @items.size
end

def empty?
  @items.empty?
end

def [](index)
  @items[index]
end
challenge icon

Défi

Facile

Complète la classe TodoList. << ajoute un texte de tâche et renvoie la liste. each transmet les tâches et renvoie to_enum(:each) en l’absence de bloc. Inclue Enumerable. size renvoie le nombre de tâches. to_s renvoie les tâches sous forme de lignes numérotées, 1. wash, ou nothing to do, et inspect renvoie #<TodoList 3 items>.

Le code fourni ajoute chaque ligne de saisie en chaînant <<, puis affiche la liste, p de la liste, les tâches numérotées avec ! au moyen de each.with_index(1) sous la forme 1! wash, le nombre de tâches contenant o, ainsi que la première tâche par ordre alphabétique.

Ton code va dans todo_list.rb. main.rb contient le code d’entrée/sortie fourni et ne peut pas être modifié.

Essayez vous-même

require_relative 'todo_list'

# Code d'entrée/sortie fourni : conservez-le tel quel
input = []
while (line = gets)
  input << line.chomp
end
list = input.reduce(TodoList.new) { |l, task| l << task }
puts list
p list
list.each.with_index(1) { |task, n| puts "#{n}! #{task}" }
puts "with o: #{list.count { |t| t.include?("o") }}"
puts "first: #{list.min}"
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