40 votes

Comment ajouter la méthode «each» à l'objet Ruby (ou dois-je étendre Array)?

J'ai un objet de Résultats qui contient un tableau de result objets avec quelques mises en cache des statistiques sur les objets dans le tableau. Je voudrais les Résultats d'objet pour être en mesure de se comporter comme un tableau. Ma première coupe à cet était d'ajouter des méthodes comme ceci

 def <<(val)
    @result_array << val
 end

C'est très similaire au c et je sais que Ruby a une meilleure façon.

J'aimerais aussi être capable de faire cela

 Results.each do |result|   
    result.do_stuff   
 end

mais je ne suis pas sûr de ce que l' each méthode est vraiment sous le capot.

Actuellement j'ai simplement retourner le sous-jacent tableau via une méthode et d'appeler sur elle, qui ne semble pas être la plus élégante solution.

Toute aide serait appréciée.

63voto

Chuck Points 138930

Pour le cas général de la mise en œuvre de la matrice de méthodes, oui, vous avez à mettre en œuvre vous-même. Vava réponse montre un exemple de cela. Dans le cas que vous avez donné, si, ce que vous voulez vraiment, c'est de déléguer la tâche de manutention each (et peut-être quelques autres méthodes) pour le contenu de l'array, et qui peuvent être automatisées.

require 'forwardable'

class Results
  include Enumerable
  extend Forwardable
  def_delegators :@result_array, :each, :<<
end

Cette classe sera tous de la Matrice de Énumérable comportement ainsi que la Matrice << de l'opérateur et il va tous aller dans l'intérieur du tableau.


Notez que lorsque vous passez votre code de la Matrice de l'héritage à cette astuce, votre << méthodes pour reprendre pas l'objet intself, comme le vrai Tableau est << n' -- cela peut vous coûter de déclarer une variable à chaque fois que vous utilisez <<.

38voto

vava Points 11364

each passe tout simplement par le biais de tableau et de l'appel de bloc donné avec chaque élément, c'est simple. Depuis l'intérieur de la classe, vous êtes à l'aide du tableau ainsi, vous pouvez simplement rediriger votre each méthode à celui de la matrice, qui est rapide et facile à lire ou à maintenir.

class Result
    include Enumerable

    def initialize
        @results_array = []
    end

    def <<(val)
        @results_array << val
    end

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

r = Result.new

r << 1
r << 2

r.each { |v|
   p v
}

#print:
# 1
# 2

Notez que j'ai mixé en Enumerable. Qui vous donnera un tas de méthodes de tableau comme all?, map, etc. pour libre.

BTW en Ruby, vous pouvez oublier l'héritage. Vous n'avez pas besoin de l'héritage de l'interface, car en tapant duck ne s'inquiètent pas vraiment de type réel, et vous n'avez pas besoin de l'héritage de code parce que mixin sont juste mieux pour ce genre de choses.

5voto

Si vous créez une classe de Résultats qui héritent de la Matrice, vous allez hériter toutes les fonctionnalités.

Vous pouvez ensuite compléter les méthodes qui ont besoin de changement en les redéfinissant, et vous pouvez les appeler super pour l'ancienne fonctionnalité.

Par exemple:

class Results < Array
  # Additional functionality
  def best
    find {|result| result.is_really_good? }
  end

  # Array functionality that needs change
  def compact
    delete(ininteresting_result)
    super
  end
end

Alternativement, vous pouvez utiliser le builtin bibliothèque forwardable. Ceci est particulièrement utile si vous ne pouvez pas hériter de la Matrice parce que vous avez besoin d'hériter d'une autre classe:

require 'forwardable'
class Results
  extend Forwardable
  def_delegator :@result_array, :<<, :each, :concat # etc...

  def best
    @result_array.find {|result| result.is_really_good? }
  end

  # Array functionality that needs change
  def compact
    @result_array.delete(ininteresting_result)
    @result_array.compact
    self
  end
end

Dans ces deux formes, vous pouvez l'utiliser comme vous voulez:

r = Results.new
r << some_result
r.each do |result|
  # ...
end
r.compact
puts "Best result: #{r.best}"

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X