最初の部分では、コード生成が必要な理由を見つけ、Dartでコード生成に必要なツールをリストしました。 第2部では、Dartで注釈を作成および使用する方法、およびsource_genとbuild_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_gen
とbuild_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_reporter.dart
ファイルを作成する必要があります。todo_reporter.dart
ファイルでは、export
を使用して、パブリックAPIを持つすべてのクラスが指定されます。 パッケージ内のクラスはimport 'package:todo_reporter/todo_reporter.dart';
を使用してimport 'package:todo_reporter/todo_reporter.dart';
できるため、これは良い習慣import 'package:todo_reporter/todo_reporter.dart';
。 ここでこのクラスを見ることができます 。 -
lib
ディレクトリ内に、すべてのコード(パブリックおよび非パブリック)を含むsrc
ディレクトリを作成します。
この場合、追加する必要があるのは注釈だけです。 注釈付きのtodo.dart
ファイルを作成しましょう。
class Todo { final String name; final String todoUrl; const Todo(this.name, {this.todoUrl}) : assert(name != null); }
注釈を付けるのに必要なことはそれだけです。 簡単だと言った。 しかし、それだけではありません。 test
ディレクトリに単体テストを追加しましょう。
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.yaml
とlib
ディレクトリが必要です。 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_runner
とsource_gen
一緒に機能します。
TodoReporterGenerator
はGeneratorForAnnotation
サブクラス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ファイルを生成できます。 必要な数だけ試して作成してください。
次の記事で
これで、ファイルを生成するための正しい設定ができました。 次の記事では、生成されたコードが本当にクールなことを行えるように、注釈の使用方法を学習します。 実際、現在生成されているコードはあまり意味がありません。