Ruby YARD: Dokumentation von Implementierungen von abstrakten Methoden

8

Ich habe ein typisches OO-Muster: eine abstrakte Basisklasse (die abstrakte Methoden definiert) und mehrere Klassen, die diese abstrakten Methoden klassenspezifisch implementieren.

Ich bin es gewohnt, Dokumentation nur einmal in abstrakten Methoden zu schreiben und dann automatisch in mehrere konkrete Klassen zu propagieren (zumindest funktioniert es in Javadoc, in Scaladoc, in Doxygen), dh ich muss es nicht wiederholen die gleiche Beschreibung in allen konkreten Klassen.

Jedoch konnte ich nicht finden, wie man solche Ausbreitung in YARD macht. Ich habe es zum Beispiel versucht:

%Vor%

Was ich bekomme:

  • Code funktioniert wie erwartet - d. h. throws AbstractMethodException wird in der abstrakten Klasse aufgerufen, macht den Job in der konkreten Klasse
  • In YARD ist AbstractClass eindeutig als abstrakt definiert, ConcreteClass ist normal
  • Method Beschreibung und Rückgabetyp ist gut in AbstractClass
  • Methode soll AbstractMethodException in AbstractClass werfen
  • Methode hat überhaupt keine Beschreibung und generische Object Rückgabetyp in ConcreteClass , es gibt keinen einzigen Hinweis darauf, dass eine abstrakte Methode in der Basisklasse existiert.

Was ich erwarte:

  • Die Beschreibung und der Rückgabetyp der Methode werden an ConcreteClass von info at AbstractClass vererbt (d. h. kopiert)
  • Idealerweise wird diese Methode im Abschnitt "geerbt" oder "implementiert" von ConcreteClass description angegeben, mit einem Referenzlink von ConcreteClass#do_something bis AbstractMethod#do_something .

Ist das möglich?

    
GreyCat 15.10.2013, 10:39
quelle

2 Antworten

4

Ich denke, das Problem läuft darauf hinaus, was Sie versuchen zu tun. Es sieht so aus, als ob Sie versuchen, ein Interface in Ruby zu implementieren, was sinnvoll ist, wenn Sie von Java oder .NET kommen, aber Ruby-Entwickler arbeiten nicht wirklich so.

Hier finden Sie einige Informationen über die typischen Überlegungen zu Interfaces in Ruby: Was? Ist Java-Interface in Ruby identisch?

Das heißt, ich verstehe, was Sie zu tun versuchen. Wenn Sie nicht möchten, dass Ihre AbstractClass direkt implementiert wird, sondern Methoden, die in einer Klasse verwendet werden können, die sich wie die AbstractClass-Regeln verhält (wie in Entwurf nach Vertrag ), dann möchten Sie wahrscheinlich ein Modul verwenden. Module funktionieren sehr gut, um Ihren Code DRY zu behalten, aber sie lösen Ihr Problem bei der Dokumentation von überschriebene Methoden . An diesem Punkt denke ich, dass Sie darüber nachdenken können, wie Sie an die Dokumentation herangehen oder sich ihr zumindest auf eine eher rubinartige Weise nähern.

Vererbung in Ruby ist wirklich (im Allgemeinen aus meiner eigenen Erfahrung) nur aus ein paar Gründen verwendet:

  • Wiederverwendbarer Code und Attribute
  • Standardverhalten
  • Spezialisierung

Es gibt offensichtlich andere Randfälle, aber ehrlich gesagt ist es das, wofür Vererbung in Ruby verwendet wird. Das bedeutet nicht, dass das, was Sie tun, nicht funktioniert oder gegen eine Regel verstößt, es ist in Ruby (oder dynamisch am stärksten typisierten Sprachen) nicht typisch. Dieses atypische Verhalten ist wahrscheinlich der Grund, warum YARD (und andere Ruby-Doc-Generatoren) nicht das tun, was Sie erwarten. Wenn Sie jedoch eine abstrakte Klasse erstellen, die nur die Methoden definiert, die in einer Unterklasse vorhanden sein müssen, gewinnen Sie aus Codeperspektive wirklich wenig. Nicht definierte Methoden führen dazu, dass eine NoMethodError-Ausnahme trotzdem ausgelöst wird, und Sie können programmgesteuert prüfen, ob ein Objekt auf einen Methodenaufruf (oder irgendeine andere Nachricht) reagiert, unabhängig davon, welche Methoden aufgerufen werden, indem Sie #respond_to?(:some_method) (oder andere reflektive Werkzeuge verwenden) um Metastücke zu bekommen). Es kommt alles zurück Ruby Verwendung von Duck Typing .

Warum sollten Sie für eine reine Dokumentation eine Methode dokumentieren, die Sie nicht verwenden? Sie sollten sich nicht wirklich um die Klasse des Objekts kümmern, das vom Aufruf einer Methode gesendet oder empfangen wird, sondern nur, worauf diese Objekte antworten . Machen Sie sich also nicht die Mühe, Ihre AbstractClass überhaupt zu erstellen, wenn sie hier keinen wirklichen Wert hinzufügt. Wenn es Methoden enthält, die Sie direkt aufrufen, ohne es zu überschreiben, erstellen Sie ein Modul, dokumentieren Sie es dort und führen Sie $ yardoc --embed-mixins aus, um Methoden (und ihre Beschreibungen) einzubeziehen, die in gemischten Modulen definiert sind. Andernfalls dokumentieren Sie Methoden, bei denen Sie sie tatsächlich implementieren, da jede Implementierung anders sein sollte (andernfalls sollten Sie sie erneut implementieren).

So würde ich etwas Ähnliches wie das machen:

%Vor%

Beim Ausführen von YARD (mit - embed-mixins) werden die Methoden aus dem Stuff-Modul (zusammen mit ihren Beschreibungen) eingefügt, und Sie wissen jetzt, dass jedes Objekt einschließlich des Stuff-Moduls die erwartete Methode aufweist.

Sie können sich auch Ruby-Verträge ansehen, da es sich vielleicht näher an dem befindet, wonach Sie suchen Erzwinge absolut Methoden, um nur die gewünschten Objekttypen zu akzeptieren und zurückzugeben, aber ich bin nicht sicher, wie das mit YARD funktionieren wird.

    
jgnagy 23.10.2013 17:24
quelle
0

Nicht ideal, aber Sie können trotzdem das (see ParentClass#method) -Konstrukt verwenden (dokumentiert hier ). Nicht ideal, weil Sie dies manuell für jede überschreibende Methode eingeben müssen.

Abgesehen davon, dass ich kein Yard-Spezialist bin, aber angesichts seiner besonders anpassungsfähigen Architektur wäre ich überrascht, dass es keinen einfachen Weg geben würde, das zu implementieren, was Sie brauchen, indem Sie Yard irgendwo im Vorlagen Abteilung, denke ich.

    
fabschurt 26.02.2015 14:19
quelle