platform/packages/macroable
2024-12-21 09:53:25 -07:00
..
doc add: adding laravel style collections, macroable, support packages 2024-12-15 18:34:28 -07:00
example add: adding laravel style collections, macroable, support packages 2024-12-15 18:34:28 -07:00
lib refactor: refactoring reflection system pass 43 fail 1 2024-12-21 09:53:25 -07:00
test refactor: refactoring reflection system pass 43 fail 1 2024-12-21 09:53:25 -07:00
.gitignore add: adding macroable package 2024-12-15 16:26:30 -07:00
analysis_options.yaml add: adding macroable package 2024-12-15 16:26:30 -07:00
CHANGELOG.md add: adding macroable package 2024-12-15 16:26:30 -07:00
LICENSE.md add: adding macroable package 2024-12-15 16:26:30 -07:00
pubspec.yaml add: adding laravel style collections, macroable, support packages 2024-12-15 18:34:28 -07:00
README.md add: adding laravel style collections, macroable, support packages 2024-12-15 18:34:28 -07:00

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

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:

Macroable.macro<YourClass>('methodName', (String arg) {
  return arg.toUpperCase();
});

Named Parameters

Support for methods with named parameters:

Macroable.macro<YourClass>(
  'format',
  ({required String text, String prefix = '>> '}) {
    return '$prefix$text';
  },
);

Method Mixing

Add all public methods from another object:

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:

// 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:

    (instance as dynamic).macroMethod()
    
  2. Macros are registered per-type, not per-instance:

    // 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 for a complete demonstration of all features.