2017-10-13 25 views
2

J'essaie de créer un trait d'attribut. Le cas d'utilisation consiste à marquer certains attributs d'une classe comme "crudable" dans le contexte d'un mappage objects-to-documents alors que d'autres ne le sont pas.Perl 6 - Est-il possible de créer un trait d'attribut qui définit un méta-attribut?

role crud { 
    has Bool $.crud is default(True); 
} 

multi trait_mod:<is>(Attribute $a, crud, $arg) { 
    $a.container.VAR does crud($arg); 
} 

class Foo { 
    has $.bar is rw; 

    # Provide an extra nested information 
    has $.baz is rw is crud(True); 
} 

En lisant et en adaptant some example code, je réussi à obtenir quelque chose qui semble faire ce que je veux. Voici a snippet with test case.

Quand j'instancier un nouveau Foo objet et définissez l'attribut $.bar (qui is pas crud), ça ressemble à ça:

.Foo @0 
├ $.bar is rw = 123456789 
└ $.baz is rw = .Scalar+{crud} @1 
    └ $.crud +{crud} = True 

Ce que je comprends est que l'attribut $.baz a ce que j'appelle meta-attribut qui est indépendant de sa valeur potentielle.

Cela me semble bon (si j'ai bien compris ce que j'ai fait ici et que mes traits ne sont pas un hack sale). Il est possible d'atteindre $foo.baz.crud, soit True. Cependant, je ne comprends pas très bien ce que veut dire , et si je peux y mettre quelque chose et comment.

Lorsque je tente de définir l'attribut $.baz instance, cette erreur est renvoyée:

Cannot modify an immutable Scalar+{crud} (Scalar+{crud}.new(crud => Bool::True)) 
    in block <unit> at t/08-attribute-trait.t line 30 

Note: Ceci est la chose la plus proche à une solution de travail que je réussi à obtenir. Je n'ai pas besoin de paramètres de crud différents pour différentes instances de classes Foo instanciées.

Je ne veux jamais changer la valeur du booléen, en fait, une fois l'objet instancié, juste fournissant aux attributs avec is crud. Je ne suis même pas intéressé de passer une valeur True ou False comme argument: s'il serait possible de simplement définir l'attribut de trait booléen à True par défaut, cela suffirait. Je ne l'ai pas réussi à le faire si, comme:

multi trait_mod:<is>(Attribute $a, :$crud!) { 
    # Something like this 
    $a.container.VAR does set-crud; 
} 

class Foo { 
    has $.bar is rw; 
    has $.baz is rw is crud; 
} 

Suis-je essayer de faire quelque chose d'impossible? Comment pourrais-je adapter ce code pour réaliser ce cas d'utilisation?

+2

Pourriez-vous expliquer ce que 'fait crud ($ arg)' fait étant donné que 'crud' ne prend pas d'arguments? Ou, étant donné que cela ressemble à un faux code et que vous dites que ce n'est pas pertinent pour votre attention dans cette question de toute façon, éditez-le? En d'autres termes, faites du dernier bit du code le cœur de la question et jetez le premier morceau de code. Cela a-t-il du sens? – raiph

+2

Oh!Étant donné la version simplifiée de la question (en ignorant '$ arg'), il me semble soudain que vous essayez simplement de faire ce' role crud {}; classe Foo {a $ .baz est rw est crud}; dis Foo.new.baz ~~ crud; # True' devrait faire au lieu de ce qu'il fait actuellement, à savoir se plaindre que "est un trait sur la variable $ -sigil pas encore implémenté. Suis-je à des kilomètres ou ...? – raiph

+2

Et si je ne suis pas à des kilomètres, qu'en est-il de la fonction de 'role crud {}; classe Foo {has @ .baz est rw est crud}; dis Foo.new.baz ~~ crud; # True, c'est-à-dire utiliser un tableau au lieu d'un scalaire? – raiph

Répondre

4

Il y a plusieurs choses qui se passent ici. Tout d'abord, la signature du trait_mod semble être fausse. Deuxièmement, il semble y avoir une mauvaise interaction lorsque le nom d'un trait est le même qu'un rôle existant. Je crois que cela devrait être une exception de la NYI, mais apparemment, ça ne va pas dans l'analyse, ou ça ne va pas dans le fait d'essayer de produire le message d'erreur.

Quoi qu'il en soit, je pense que c'est ce que vous voulez:

role CRUD {}; # since CRUD is used as an acronym, I chose to use uppercase here 

multi trait_mod:<is>(Attribute:D $a, :$crud!) { # note required named attribute! 
    $a.^mixin: CRUD if $crud; # mixin the CRUD role if a True value was given 
} 

class A { 
    has $.a is crud(False); # too bad "is !crud" is invalid syntax 
    has $.b is crud; 
} 

say "$_.name(): { $_ ~~ CRUD }" for A.^attributes; # $!a: False, $!b: True 

Hope this helps.

+0

Merci beaucoup Elizabeth, ça aide beaucoup! C'était difficile de trouver comment faire cela tout seul car j'ai commencé à travailler avec Perl6 la semaine dernière seulement après avoir lu le "Perl 6 Introduction" de Naoum Hankache (très clair et efficace pour un démarrage rapide). J'attends une copie du livre "Perl6 en un coup d'oeil" et je me sens très excité de découvrir plus. – smonff