Im ersten Teil haben wir herausgefunden, warum Codegenerierung erforderlich ist, und die erforderlichen Tools für die Codegenerierung in Dart aufgelistet. Im zweiten Teil erfahren Sie, wie Sie Anmerkungen in Dart erstellen und verwenden sowie wie Sie source_gen und build_runner verwenden , um die Codegenerierung zu starten.

Dart-Anmerkungen
Anmerkungen sind syntaktische Metadaten, die dem Code hinzugefügt werden können. Mit anderen Worten, es besteht die Möglichkeit, jeder Komponente des Codes zusätzliche Informationen hinzuzufügen, z. B. einer Klasse oder Methode. Anmerkungen werden im Dart-Code häufig verwendet: Wir verwenden @required
um anzuzeigen, dass ein benannter Parameter erforderlich ist, und unser Code wird nicht kompiliert, wenn der mit Anmerkungen versehene Parameter nicht angegeben wird. Wir verwenden @override
auch, um @override
, dass eine bestimmte in einer übergeordneten Klasse definierte API in einer @override
Klasse implementiert ist. Anmerkungen beginnen immer mit dem @
-Symbol.
Wie erstelle ich eine eigene Anmerkung?
Obwohl die Idee, dem Code Metadaten hinzuzufügen, etwas exotisch und kompliziert klingt, sind Anmerkungen eines der einfachsten Dinge in der Dart-Sprache. Es wurde bereits gesagt, dass Anmerkungen lediglich zusätzliche Informationen enthalten . Sie ähneln PODO (Plain Old Dart Objects). Und jede Klasse kann als Annotation dienen, wenn darin ein const
Konstruktor definiert ist :
class { final String name; final String todoUrl; const Todo(this.name, {this.todoUrl}) : assert(name != null); } @Todo('hello first annotation', todoUrl: 'https://www.google.com') class HelloAnnotations {}
Wie Sie sehen können, sind Anmerkungen sehr einfach. Und was zählt, ist, was wir mit diesen Anmerkungen machen werden. Dies wird uns helfen, source_gen
und build_runner
.
Wie benutzt man build_runner?
build_runner
ist ein Dart-Paket, mit dem wir Dateien mit Dart-Code generieren können. Wir werden Builder
Dateien mit build.yaml
. Wenn es konfiguriert ist, wird Builder
bei jedem build
Befehl aufgerufen oder wenn die Datei geändert wird. Wir haben auch die Möglichkeit, Code zu analysieren, der geändert wurde oder bestimmte Kriterien erfüllt.
source_gen zum Verständnis von Dartcode
In gewisser build_runner
ist build_runner
ein Mechanismus, der die Frage " Wann muss ich Code generieren?" Beantwortet. Gleichzeitig beantwortet source_gen
die Frage „ Welcher Code soll generiert werden?“. source_gen
bietet ein Framework zum Erstellen von Buildern, damit build_runner
funktioniert. Außerdem bietet source_gen
eine praktische API zum Parsen und Generieren von Code.
Alles zusammen: TODO-Bericht
Im Rest dieses Artikels werden wir das Projekt todo_reporter.dart zerlegen , das hier zu finden ist .
Es gibt eine ungeschriebene Regel, der alle Projekte folgen, die die Codegenerierung verwenden: Sie müssen ein Paket mit Anmerkungen und ein separates Paket für den Generator erstellen, der diese Anmerkungen verwendet. Informationen zum Erstellen einer Paketbibliothek in Dart / Flutter finden Sie hier .
Zuerst müssen Sie das Verzeichnis todo_reporter.dart
erstellen. In diesem Verzeichnis müssen Sie das Verzeichnis todo_reporter
erstellen, das die Anmerkung enthält, das Verzeichnis todo_reporter_generator
, um die Anmerkung zu verarbeiten, und schließlich das example
das eine Demonstration der Funktionen der zu erstellenden Bibliothek enthält.
Das Suffix .dart
aus Gründen der Übersichtlichkeit zum Stammverzeichnisnamen hinzugefügt. Dies ist natürlich nicht erforderlich, aber ich befolge diese Regel gerne, um genau anzuzeigen, dass dieses Paket in jedem Dart-Projekt verwendet werden kann. Im Gegenteil, wenn ich angeben wollte, dass dieses Paket nur für Flutter ist (wie ozzie.flutter ), würde ich ein anderes Suffix verwenden. Dies ist nicht notwendig, es ist nur eine Namenskonvention, die ich einzuhalten versuche.
Erstellen Sie todo_reporter, unser einfaches Anmerkungspaket
Wir werden todo_reporter
in todo_reporter.dart
erstellen. Erstellen Sie dazu die Datei pubspec.yaml
und das Verzeichnis lib
.
pubspec.yaml
sehr einfach:
name: todo_reporter description: Keep track of all your TODOs. version: 1.0.0 author: Jorge Coca <jcocaramos@gmail.com> homepage: https://github.com/jorgecoca/todo_reporter.dart environment: sdk: ">=2.0.0 <3.0.0" dependencies: dev_dependencies: test: 1.3.4
Es gibt keine Abhängigkeiten außer dem im Entwicklungsprozess verwendeten Testpaket.
lib
im lib
Verzeichnis wie folgt vor:
- Sie müssen die Datei
todo_reporter.dart
erstellen, in der beim export
alle Klassen mit einer öffentlichen API angegeben werden. Dies ist eine gute Vorgehensweise, da jede Klasse in unserem Paket mit import 'package:todo_reporter/todo_reporter.dart';
importiert werden kann import 'package:todo_reporter/todo_reporter.dart';
. Sie können diese Klasse hier sehen . - Innerhalb des
lib
Verzeichnisses erstellen wir das src
Verzeichnis, das den gesamten Code enthält - öffentlich und nicht öffentlich.
In unserem Fall müssen wir lediglich eine Anmerkung hinzufügen. Erstellen wir eine todo.dart
Datei mit unserer Anmerkung:
class Todo { final String name; final String todoUrl; const Todo(this.name, {this.todoUrl}) : assert(name != null); }
Das ist alles, was Sie zum Kommentieren benötigen. Ich sagte, dass es einfach sein wird. Das ist aber noch nicht alles. Fügen wir dem Testverzeichnis Unit-Tests hinzu:
todo_test.dart import 'package:test/test.dart'; import 'package:todo_reporter/todo_reporter.dart'; void main() { group('Todo annotation', () { test('must have a non-null name', () { expect(() => Todo(null), throwsA(TypeMatcher<AssertionError>())); }); test('does not need to have a todoUrl', () { final todo = Todo('name'); expect(todo.todoUrl, null); }); test('if it is a given a todoUrl, it will be part of the model', () { final givenUrl = 'http://url.com'; final todo = Todo('name', todoUrl: givenUrl); expect(todo.todoUrl, givenUrl); }); }); }
Dies ist alles, was wir zum Erstellen der Anmerkung benötigen. Den Code finden Sie hier . Jetzt können wir zum Generator gehen.
Einen coolen Job machen: todo_reporter_generator
todo_reporter_generator
wir nun wissen, wie Pakete erstellt werden, erstellen todo_reporter_generator
Paket todo_reporter_generator
. In diesem Paket sollten sich die build.yaml
pubspec.yaml
und build.yaml
sowie ein lib
Verzeichnis befinden. Das lib
Verzeichnis muss das src
Verzeichnis und die Datei builder.dart
enthalten. Unser todo_reporter_generator
wird als separates Paket betrachtet, das als dev_dependency
zu anderen Projekten hinzugefügt wird. Dies liegt daran, dass die Codegenerierung nur in der Entwicklungsphase erforderlich ist und nicht zur fertigen Anwendung hinzugefügt werden muss.
pubspec.yaml
wie folgt:
name: todo_reporter_generator description: An annotation processor for @Todo annotations. version: 1.0.0 author: Jorge Coca <jcocaramos@gmail.com> homepage: https://github.com/jorgecoca/todo_reporter.dart environment: sdk: ">=2.0.0 <3.0.0" dependencies: build: '>=0.12.0 <2.0.0' source_gen: ^0.9.0 todo_reporter: path: ../todo_reporter/ dev_dependencies: build_test: ^0.10.0 build_runner: '>=0.9.0 <0.11.0' test: ^1.0.0
Jetzt erstellen build.yaml
. Diese Datei enthält die für unsere Builder erforderliche Konfiguration. Weitere Details finden Sie hier . build.yaml
wie folgt:
targets: $default: builders: todo_reporter_generator|todo_reporter: enabled: true builders: todo_reporter: target: ":todo_reporter_generator" import: "package:todo_reporter_generator/builder.dart" builder_factories: ["todoReporter"] build_extensions: {".dart": [".todo_reporter.g.part"]} auto_apply: dependents build_to: cache applies_builders: ["source_gen|combining_builder"]
Die import
Eigenschaft verweist auf die Datei, die den Builder
enthält, und die Eigenschaft builder_factories
verweist auf die Methoden, mit denen der Code generiert wird.
Jetzt können wir die Datei builder.dart
im lib
Verzeichnis erstellen:
import 'package:build/build.dart'; import 'package:source_gen/source_gen.dart'; import 'package:todo_reporter_generator/src/todo_reporter_generator.dart'; Builder todoReporter(BuilderOptions options) => SharedPartBuilder([TodoReporterGenerator()], 'todo_reporter');
Und die Datei todo_reporter_generator.dart
im Verzeichnis src
:
import 'dart:async'; import 'package:analyzer/dart/element/element.dart'; import 'package:build/src/builder/build_step.dart'; import 'package:source_gen/source_gen.dart'; import 'package:todo_reporter/todo_reporter.dart'; class TodoReporterGenerator extends GeneratorForAnnotation<Todo> { @override FutureOr<String> generateForAnnotatedElement( Element element, ConstantReader annotation, BuildStep buildStep) { return "// Hey! Annotation found!"; } }
Wie Sie sehen können, builder.dart
wir in der Datei todoReporter
die vom Builder
erstellte Methode builder.dart
definiert. Builder
wird mit dem SharedPartBuilder
, der unseren TodoReporterGenerator
. build_runner
und source_gen
arbeiten also zusammen.
Unser TodoReporterGenerator
ist eine Unterklasse von GeneratorForAnnotation
, daher wird die generateForAnnotatedElement
Methode nur ausgeführt, wenn diese Annotation (in unserem Fall @Todo
) im Code gefunden wird.
Die generateForAnnotatedElement
Methode gibt eine Zeichenfolge zurück, die unseren generierten Code enthält. Wenn der generierte Code nicht kompiliert wird, schlägt die gesamte Erstellungsphase fehl . Dies ist sehr nützlich, da es Fehler in der Zukunft vermeidet.
Daher erstellt unser todo_repoter_generator
bei jeder Codegenerierung eine todo_repoter_generator
mit dem Kommentar // Hey! Annotation found!
// Hey! Annotation found!
Im nächsten Artikel erfahren Sie, wie Sie Anmerkungen verarbeiten.
Alles zusammen: mit todo_reporter
Jetzt können Sie zeigen, wie todo_reporter.dart
. Es wird empfohlen, ein example
hinzuzufügen, wenn Sie mit Paketen arbeiten. So können andere Entwickler sehen, wie die API in einem realen Projekt verwendet werden kann.
Lassen Sie uns ein Projekt erstellen und die erforderlichen Abhängigkeiten zu pubspec.yaml
. In unserem Fall erstellen wir ein Flutter-Projekt im example
und fügen die Abhängigkeiten hinzu:
dependencies: flutter: sdk: flutter todo_reporter: path: ../todo_reporter/ dev_dependencies: build_runner: 1.0.0 flutter_test: sdk: flutter todo_reporter_generator: path: ../todo_reporter_generator/
Nach Erhalt der Pakete ( flutter packages get
) können wir unsere Anmerkung verwenden:
import 'package:todo_reporter/todo_reporter.dart'; @Todo('Complete implementation of TestClass') class TestClass {}
Nachdem alles vorhanden ist, lassen Sie unseren Generator laufen:
$ flutter packages pub run build_runner build
Nachdem der Befehl ausgeführt wurde, werden Sie eine neue Datei in unserem Projekt todo.g.dart
: todo.g.dart
. Es wird Folgendes enthalten:
Wir haben erreicht, was wir wollten! Jetzt können wir die richtige Dart-Datei für jede @Todo
Annotation in unserem Code generieren. Versuchen Sie, so viele zu erstellen, wie Sie benötigen.
Im nächsten Artikel
Jetzt haben wir die richtigen Einstellungen zum Generieren von Dateien. Im nächsten Artikel erfahren Sie, wie Sie Anmerkungen verwenden, damit der generierte Code wirklich coole Dinge bewirken kann. Schließlich macht der Code, der jetzt generiert wird, wenig Sinn.