zengen 0.3.0 zengen: ^0.3.0 copied to clipboard
A package to generate boilerplate code.
ZenGen #
This project provides a source_gen generator to generate boilerplate code.
This library is inspired from the project Lombok in the Java world.
Features #
@ToString() #
Annotating a class with @ToString()
will generate an implementation of String toString()
built by default with its public getters.
For instance :
@ToString()
class _A {
final a;
final int b;
_A(this.a, this.b);
}
will generate :
@GeneratedFrom(_A)
class A {
final a;
final int b;
A(this.a, this.b);
@override String toString() => "A(a=$a, b=$b)";
}
The code generated can be customized with the following optional parameters:
callSuper
: if set totrue
the result oftoString
will contains the result ofsuper.toString()
.exclude
: a list of getter names can be exclude with this argument.includePrivate
: if set totrue
the generation will include private getters.
@EqualsAndHashCode() #
Annotating a class with @EqualsAndHashCode()
will generate an implementation of bool operator ==(o)
and int get hashCode
built by default with its public getters.
For instance :
@EqualsAndHashCode()
class _A {
final a;
final int b;
_A(this.a, this.b);
}
will generate :
@GeneratedFrom(_A)
class A {
final a;
final int b;
A(this.a, this.b);
@override bool operator ==(o) => identical(this, o) ||
o.runtimeType == runtimeType && o.a == a && o.b == b;
@override int get hashCode => hashObjects([a, b]);
}
The code generated can be customize with the following optional parameters:
callSuper
: if set totrue
the generated code will use additionnallysuper.hashCode
andsuper == o
.exclude
: a list of getter names can be exclude with this argument.includePrivate
: if set totrue
the generation will include private getters.
@DefaultConstructor() #
Annotating an external constructor with @DefaultConstructor()
will generate a default constructor with uninitialized final fields as required parameters and mutable fields as optional named parameters.
You can use the useConst
parameter to generate a const constructor.
For instance :
class _A {
var a;
final b;
@DefaultConstructor() external _A();
}
will generate :
@GeneratedFrom(_A)
class A {
var a;
final b;
A(this.b, {this.a});
}
The external _A();
is used to make the analyzer happy and will be removed in the generated A
.
@Value() #
Annotating a class with @Value()
is the same as annotating the class with @DefaultConstructor()
, @EqualsAndHashCode()
and @ToString()
.
For instance :
@Value()
class _A {
final int a;
final b, c;
external _A();
}
will generate :
@GeneratedFrom(_A)
class A {
final int a;
final b, c;
A(this.a, this.b, this.c);
@override bool operator ==(o) => identical(this, o) ||
o.runtimeType == runtimeType && o.a == a && o.b == b && o.c == c;
@override int get hashCode => hashObjects([a, b, c]);
@override String toString() => "A(a=$a, b=$b, c=$c)";
}
Note that you can customize @EqualsAndHashCode()
and @ToString()
by using the annotation with the custom parameters.
You can use the useConst
parameter to generate a const constructor.
@Delegate() #
Annotating a field/getter with @Delegate()
will add to the enclosing class all the public methods available on the type of the field/getter.
For instance :
abstract class A {
m1();
}
class _B {
@Delegate() A _a;
}
will generate :
@GeneratedFrom(_B)
class B {
@Delegate() A _a;
m1() => _a.m1();
}
The code generated can be customize with the following optional parameters:
exclude
: a list of members can be exclude with this argument.
@Lazy() #
Annotating a field with @Lazy()
will make it lazy computed.
For instance :
class _A {
@Lazy() var a = "String";
}
will generate :
@GeneratedFrom(_A)
class A {
dynamic get a => _lazyFields.putIfAbsent(#a, () => "String");
set a(dynamic v) => _lazyFields[#a] = v;
final _lazyFields = <Symbol, dynamic>{};
}
The lazy fields are stored into _lazyFields
by field names. If the field is final no setter will be generated.
@Cached() #
Annotating a method with @Cached()
will make its result managed by a cache. By default the cache used is a forever cache that will compute the result once and keep it forever in memory.
For instance :
class _A {
@Cached() int fib(int n) => (n < 2) ? n : fib(n - 1) + fib(n - 2);
}
will generate :
@GeneratedFrom(_A)
class A {
int fib(int n) => _caches
.putIfAbsent(
#fib,
() => _createCache(
#fib, (int n) => (n < 2) ? n : fib(n - 1) + fib(n - 2)))
.getValue([n]);
final _caches = <Symbol, Cache>{};
Cache _createCache(Symbol methodName, Function compute) => new Cache(compute);
}
The caches for each method are stored into _caches
. You can implement your own Cache _createCache(Symbol methodName, Function compute)
to customize the cache policy.
@Implementation() #
Annotating a method with @Implementation()
will make it the method called by all abstract members.
The method annotated must have exactly one parameter of type StringInvocation
.
This type is the same as Invocation
from dart:core except that the Symbol
are replaced by String
.
This allows to avoid dart:mirrors.
For instance :
abstract class _A {
m1();
String get g;
void set s(String s);
@Implementation() _noSuchMethod(i) => print(i);
}
will generate :
@GeneratedFrom(_A)
class A {
m1() => _noSuchMethod(new StringInvocation('m1', isMethod: true));
String get g => _noSuchMethod(new StringInvocation('g', isGetter: true));
void set s(String s) {
_noSuchMethod(
new StringInvocation('s', isSetter: true, positionalArguments: [s]));
}
_noSuchMethod(i) => print(i);
}
Usage #
To use this library in your code :
- add a dependency in your
pubspec.yaml
:
dependencies:
zengen: any
- add import in your
dart
code :
import 'package:zengen/zengen.dart';
- create a script
build.dart
that run the generator
import 'package:zengen/generator.dart';
import 'package:source_gen/source_gen.dart' show build;
main(List<String> args) async {
print(await build(args, [new ZengenGenerator()],
librarySearchPaths: ['example/', 'lib/', 'web/', 'test/']));
}
You can use the build_system package to allow the generator to be run on every file changes.
License #
Apache 2.0