blog

[Flutter】パート2 Dartでコードを生成する:アノテーション、source_gen、build_runner

パート1 Dartでのコード生成:基本」では、コード生成の背後にある動機が何であるかを紹介し、コンピュータに難しい仕事をさせるためのDartの最も重要なツールのリストを紹介しました。この記事では、Da...

Jan 6, 2021 · 9 min. read
シェア

原文:

公開: 2018年10月31日 - 7 分 読む

」では、コード生成の背景にある動機とは何かを紹介し、コンピュータが大変な作業を行うためのDartにおける最も重要なツールを列挙しました。この記事では、Dartアノテーションの作成方法と使用方法、そして使用して作業を開始する方法について説明します。

Dartのアノテーション

アノテーションは、Dart コードに追加できる構文メタデータの一形態です。言い換えれば、コードの任意のコンポーネントに追加情報を追加する方法です。アノテーションは、Dartのコードのいたるところで見かけることができます。@requiredを使用して、名前付きパラメータがオプションではないことを指定し、アノテーションされたフィールドが存在しない場合はコードがコンパイルされないようにしたり、@overrideを使用して、親クラスで指定されたAPIが子クラスで実装されていることを特定したりします。なぜアノテーションだとわかるのでしょうか?アノテーションを見つけるのは簡単です。

しかし、注釈はどのように作成されるのでしょうか?

クラス内に「メタデータ」を持つというアイデアは、非常にエキゾチックで複雑に聞こえますが、アノテーションは実際にはDartで最も単純なものの1つです。上の段落で、アノテーションは単に余分な情報を運ぶものだと述べました。データクラスのようなものです。定数コンストラクタさえあれば、どんなクラスでもアノテーションに変換できます。

class Todo {
 final String name; final String todoUrl; final
 final String todoUrl.Const Todo(this.name, {this.todoUrl} : assert(name !
 const Todo(this.name, {this.todoUrl}) : assert(name != null);
}
@Todo('hello first annotation', todoUrl: 'https://..om')
class HelloAnnotations {}

ご覧のように、注釈はとてもシンプルです。重要なのは、アノテーションをどのように使うかです。アノテーションに含まれる情報と、その情報をどのように使うかが、アノテーションを特別なものにするのです。そこで、source_genとbuild_runnerが役に立ちます。

ビルドの使い方_runner

build_runnerは、Dart コードを使用してファイルを生成するのに役立つ Dart パッケージです。Builderファイルはbuild.yamlを介して設定されます。一度設定されると、ビルドがトリガーされるか、ファイルが変更されると、更新が受信され、変更されたコードや特定の標準に準拠したコードを解析できるようになります。

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

ある意味で、build_runner は、いつコードを生成する必要があるかという質問に答えるメカニズムであり、source_gen は、どのようなコードを生成する必要があるかという質問に対する答えであると考えることができます。source_gen は、build_runner が期待するものを構築するためのフレームワークを提供すると同時に、コードを解析して生成するためのユーザーフレンドリーな API を公開します。

すべてのピースをまとめる:TODOレポーター。

この記事の続きでは、このbuild_runnerあるtodo_reporter.dartというペット・プロジェクトで動作します。

これは、コード生成を使用するすべてのプロジェクトで見られる不文律です。アノテーション用のパッケージとジェネレータ用の別のパッケージを作成し、それらに値を追加します。Dart/Flutterでライブラリパッケージを作成するために必要な情報は、このリンクあります。

ルートフォルダの接尾辞を.dartにしているのは、わかりやすくするためです。これは必須ではありませんが、このパッケージがどのDartプロジェクトでも使えることを明確にするためです。逆に、ozzie.flutterようにFlutter専用のパッケージにしたい場合は、別のサフィックスを使います。これは強制ではなく、私が好きな命名規則です。

todo_reporterを作成する注釈付きパッケージは、最も単純なものでもあります。

name: todo_reporter
description: Keep track of all your TODOs.
version: 1.0.0
author: Jorge Coca <jcocaramos@gmail.com>
homepage: https://.//_.rt 
environment: 
 sdk: ">=2.0.0 <3.0.0" 
dependencies: 
dev_dependencies: 
 test: 1.3.4

開発目的にのみ使用されるテストパッケージ以外には、実際の依存関係はありません。

libフォルダーでは、次のようにします。

  • import "package:todo_reporter/todo_reporter.dart"todo_reporter.dartが作成され、パッケージのパブリックAPIを公開するためにexportを使用するすべてのクラスがそこに登録されます。 これは、パッケージ内の任意のパブリッククラスが.NET経由でインポートできるので、良いプラクティスです。このクラスがどのようなものか、ここで見ることができます:github.com/t....

  • libフォルダの中にsrcフォルダを作成し、公開・非公開を問わずすべてのコードを格納します。

サンプルに含める必要があるのはコメントだけです。これらを入れたtodo.dartファイルを作りましょう。

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

さて、必要なメモは以上です。簡単だって言ったでしょ?さて、まだ終わりではありません。テストパッケージにユニットテストを追加しましょう。

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://.om';
 final todo = Todo('name', todoUrl: givenUrl);
 expect(todo.todoUrl, givenUrl);
 });
 });
}

これだけでアノテーションを作成することができます。コードはこのリンクあります。

それではコード生成に取り掛かりましょう。

Todo_reporter_generator。

todo_reporter_generatorパッケージの作成方法がわかったところで、.NET というパッケージを作成してみましょう。todo_reporter_generator.dartその中に pubspec.yaml、build.yaml ファイル、lib フォルダがあり、lib フォルダの中に src フォルダと export ステートメントを含むファイルがあります。これは、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://.//_.rt 
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を完成させましょう。このファイルにはBuildersに必要な設定が含まれています。詳細はこちらを参照してください:github.com/b...

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_factories エントリはコードをビルドするメソッドを指します。todo_reporter_generator.dartlibにbuilder.dartファイルを作成し、srcに以下の内容のファイルを追加します。

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

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

todo_reporter_generator.dart

TodoReporterGeneratorご覧のように、builder.dart には、Builder を作成する todoReporter メソッドがあります。この Builder は、.NET ファイルを受け取る SharedPartBuilder を使用して提供されます。このように、build_runner と source_gen は連携して動作します。

TodoReporterGeneratorGeneratorForAnnotationgenerateForAnnotatedElementつまり、Todoの場合、与えられたコメントでコメントされたコード片を見つけたときのみ実行されます。

generateForAnnotatedElement生成されたコードがコンパイルされない場合、ビルドフェーズは失敗します

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/ これらのファイルをプロジェクトで使用すると、コードを自動生成しようとするたびに、. コメントの扱い方については、次の投稿で説明します。

すべてのピースをまとめる:使用中のtodo_reporter

todo_repoter.dartを使い始めるための最後のピースは、プロジェクト上でその機能を実証することです。他の開発者が実際のプロジェクトでAPIがどのように使われているかを見ることができます。

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/

さて、パッケージを取得した後、使用されるアノテーション。

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のコードに含まれるすべてのTodoコメントに対して、有効なDartファイルを生成できるようになりました。コードに含まれるすべての Todo コメントに対して有効な Dart ファイルを生成できるようになりました。お好きなだけコメントを作成してください。

次の記事では...

ファイルを生成するための正しいセットアップができたので、次の記事では、生成されたコードが実際に何かクールなことをできるようにするコメントを利用する方法を学びます

www.DeepL.com/Translator翻译 経由

Read next

クローム音声自動再生問題

テストした結果、やはり音声はうまくいきません。iframe内の音声は、自動再生や呼び出し再生方式を設定しても、トップページで直接対応する設定や操作と同じ現象になります。 video要素はミュートしていれば自動再生できますが、chrome公式によると、その後の実装で保証されない可能性があるとのことです。そのため、v...

Jan 6, 2021 · 2 min read