12
votes

Meilleur moyen d'obtenir des attributs d'initialisation abstraite

Quelle est la meilleure façon de résumer ce modèle:

class MyClass
  attr_accessor :foo, :bar

  def initialize(foo, bar)
    @foo, @bar = foo, bar
  end
end


6 commentaires

C'est vraiment vague. Quelle partie de cela voulez-vous abstrait? Comment voulez-vous résumer?


De plus, vous pouvez essayer de demander ici: refactoryCode.com


Je souhaite soit créer un module que je peux mélanger en classes ou remplacer la classe elle-même afin que je puisse écrire une seule ligne de code et avoir créé les accesseurs et l'initialisateur.


Avez-vous besoin de spécifier des paramètres non-attr_accessor pour initialiser? Envisagez-vous des commandes générationnelles des attraisons de super-classes dans la signature?


Je ne suis pas sûr ... J'aimerais éviter de perdre l'initialisateur créé par Initialize_with Si un nouvel initialiseur est créé, mais je comprends que cela introduit une certaine confusion autour de la signature de la méthode. Peut-être que vous feriez: foo.new (new_arg, new_arg2,: foo => 1,: bar => 2)? Cela semble également potentiellement déroutant. Les pensées?


Je voudrais probablement aller avec foo.new {user_param ,: user_option => option_value ,: attrs => {: foo => 1,: bar => 2}}. C'est un peu verbeux, mais je ne sais pas comment le faire d'autre. Vous pouvez même classer_eval les Attr_Accessors en provenance d'une initialisation des appelants, s'ils n'existent pas encore sur l'objet.


5 Réponses :


1
votes

C'est la première solution qui me vient à l'esprit. Il y a un gros inconvénient dans mon module: vous devez définir la méthode d'initialisation de la classe avant d'inclure le module ou cela ne fonctionnera pas.

Il y a probablement une meilleure solution pour ce problème, mais c'est ce que j'ai écrit en moins de deux minutes.

En outre, je n'ai pas eu trop de performances. Vous pouvez probablement trouver une bien meilleure solution que moi, surtout parler de performances. ;) xxx


2 commentaires

Je rejette à peu près cette solution hors de la main pour la dépendance de l'activesupport. Toute dépendance pour ce type de chose serait indésirable, mais obligeant que la bibliothèque de rubs rubis odieux autour de viennent juste une insulte à la blessure.


J'ai utilisé ActiveSupport juste pour profiter de alias_method_chain, mais vous n'en avez pas besoin du tout. Vous pouvez utiliser des alias.



7
votes

Une solution à ce problème déjà (partiellement) Existe , mais Si vous souhaitez une approche plus déclarative dans vos classes, les suivants doivent fonctionner. XXX PRE>

Vous pouvez maintenant faire: P>

class MyClass < ParentClass
  initialize_with :foo, :bar
  def initialize(baz)
    @initialized = true
    super(baz) # pass any arguments to initializer of superclass
  end
end
my_obj = MyClass.new "foo", "bar", "baz"
my_obj.foo #=> "foo"
my_obj.bar #=> "bar"
my_obj.instance_variable_get(:@initialized) #=> true
  • Spécifiez les attributs de constructeur avec initialize_with code> li>
  • Utilisez éventuellement initialiser code> pour effectuer une initialisation personnalisée li>
  • possible d'appeler super code> dans initialiser code> li>
  • Arguments à Initialiser CODE> sont les arguments qui n'ont pas été consommés par des attributs spécifiés avec initialize_with code> li>
  • facilement extrait dans un module li>
  • Constructor Attributs spécifiés avec initialisze_with code> sont hérités, mais la définition d'un nouvel ensemble sur une classe enfant supprimera les attributs parent li>
  • Solution dynamique a probablement une performance frappée li> ul>

    Si vous souhaitez créer une solution avec une performance minimale absolue, il ne serait pas si difficile de refacteur la plupart em> de la fonctionnalité dans une chaîne qui peut être eval ED lorsque l'initialiseur est défini. Je n'ai pas comparé quelle est la différence. P>

    Remarque: j'ai trouvé que le piratage nouveau code> fonctionne mieux que le piratage initialiser code>. Si vous définissez initialiser code> avec métaprogramming, vous obtiendrez probablement un scénario dans lequel vous passez un bloc à initialize_with code> comme initialisateur de substitution, et il n'est pas possible d'utiliser super code> dans un bloc. p> p>


2 commentaires

Cette solution a l'air assez bien. Il semble que vous puissiez appeler Zsuper (Super sans parens ni arguments), c'est-à-dire super au lieu de Super (Baz). J'aimerais certainement voir une solution qui n'a pas besoin de définir_method et que vous pourriez éviter d'utiliser instance_variable_set. Comme vous l'avez souligné, cela nécessiterait probablement des chaînes eval.


J'accepte cette solution même s'il utilise Define_Method. Je vais soumettre ma propre réponse ci-dessous demain pour la considération de chacun.



1
votes
class MyClass < Struct.new(:foo, :bar)
end

4 commentaires

Le problème avec cette solution est que si vous ajoutez un initialiseur avec des arguments, il essuie l'initialiseur de structure par défaut.


Vous pouvez toujours faire des choses comme: classe myClass


J'aime la classe myclass


J'ai constaté que héritating de struct.new () brise () la rechargement automatique des rails et conduit également à TypeErrors: Stackoverflow.com/Questtions/9785694/...



0
votes

Ce module permet à un hasch comme une option de nouvelle (). Vous pouvez inclure le module dans une classe avec héritage et le constructeur fonctionne toujours.

J'aime mieux que la liste des valeurs d'attr tant que paramètres, car, en particulier avec des attractions héritées, je n'aimerais pas d'essayer de vous rappeler quel paramètre était lequel. xxx

et vous pouvez faire ceci: xxx


0 commentaires

1
votes

Je sais que c'est une vieille question avec des réponses parfaitement acceptables, mais je voulais poster ma solution car il tire parti de Module # Prepend code> (Nouveau dans Ruby 2.2) et le fait que les modules sont aussi des cours Pour une solution très simple. D'abord le module pour faire la magie:

class MyClass
  prepend InitializeWith.new :foo, :bar

  def initialize extra
    puts extra
  end
end
MyClass.new 'baz', 'boo', 'dog'


0 commentaires