3 votes

ruby : initialisation en masse des variables d'instance

Existe-t-il un moyen simple d'assigner des variables d'instance en masse ?

  def initialize(title: nil, label_left: nil, label_right: nil, color_set: nil)
    @title = title
    @label_left = label_left
    @label_right = label_right
    @color_set = color_set
  end

Puis-je boucler/itérer à travers les arguments d'initialisation et assigner automatiquement ?

9voto

tadman Points 70178

Si vous voulez des variables spécifiques, alors pas vraiment. Utiliser la réflexion ici, même si elle était disponible, serait un problème.

Ce que vous avez ici est le cas le plus trivial. Souvent, vous verrez du code qui ressemble plus à ceci :

def initialize(title: nil, label: nil, label_width: nil, color_set: nil)
  @title = title.to_s
  @label = label_left.to_s
  @label_width = label_width.to_i
  @color_set = MyRGBConverter.to_rgb(color_set)
end

L'initialisateur est un endroit où vous pouvez effectuer toute conversion et validation nécessaires. Si certains de ces arguments doivent avoir certaines valeurs, vous aurez des tests pour cela, raise une exception sur une erreur et ainsi de suite. Le code répétitif que vous avez ici dans le cas minimal est souvent étendu et augmenté de sorte qu'il n'y a pas de solution générale possible.

Cela conduit à un code comme celui-ci :

def initialize(title: nil, label: nil, label_width: nil, color_set: nil)
  @title = title.to_s
  unless (@title.match(/\S/))
    raise "Title not specified"
  end

  @label = label_left.to_s
  unless (@label.match(/\A\w+\z/))
    raise "Invalid label #{@label.inspect}"
  end

  @label_width = label_width.to_i
  if (@label_width <= 0)
    raise "Label width must be > 0, #{@label_width} specified."
  end

  @color_set = MyRGBConverter.to_rgb(color_set)
end

Si vous ne vous souciez vraiment pas des arguments que vous recevez, vous pouvez le faire dans Ruby 2.3 avec la nouvelle fonction mots-clés-arguments prescripteur ** :

def initialize(**options)
  options.each do |key, value|
    instance_variable_set("@#{key}", value)
  end
end

Notez que c'est potentiellement dangereux si ces valeurs sont fournies par l'utilisateur, donc vous pourriez vouloir les mettre sur liste blanche d'une manière ou d'une autre :

VALID_OPTIONS = [ :title, :label_left, :label_right, :color_set ]

def initialize(**options)
  options.each do |key, value|
    raise "Unknown option #{key.inspect}" unless (VALID_OPTIONS.include?(key))

    instance_variable_set("@#{key}", value)
  end
end

Si vous constatez que beaucoup de ces arguments sont transmis régulièrement, vous pouvez envisager de créer une sorte d'objet structuré et de le transmettre, ce qui serait une meilleure solution. Cela dépend de la façon dont votre code fonctionne.

1voto

user1934428 Points 3811

@tadman a déjà fourni une excellente réponse à cette question, mais en voici une autre : Si vous êtes prêt à vous passer des paramètres nommés, vous pourriez faire comme ceci :

def initialize(*args)
  @title, @label_left, @label_right, @color_set, *nada = args
  fail "Too many arguments" unless nada.empty?
end 

[MISE À JOUR : correction du code, selon le commentaire donné par @sawa].

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