platform/packages/macroable/README.md

129 lines
3.1 KiB
Markdown

# Platform Macroable
A Dart implementation of Laravel's Macroable trait, allowing runtime method extension of classes.
## Features
- Add methods to classes at runtime through macros
- Mix in methods from other objects
- Support for both positional and named parameters
- Type-safe macro registration and usage
- Easy method existence checking
- Ability to clear registered macros
## Usage
```dart
import 'package:platform_macroable/platform_macroable.dart';
// 1. Add the Macroable mixin to your class
class StringFormatter with Macroable {
String capitalize(String input) =>
input.isEmpty ? '' : input[0].toUpperCase() + input.substring(1);
}
void main() {
final formatter = StringFormatter();
// 2. Register a macro with positional parameters
Macroable.macro<StringFormatter>('repeat', (String text, int times) {
return text * times;
});
// 3. Register a macro with named parameters
Macroable.macro<StringFormatter>(
'wrap',
({required String text, String start = '[', String end = ']'}) {
return '$start$text$end';
},
);
// 4. Use the macros (requires dynamic casting)
print(formatter.capitalize('hello')); // Built-in method
print((formatter as dynamic).repeat('ha ', 3)); // Prints: ha ha ha
print((formatter as dynamic).wrap(text: 'hello')); // Prints: [hello]
// 5. Mix in methods from another class
class TextTransformations {
String reverse(String text) => text.split('').reversed.join();
}
Macroable.mixin<StringFormatter>(TextTransformations());
print((formatter as dynamic).reverse('hello')); // Prints: olleh
// 6. Check if a macro exists
print(Macroable.hasMacro<StringFormatter>('reverse')); // Prints: true
// 7. Clear all macros
Macroable.flushMacros<StringFormatter>();
}
```
## Features in Detail
### Basic Macro Registration
Register methods that can be called on instances of your class:
```dart
Macroable.macro<YourClass>('methodName', (String arg) {
return arg.toUpperCase();
});
```
### Named Parameters
Support for methods with named parameters:
```dart
Macroable.macro<YourClass>(
'format',
({required String text, String prefix = '>> '}) {
return '$prefix$text';
},
);
```
### Method Mixing
Add all public methods from another object:
```dart
class Helper {
String process(String input) => input.trim();
int calculate(int x, int y) => x + y;
}
Macroable.mixin<YourClass>(Helper());
```
### Utility Methods
Check for macro existence and clear macros:
```dart
// Check if a macro exists
bool exists = Macroable.hasMacro<YourClass>('methodName');
// Remove all macros
Macroable.flushMacros<YourClass>();
```
## Important Notes
1. Macro calls require dynamic casting since they're resolved at runtime:
```dart
(instance as dynamic).macroMethod()
```
2. Macros are registered per-type, not per-instance:
```dart
// All instances of YourClass will have access to this macro
Macroable.macro<YourClass>('method', () => 'result');
```
3. Type safety is maintained at registration time through generics.
## Example
See the [example](example/platform_macroable_example.dart) for a complete demonstration of all features.