8
votes

METAPROgrammatiquement définissant les méthodes de rubis qui prennent des arguments de mots clés?

struct me permet de créer une nouvelle classe qui prend des arguments et a une belle sémantique. Cependant, les arguments ne sont pas obligés et leur commande nécessite de consulter la définition: xxx

J'aimerais quelque chose de similaire à une structure, mais qui utilise des arguments de mots clés à la place: < Pré> xxx

qui pourrait ressembler à quelque chose comme ceci: xxx

mais ce qui devrait aller dans les accolades pour définir un initialize Méthode sur Klass tel que:

  • Il nécessite des arguments de mots clés sans valeur par défaut;
  • Les mots-clés sont donnés en tant que tableau de symboles dans attributs ; et
  • La méthode initialize attribue à des variables d'instance du même nom

0 commentaires

4 Réponses :


1
votes

Je pourrais mal comprendre la question mais cherchez-vous quelque chose comme ça? XXX PRE>

ALORS P>

Point = StricterStruct.new(:x,:y)
#=> Point
p = Point.new(x: 12, y: 77)
#=> #<Point:0x2a89400 @x=12, @y=77>
p2 = Point.new(x: 17)
#=> ArgumentError
p2 = Point.new(y: 12)
#=> ArgumentError
p2 = Point.new(y:17, x: 22)
#=>  #<Point:0x28cf308 @y=17, @x=22>


7 commentaires

Ce n'est pas tout à fait raison - comme mon exemple montre, point.new (x: 12) aurait dû vous avoir donné une argumentError depuis que vous n'avez pas spécifié y .


@Johnfeminella a raté cette partie. Maintenant, il semble encore plus laid :( mais fonctionne comme demandé.


Je ne comprends pas pourquoi vous introduisez la variable de classe, car attributs est visible avec définir_method .


@Johnfeminellellella a nettoyé beaucoup, j'aime mieux votre message d'erreur, mais cela acceptera les chaînes ou les symboles et les convertira en snake_case downcase.


Il me semble que ce serait mieux sans attributs.map! .


@CarySwoveland Je voulais que cela accepte des choses comme stricterstruct.new ("Ceci est un var") the attributs.map! L'appel me permet de changer cela en place sur ["this_is_a_var"]


Oui, je sais, mais cela répond à une question différente. La question est très spécifique sur les attributs, conformément à un resserrement de struct . En outre, la méthode d'appel peut ne pas vouloir que ces attributs modifiés.



6
votes

J'ai chuté en utilisant un (étonnamment pythonique) ** kwargs code> stratégie, grâce aux nouvelles fonctionnalités de Ruby 2.0 +:

module StricterStruct
  def self.new(*attribute_names_as_symbols)
    c = Class.new
    l = attribute_names_as_symbols

    c.instance_eval {
      define_method(:initialize) do |**kwargs|
        unless kwargs.keys.sort == l.sort
          extra   = kwargs.keys - l
          missing = l - kwargs.keys

          raise ArgumentError.new <<-MESSAGE
            keys do not match expected list:
              -- missing keys: #{missing}
              -- extra keys:   #{extra}
          MESSAGE
        end

        kwargs.map do |k, v|
          instance_variable_set "@#{k}", v
        end
      end

      l.each do |sym|
        attr_reader sym
      end
    }

    c
  end
end


3 commentaires

J'aime le message que je viens de changer le mien pour avoir une structure très similaire bien que je vous ai donné des méthodes de getter et de réglage pour l'instance_variables. Désolé, je n'étais pas aussi rapide que vous répondez à votre propre question :). Notez également que j'ai mis à jour ma réponse pour accepter des chaînes ou des symboles et de les formater comme snake_case.


Ne voulez-vous pas dire def self.new (* attribut_names_as_symbols) ? En outre, je pense que vous pouvez créer chaque accesseur de lecture avec attr_reader sym . Question interessante.


@CarySwoveland Oui, c'est une faute de frappe de ma pâte de copie. Merci d'avoir attrapé ça. Vous avez également raison que Att_Reader est beaucoup plus simple; J'aurais dû ramasser sur ça!



0
votes

On dirait que vous recherchez: OpenStruct :

require 'ostruct'

foo = OpenStruct.new(bar: 1, 'baz' => 2)
foo # => #<OpenStruct bar=1, baz=2>

foo.bar # => 1
foo[:bar] # => 1
foo.baz # => 2
foo.baz = 3
foo # => #<OpenStruct bar=1, baz=3>


2 commentaires

Comme je l'ai mentionné dans l'exemple, l'une des propriétés souhaitées est que argumentError ou une exception similaire est soulevé si vous ne spécifiez pas tout. Parce qu'un openStruct peut être modifié à tout moment, ce n'est pas un bon choix ici. De plus, OpenSruct est beaucoup plus lent que la structure, donc si vous en faites beaucoup, c'est cher.


J'ai toujours considéré l'openssatrice comme la classe pour les personnes qui n'étaient pas sûres de ce qu'ils voulaient. Votre cas nécessite une vérification plus rigoureuse une fois que l'instance est créée, ce qui est définitivement où OpenSrUCT échoue et que je pense être un vote en panne pour OpenStruct. Peut-être que votre code serait un bon ajout à Ruby et OpenSruct pourrait être obsolète à cause de sa lenteur.



0
votes

Je cherchais également cela pour cela, et éventuellement trébuché à travers ce joyau qui fait exactement cela:

https: //github.com/etiennebarrie/kwattr xxx

au lieu de xxx


0 commentaires