decorator_gen 0.5.0
decorator_gen: ^0.5.0 copied to clipboard
Automatically generates code for the decorator pattern in Dart by annotating classes.
Decorator Gen #
A Dart code generator that automatically creates the decorator pattern for your Dart code.
The builder generates code if it finds classes with annotations from the decorator_annotation package.
Features #
- Generate complete decorator classes with a single
@Decorator()
annotation- Forward all public members of the source class
- Works with generics, records, nested types, etc.
- Object methods can be forwarded globally or per class
Installation #
Add the following to your pubspec.yaml
:
dependencies:
decorator_annotation: ^latest
dev_dependencies:
decorator_gen: ^latest
build_runner: any
Usage #
1. Annotate Your Class And Include The Part Directive #
import 'package:decorator_annotation/decorator_annotation.dart';
part 'example.g.dart'; // This part directive is necessary for code generation
@Decorator() // Add this annotation to generate a decorator for this class
class MyService {
final String name;
MyService(this.name);
String greet(String message) => 'Hello $message from $name';
Future<String> asyncOperation() async {
await Future.delayed(const Duration(seconds: 1));
return 'Completed';
}
}
// Generates: MyServiceDecorator in example.g.dart
class MyServiceDecorator implements MyService {
final MyService myService;
MyServiceDecorator({required this.myService});
@override
String greet(String message) {
return myService.greet(message);
}
@override
Future<String> asyncOperation() {
return myService.asyncOperation();
}
@override
String get name => myService.name;
}
2. Run Code Generation #
dart run build_runner build
3. Use Your Generated Decorator #
// Generated: MyServiceDecorator
class LoggingServiceDecorator extends MyServiceDecorator {
LoggingServiceDecorator({required super.myService});
@override
String greet(String message) {
print('Calling greet with: $message');
final result = super.greet(message);
print('greet returned: $result');
return result;
}
@override
Future<String> asyncOperation() async {
print('Starting async operation');
final result = await super.asyncOperation();
print('Async operation completed');
return result;
}
}
// Usage
final service = MyService('TestService');
final decorator = LoggingServiceDecorator(myService: service);
print(decorator.greet('World')); // Logs and returns result
Supported Features #
Generics (with Bounds) #
@Decorator()
class GenericService<T extends Comparable<T>> {
T process(T value) => /* implementation */
}
// Generates: GenericServiceDecorator<T extends Comparable<T>>
Mixins #
mixin SimpleMixin {
void mixinMethod() => /* implementation */
}
@Decorator()
class MixinService with SimpleMixin {
void ownMethod() => /* implementation */
}
// Generates: MixinServiceDecorator having mixinMethod and ownMethod
Object methods and Annotation-level Forwarding #
You can control which Object methods are forwarded per class using parameters on the @Decorator()
annotation:
@Decorator(
forwardToString: true, // forward toString (default: true)
forwardEquals: false, // do NOT forward == (default: true)
forwardHashCode: true, // forward hashCode (default: true)
forwardRuntimeType: true, // forward runtimeType (default: false)
forwardNoSuchMethod: false, // do NOT forward noSuchMethod (default: false)
)
class CustomService {
final String name;
CustomService(this.name);
@override
String toString() => 'CustomService($name)';
@override
bool operator ==(Object other) => other is CustomService && other.name == name;
@override
int get hashCode => name.hashCode;
@override
Type get runtimeType => super.runtimeType;
@override
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
String processData(String data) => 'Processing: $data';
}
// Only toString, hashCode, and runtimeType will be forwarded in the generated decorator.
Operators #
@Decorator()
class OperatorService {
int operator +(int other) => /* implementation */
bool operator ==(Object other) => /* implementation */
int operator [](int index) => /* implementation */
}
// Generates: OperatorServiceDecorator with forwarded operators
Parameters (positional, named, optional, combined) #
@Decorator()
class ParameterService {
void positionalNamed(int a, {String? b, double c = 0.0}) => /* implementation */
void positionalOptional(int a, [String? b, double c = 0.0]) => /* implementation */
}
// Generates: ParameterServiceDecorator with all parameter types handled
Records #
@Decorator()
class RecordService {
(int, String) getTuple() => (42, 'Hello World!');
// With named fields
void setRecord(({int foo, String bar}) record) => /* implementation */
}
// Generates: RecordServiceDecorator with tuple handling
Forwarding Object Methods: Global Defaults #
The generator can generate code that forwards the Object methods.
The following Object methods are included by default:
toString
==
hashCode
The following Object methods are excluded by default:
runtimeType
noSuchMethod
You can customize the global default behavior in your build.yaml
file:
targets:
$default:
builders:
decorator_gen:
enabled: true
options:
forward_object_method:
toString: true # Defaults to true
"==": true # Defaults to true
hashCode: true # Defaults to true
runtimeType: false # Defaults to false
noSuchMethod: false # Defaults to false
FAQ #
Private members #
Private members (those starting with _
) are included in the generated decorators.
This is required by the Dart compiler. All accessible members must be implemented.
Static members #
Static members are not included in the generated decorators.
Contributing #
Contributions are welcome! Please feel free to submit a Pull Request.
License #
This project is licensed under the MIT License.