Dartでのコード生成。 パート2.注釈、source_genおよびbuild_runner

最初の部分では、コード生成が必要な理由を見つけ、Dartでコード生成に必要なツールをリストしました。 第2部では、Dartで注釈を作成および使用する方法、およびsource_genbuild_runnerを使用してコード生成を開始する方法を学習します。



Dartアノテーション


注釈は、コードに追加できる構文メタデータです。 言い換えると、コードのコンポーネント(クラスやメソッドなど)に追加情報を追加する機会です。 注釈はDartコードで広く使用されています。 @requiredを使用して名前付きパラメーターが必要であることを示し、注釈付きパラメーターが指定されていない場合、コードはコンパイルされません。 また、 @overrideを使用して、親クラスで定義されたAPI @overrideクラスで実装されていることを示します。 注釈は常に@記号で始まります。


独自の注釈を作成する方法は?


コードにメタデータを追加するという考えは少しエキゾチックで複雑に聞こえますが、アノテーションはDart言語で最も単純なものの1つです。 以前に注釈が単に追加情報を運ぶと言われました。 これらはPODO (Plain Old Dart Objects)に似ています。 またconstコンストラクターが定義されている場合、どのクラスも注釈として機能します


 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 {} 

ご覧のとおり、注釈は非常に簡単です。 そして主なことは、これらの注釈を使用して何をするかです。 これはsource_genbuild_runnerます。


build_runnerの使用方法は?


build_runnerは、Dartコードを使用してファイルを生成するのに役立つDartパッケージです。 build.yamlを使用してBuilderファイルを構成します。 設定されると、 Builderはすべてのbuildコマンドで、またはファイルが変更されたときに呼び出されます。 また、変更されたコードや特定の条件を満たすコードを解析する機会もあります。


Dartコードを理解するためのsource_gen


ある意味では、 build_runnerは「 いつコードを生成する必要があるのか​​」という質問に答えるメカニズムです。 同時に、 source_genは「 どのコードを生成する必要がありますか?」という質問に答えます。 source_genは、 source_gen機能するBuilderを作成するためのフレームワークを提供します。 また、 source_genは、コードを解析および生成するための便利なAPIを提供します。


すべてをまとめる:TODOレポート


この記事の残りの部分では、 todo_reporter.dartプロジェクトを逆アセンブルします 。これは、 こちらにあります


コード生成を使用するすべてのプロジェクトが従う未記述のルールがあります。 アノテーションを含む パッケージと、これらのアノテーションを使用するジェネレーター用の個別のパッケージを作成する必要があります。 Dart / Flutterでパッケージライブラリを作成する方法については、 こちらをご覧ください


まず、 todo_reporter.dartディレクトリを作成する必要があります。 このディレクトリ内に、注釈を含むtodo_reporter_generatorディレクトリ、注釈を処理するtodo_reporter_generatorディレクトリ、および作成されるライブラリの機能のデモを含むexampleディレクトリを作成する必要があります。


明確にするために、サフィックス.dartルートディレクトリ名に追加され.dartいます。 もちろん、これは必須ではありませんが、このルールに従って、このパッケージがどのDartプロジェクトでも使用できるという事実を正確に示したいと思います。 それどころか、このパッケージがFlutter( ozzie.flutterなど )専用であることを示したい場合は、別のサフィックスを使用します。 これは必ずしも必要ではありません。単なる命名規則であり、私はそれを順守しようとしています。


シンプルなアノテーションパッケージtodo_reporterの作成


todo_reporter内にtodo_reporter.dartを作成します。 これを行うには、 pubspec.yamlファイルとlibディレクトリを作成します。


pubspec.yaml非常に簡単です。


 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 

開発プロセスで使用されるtestパッケージを除き、依存関係はありません。


libディレクトリで、次を実行する必要があります。



この場合、追加する必要があるのは注釈だけです。 注釈付きのtodo.dartファイルを作成しましょう。


 class Todo { final String name; final String todoUrl; const Todo(this.name, {this.todoUrl}) : assert(name != null); } 

注釈を付けるのに必要なことはそれだけです。 簡単だと言った。 しかし、それだけではありません。 testディレクトリに単体テストを追加しましょう。


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); }); }); } 

これで注釈を作成することができます。 ここでコードを見つけることができます。 これでジェネレーターに行くことができます。


クールな仕事をする:todo_reporter_generator


パッケージの作成方法がわかったので、 todo_reporter_generatorパッケージを作成しましょう。 このパッケージ内には、 pubspec.yamlおよびbuild.yamllibディレクトリが必要です。 libディレクトリには、 srcディレクトリとbuilder.dartファイルがbuilder.dartです。 todo_reporter_generatorは、 dev_dependencyとして他のプロジェクトに追加される個別のパッケージと見なされます。 これは、コード生成が開発段階でのみ必要であり、完成したアプリケーションに追加する必要がないためです。


pubspec.yaml次のとおりです。


 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 

ここでbuild.yaml作成しましょう。 このファイルには、 Builderに必要な構成が含まれています。 詳細はこちらをご覧くださいbuild.yaml次のとおりです。


 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"] 

importプロパティは、 Builderを含むファイルを指し、 builder_factoriesプロパティは、コードを生成するメソッドを指します。


これで、 libディレクトリにbuilder.dartファイルを作成できます。


 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'); 

srcディレクトリーのtodo_reporter_generator.dartファイル:


 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!"; } } 

ご覧のとおり、 builder.dartファイルで、 Builderが作成するtodoReporterメソッドを定義しています。 Builderは、 SharedPartBuilderを使用するTodoReporterGeneratorを使用して作成されます。 したがって、 build_runnersource_gen一緒に機能します。


TodoReporterGeneratorGeneratorForAnnotationサブクラスGeneratorForAnnotation 。そのため、 generateForAnnotatedElementメソッドは、この注釈(この場合は@Todo )がコードで見つかった場合にのみ実行されます。


generateForAnnotatedElementメソッドは、生成されたコードを含む文字列を返します。 生成されたコードがコンパイルされない場合、ビルドフェーズ全体が失敗します。 これは、将来の間違いを避けるのに役立つため、非常に便利です。


したがって、各コード生成で、 todo_repoter_generatorはコメント付きのpartファイルを作成します// Hey! Annotation found! // Hey! Annotation found! 次の記事では、注釈を処理する方法を学びます。


すべてをまとめる:todo_reporterを使用する


これで、 todo_reporter.dartを実演できます。 パッケージを使用する場合は、 exampleプロジェクトを追加することをお勧めします。 そのため、他の開発者は、実際のプロジェクトでAPIを使用する方法を確認できます。


プロジェクトを作成し、必要な依存関係をpubspec.yaml追加しましょう。 この例では、 exampleディレクトリ内にFlutterプロジェクトを作成し、依存関係を追加します。


 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/ 

パッケージを受け取った後( flutter packages get )アノテーションを使用できます:


 import 'package:todo_reporter/todo_reporter.dart'; @Todo('Complete implementation of TestClass') class TestClass {} 

すべてが整ったので、ジェネレーターを実行します:


 $ flutter packages pub run build_runner build 

コマンドが完了すると、プロジェクトに新しいファイルtodo.g.dart表示されます。 次のものが含まれます。


 // GENERATED CODE - DO NOT MODIFY BY HAND part of 'todo.dart'; // ***************************************************************** // TodoReporterGenerator // ******************************************************************** // Hey! Annotation found! 

私たちは望んでいたものを達成しました! これで、コード内の各@Todoアノテーションに対して正しいDartファイルを生成できます。 必要な数だけ試して作成してください。


次の記事で


これで、ファイルを生成するための正しい設定ができました。 次の記事では、生成されたコードが本当にクールなことを行えるように、注釈の使用方法を学習します。 実際、現在生成されているコードはあまり意味がありません。



Source: https://habr.com/ru/post/J446264/


All Articles