2024-12-15 23:26:30 +00:00
|
|
|
# Platform Macroable
|
|
|
|
|
2024-12-16 01:34:28 +00:00
|
|
|
A Dart implementation of Laravel's Macroable trait, allowing runtime method extension of classes.
|
2024-12-15 23:26:30 +00:00
|
|
|
|
|
|
|
## Features
|
|
|
|
|
2024-12-16 01:34:28 +00:00
|
|
|
- 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
|
2024-12-15 23:26:30 +00:00
|
|
|
|
2024-12-16 01:34:28 +00:00
|
|
|
## Usage
|
|
|
|
|
|
|
|
```dart
|
|
|
|
import 'package:platform_macroable/platform_macroable.dart';
|
2024-12-15 23:26:30 +00:00
|
|
|
|
2024-12-16 01:34:28 +00:00
|
|
|
// 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();
|
|
|
|
}
|
2024-12-15 23:26:30 +00:00
|
|
|
|
2024-12-16 01:34:28 +00:00
|
|
|
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>();
|
|
|
|
}
|
2024-12-15 23:26:30 +00:00
|
|
|
```
|
|
|
|
|
2024-12-16 01:34:28 +00:00
|
|
|
## Features in Detail
|
2024-12-15 23:26:30 +00:00
|
|
|
|
2024-12-16 01:34:28 +00:00
|
|
|
### Basic Macro Registration
|
2024-12-15 23:26:30 +00:00
|
|
|
|
2024-12-16 01:34:28 +00:00
|
|
|
Register methods that can be called on instances of your class:
|
2024-12-15 23:26:30 +00:00
|
|
|
|
|
|
|
```dart
|
2024-12-16 01:34:28 +00:00
|
|
|
Macroable.macro<YourClass>('methodName', (String arg) {
|
|
|
|
return arg.toUpperCase();
|
|
|
|
});
|
|
|
|
```
|
2024-12-15 23:26:30 +00:00
|
|
|
|
2024-12-16 01:34:28 +00:00
|
|
|
### Named Parameters
|
2024-12-15 23:26:30 +00:00
|
|
|
|
2024-12-16 01:34:28 +00:00
|
|
|
Support for methods with named parameters:
|
2024-12-15 23:26:30 +00:00
|
|
|
|
2024-12-16 01:34:28 +00:00
|
|
|
```dart
|
|
|
|
Macroable.macro<YourClass>(
|
|
|
|
'format',
|
|
|
|
({required String text, String prefix = '>> '}) {
|
|
|
|
return '$prefix$text';
|
|
|
|
},
|
|
|
|
);
|
|
|
|
```
|
2024-12-15 23:26:30 +00:00
|
|
|
|
2024-12-16 01:34:28 +00:00
|
|
|
### Method Mixing
|
2024-12-15 23:26:30 +00:00
|
|
|
|
2024-12-16 01:34:28 +00:00
|
|
|
Add all public methods from another object:
|
2024-12-15 23:26:30 +00:00
|
|
|
|
2024-12-16 01:34:28 +00:00
|
|
|
```dart
|
|
|
|
class Helper {
|
|
|
|
String process(String input) => input.trim();
|
|
|
|
int calculate(int x, int y) => x + y;
|
|
|
|
}
|
2024-12-15 23:26:30 +00:00
|
|
|
|
2024-12-16 01:34:28 +00:00
|
|
|
Macroable.mixin<YourClass>(Helper());
|
|
|
|
```
|
2024-12-15 23:26:30 +00:00
|
|
|
|
2024-12-16 01:34:28 +00:00
|
|
|
### Utility Methods
|
2024-12-15 23:26:30 +00:00
|
|
|
|
2024-12-16 01:34:28 +00:00
|
|
|
Check for macro existence and clear macros:
|
2024-12-15 23:26:30 +00:00
|
|
|
|
2024-12-16 01:34:28 +00:00
|
|
|
```dart
|
|
|
|
// Check if a macro exists
|
|
|
|
bool exists = Macroable.hasMacro<YourClass>('methodName');
|
2024-12-15 23:26:30 +00:00
|
|
|
|
2024-12-16 01:34:28 +00:00
|
|
|
// Remove all macros
|
|
|
|
Macroable.flushMacros<YourClass>();
|
2024-12-15 23:26:30 +00:00
|
|
|
```
|
|
|
|
|
2024-12-16 01:34:28 +00:00
|
|
|
## 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');
|
|
|
|
```
|
2024-12-15 23:26:30 +00:00
|
|
|
|
2024-12-16 01:34:28 +00:00
|
|
|
3. Type safety is maintained at registration time through generics.
|
2024-12-15 23:26:30 +00:00
|
|
|
|
2024-12-16 01:34:28 +00:00
|
|
|
## Example
|
2024-12-15 23:26:30 +00:00
|
|
|
|
2024-12-16 01:34:28 +00:00
|
|
|
See the [example](example/platform_macroable_example.dart) for a complete demonstration of all features.
|