142 votes

Ruby - convertit élégamment une variable en tableau si ce n'est pas déjà un tableau

Étant donné un tableau, un seul élément, ou nil, obtient un tableau - les deux derniers étant respectivement un tableau à un seul élément et un tableau vide.

J'ai pensé à tort que Ruby fonctionnerait de cette façon :

[1,2,3].to_a  #= [1,2,3]     # Already an array, so no change
1.to_a        #= [1]         # Creates an array and adds element
nil.to_a      #= []          # Creates empty array

Mais ce que vous obtenez vraiment est :

[1,2,3].to_a  #= [1,2,3]         # Hooray
1.to_a        #= NoMethodError   # Do not want
nil.to_a      #= []              # Hooray

Pour résoudre ce problème, je dois donc soit utiliser une autre méthode, soit métaprogrammer en modifiant la méthode to_a de toutes les classes que j'ai l'intention d'utiliser - ce qui n'est pas une option pour moi.

C'est donc une Méthode :

result = nums.class == "Array".constantize ? nums : (nums.class == "NilClass".constantize ? [] : ([]<<nums))

Le problème, c'est que c'est un peu le bazar. Existe-t-il une manière élégante de procéder ? (Je serais étonné si c'était la façon Ruby-ish de résoudre ce problème).


Quelles sont les applications ? Pourquoi même convertir en tableau ?

Dans ActiveRecord de Rails, l'appel dit, user.posts retournera soit un tableau de messages, un seul message, ou nil. Lorsque vous écrivez des méthodes qui travaillent sur les résultats de cette méthode, il est plus facile de supposer que la méthode prendra un tableau, qui peut avoir zéro, un ou plusieurs éléments. Exemple de méthode :

current_user.posts.inject(true) {|result, element| result and (element.some_boolean_condition)}

7voto

Bruno Meira Points 11

Et si

[].push(anything).flatten

2voto

Pelle ten Cate Points 2613

Au risque d'énoncer une évidence, et sachant que ce n'est pas le sucre syntaxique le plus savoureux jamais vu sur la planète et ses environs, ce code semble faire exactement ce que vous décrivez :

foo = foo.is_a?(Array) ? foo : foo.nil? ? [] : [foo]

1voto

runub Points 171

Vous pouvez écraser la méthode de tableau de l'objet

class Object
    def to_a
        [self]
    end
end

Tout hérite d'Object, donc to_a sera maintenant défini pour tout ce qui existe sous le soleil.

1voto

Malware Skiddie Points 124

J'ai parcouru toutes les réponses et la plupart ne fonctionnent pas avec Ruby 2+.

Mais elado a la solution la plus élégante, à savoir

Avec ActiveSupport (Rails) : Array.wrap

Array.wrap([1, 2, 3]) # => [1, 2, 3]

Array.wrap(1) # => [1]

Array.wrap(nil) # => []

Array.wrap({a : 1, b : 2}) # => [{:a=>1, :b=>2}]]

Malheureusement, cela ne fonctionne pas non plus pour ruby 2+ car vous obtiendrez une erreur

undefined method `wrap' for Array:Class

Pour y remédier, il faut donc exiger.

nécessite 'active_support/deprecation'.

nécessite 'active_support/core_ext/array/wrap'.

0voto

Jefffrey Points 31698

Puisque la méthode #to_a existe déjà pour les deux principales classes problématiques ( Nil et Hash ), il suffit de définir une méthode pour le reste en étendant la méthode Object :

class Object
    def to_a
        [self]
    end
end

et ensuite vous pouvez facilement appeler cette méthode sur n'importe quel objet :

"Hello world".to_a
# => ["Hello world"]
123.to_a
# => [123]
{a:1, b:2}.to_a
# => [[:a, 1], [:b, 2]] 
nil.to_a
# => []

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