ixtrator is a straightforward tool for Dart developers. It takes your Dart classes and helps you generate clear abstract classes from them. This makes your code easier to understand and work with. It's a simple, no-fuss solution to a common problem.
Explore the docs »
Report Bug
·
Request Feature
Table of Contents
ixtrator is a simple package that simplifies extracting abstract classes in Dart projects. With its automated class structure generation, it generates the abstractions while only focusing on implementation, improving code organization, readability, and maintainability, making it an invaluable tool for Dart developers.
This project is distributed under the MIT License. See LICENSE.txt
for more information.
a) Add your_package as a dependency in your Pubspec.yaml:
dependencies:
ixtrator: ^1.0.0
b) Create a build.yaml file in the root of your project with the following configuration:
targets:
$default:
builders:
ixtrator|ixtratorBuilder:
enabled: true
c) In your Dart class, apply the @GenerateClassStructure() decorator. For example:
@GenerateClassStructure()
class MyClass implements IMyClass {
Stream<String> myMethod(int param1, {String param2 = 'default'}) {
return Stream.empty();
}
// ... Other methods
}
d): Generate Abstract Classes Run the following command to generate the abstract class structures:
dart run build_runner build
ixtrator will generate the corresponding abstract class structure based on your class methods. Look for the generated .g.dart files in your project directory.
d): In the generated .g.dart files, you'll find the method signatures along with the result class. Copy the abstract class structure and apply it to your original class with the @override annotation. Also, implement the result class:
abstract class IMyClass {
Stream<String> myMethod(int param1, {String param2 = 'default'});
Future<void> myM34(dynamic param1, {required dynamic param2});
List<DateTime> dates();
void simpleVoid();
}
class MyClass implements IMyClass {
@override
Stream<String> myMethod(int param1, {String param2 = 'default'}) {
return Stream.empty();
}
@override
Future<void> myM34(dynamic param1, {required dynamic param2}) async {}
@override
List<DateTime> dates() {
return [];
}
@override
void simpleVoid() {}
}
1): First, you apply the @GenerateClassStructure() annotation to your class. ixtrator will generate the abstract class structure with method signatures.
In the same directory as your Dart file, create a file with a .g.dart extension. This is where the generated code will be placed. For example, if your Dart file is named example.dart, your generated file could be named example.g.dart.
In your Dart file, use the part directive to specify the generated part file:
import 'package:ixtrator/ixtrator.dart';
part 'example.g.dart';
@GenerateClassStructure()
class MyClass implements IMyClass {
@override
Stream<String> myMethod(int param1, {String param2 = 'default'}) {
return Stream.empty();
}
@override
Future<void> myM34(param1, {required param2}) async {}
@override
List<DateTime> dates() {
return [];
}
@override
void simpleVoid() {}
}
- ✅ Automatic Abstract Class Generation: Ixtrator automates the process of creating abstract classes based on your concrete classes.
- ✅ Simplified Code Maintenance: With generated abstract classes, your codebase becomes more organized and easier to maintain.
- ✅ Enhanced Code Structure: It promotes adherence to best practices and clean code principles by separating interfaces from implementations.
- ✅ Annotations: It utilizes the @GenerateClassStructure annotation to identify which classes need abstract counterparts.
- ✅ Minimal Configuration: Ixtrator requires minimal configuration, making it easy to integrate into your Dart projects.
Right now this package has concluded all his intended features. If you have any suggestions or find something to report, see below how to contribute to it.
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.
If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the appropriate tag. Don't forget to give the project a star! Thanks again!
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature
) - Commit your Changes (
git commit -m 'Add some AmazingFeature'
) - Push to the Branch (
git push origin feature/AmazingFeature
) - Open a Pull Request
Remember to include a tag, and to follow Conventional Commits and Semantic Versioning when uploading your commit and/or creating the issue.
More example:
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'example_usage.dart';
// **************************************************************************
// IxtratorGenerator
// **************************************************************************
abstract class IExampleClass<T> {
Future<int> multiply(int a, int b);
Stream<int> countNumbers(int start, int end);
void greet({required String name});
void sayHello();
Future<String> fetchMessage();
Stream<String> generateMessages();
Future<int> add(int a, int b);
Future<int> subtract(int a, int b);
Future<void> performOperations();
Future<void> processUserData({required String username, required int age});
Future<void> printNumbersInRange(int start, int end);
Stream<int> generateNumbersInRange(int start, int end);
Future<List<String>> processItems<T>(List<T> items, {String separator = ','});
Stream<List<int>> generateRandomLists<T>(List<T> items);
Future<Person> createPerson(String name, int age);
Stream<Person> generatePeople();
}
part 'example_usage.g.dart';
@GenerateClassStructure()
class ExampleClass implements IExampleClass{
// Method 1: Future with return and arguments
Future<int> multiply(int a, int b) async {
await Future.delayed(Duration(seconds: 1));
return a * b;
}
// Method 2: Stream with return and arguments
Stream<int> countNumbers(int start, int end) async* {
for (int i = start; i <= end; i++) {
await Future.delayed(Duration(milliseconds: 500));
yield i;
}
}
// Method 3: Void with required arguments
void greet({required String name}) {
print('Hello, $name!');
}
// Method 4: Void without arguments
void sayHello() {
print('Hello, world!');
}
// Method 5: Future with return and no arguments
Future<String> fetchMessage() async {
await Future.delayed(Duration(seconds: 2));
return 'Hello from the future!';
}
// Method 6: Stream with return and no arguments
Stream<String> generateMessages() async* {
for (int i = 0; i < 5; i++) {
await Future.delayed(Duration(seconds: 1));
yield 'Message $i';
}
}
// Method 7: Chaining Future methods
Future<int> add(int a, int b) async {
await Future.delayed(Duration(seconds: 1));
return a + b;
}
Future<int> subtract(int a, int b) async {
await Future.delayed(Duration(seconds: 1));
return a - b;
}
Future<void> performOperations() async {
final sum = await add(5, 3);
final difference = await subtract(10, 4);
print('Sum: $sum, Difference: $difference');
}
// Method 8: Asynchronous method with named arguments
Future<void> processUserData({required String username, required int age}) async {
await Future.delayed(Duration(seconds: 1));
print('Processing user data: $username, $age years old');
}
// Method 9: Future method with async* for a range
Future<void> printNumbersInRange(int start, int end) async {
for (int i = start; i <= end; i++) {
await Future.delayed(Duration(milliseconds: 500));
print(i);
}
}
// Method 10: Stream with async* for a range
Stream<int> generateNumbersInRange(int start, int end) async* {
for (int i = start; i <= end; i++) {
await Future.delayed(Duration(milliseconds: 500));
yield i;
}
}
// Method 11: Future with generic types and lists of objects as parameters and return
Future<List<String>> processItems<T>(List<T> items, {String separator = ','}) async {
await Future.delayed(Duration(seconds: 1));
final result = items.map((item) => item.toString()).join(separator);
return result.split(separator);
}
// Method 12: Stream with generic types and lists of objects as parameters and return
Stream<List<int>> generateRandomLists<T>(List<T> items) async* {
for (int i = 0; i < 5; i++) {
await Future.delayed(Duration(seconds: 1));
yield items.map((item) => i).toList();
}
}
// Method 13: Future with objects as parameters and return
Future<Person> createPerson(String name, int age) async {
await Future.delayed(Duration(seconds: 1));
return Person(name, age);
}
// Method 14: Stream with objects as parameters and return
Stream<Person> generatePeople() async* {
final people = [
Person('Alice', 30),
Person('Bob', 25),
Person('Carol', 35),
];
for (var person in people) {
await Future.delayed(Duration(seconds: 1));
yield person;
}
}
}
class Person {
final String name;
final int age;
Person(this.name, this.age);
}