From 932f83f0f8cd928abc5d43a77d7357f30423f9fa Mon Sep 17 00:00:00 2001 From: Patrick Stewart Date: Fri, 27 Dec 2024 10:43:05 -0700 Subject: [PATCH] refactor: removing wrap() as it is not idiomatic dart all test pass --- .../container/lib/src/container.dart | 69 +--- .../container/container/test/wrap_test.dart | 306 ------------------ 2 files changed, 2 insertions(+), 373 deletions(-) delete mode 100644 incubation/container/container/test/wrap_test.dart diff --git a/incubation/container/container/lib/src/container.dart b/incubation/container/container/lib/src/container.dart index 988e461..f7e1782 100644 --- a/incubation/container/container/lib/src/container.dart +++ b/incubation/container/container/lib/src/container.dart @@ -13,6 +13,8 @@ import 'exception.dart'; import 'reflector.dart'; import 'contextual_binding_builder.dart'; +var currentPos = 0; + class Container { /// The [Reflector] instance used by this container for reflection-based operations. /// @@ -1157,73 +1159,6 @@ class Container { bind(abstract).to(concrete); } - /// Wrap a closure with dependency injection - /// - /// This allows you to wrap a closure so its dependencies will be injected when executed. - /// The wrapped closure will receive injected dependencies first, followed by any - /// additional parameters passed to the wrapper. - /// - /// ```dart - /// var wrapped = container.wrap((Logger logger, String message) { - /// logger.log(message); - /// }); - /// wrapped('Hello world'); // Logger will be injected automatically - /// ``` - Function wrap(T callback) { - return ([dynamic arg1]) { - // Get the function's parameter types through reflection - var reflectedFunction = reflector.reflectFunction(callback); - if (reflectedFunction == null) { - throw BindingResolutionException( - 'Could not reflect function parameters for dependency injection'); - } - - // Resolve dependencies for each parameter - var resolvedArgs = []; - var namedArgs = {}; - - // First resolve all container-injectable parameters - var injectedTypes = {}; - for (var param in reflectedFunction.parameters) { - var paramType = param.type.reflectedType; - if (has(paramType)) { - if (param.isNamed) { - namedArgs[Symbol(param.name)] = make(paramType); - } else { - resolvedArgs.add(make(paramType)); - } - injectedTypes.add(paramType); - } - } - - // Then add any provided arguments for remaining parameters - var providedArgs = []; - if (arg1 != null) providedArgs.add(arg1); - - // Process remaining parameters in order - var paramIndex = 0; - var providedIndex = 0; - for (var param in reflectedFunction.parameters) { - if (param.isNamed) continue; - if (injectedTypes.contains(param.type.reflectedType)) { - paramIndex++; - continue; - } - - if (providedIndex < providedArgs.length) { - resolvedArgs.add(providedArgs[providedIndex++]); - } else if (param.isRequired) { - throw BindingResolutionException( - 'No value provided for required parameter ${param.name} of type ${param.type.reflectedType}'); - } - paramIndex++; - } - - // Call the function with resolved arguments - return Function.apply(callback, resolvedArgs, namedArgs); - }; - } - /// Register a binding if it hasn't already been registered void bindIf(dynamic concrete, {bool singleton = false}) { if (!has()) { diff --git a/incubation/container/container/test/wrap_test.dart b/incubation/container/container/test/wrap_test.dart deleted file mode 100644 index 63201fa..0000000 --- a/incubation/container/container/test/wrap_test.dart +++ /dev/null @@ -1,306 +0,0 @@ -import 'package:platformed_container/container.dart'; -import 'package:test/test.dart'; - -abstract class Logger { - void log(String message); -} - -class ConsoleLogger implements Logger { - @override - void log(String message) => print('Console: $message'); -} - -void main() { - late Container container; - - setUp(() { - container = Container(MockReflector()); - }); - - group('Wrap Tests', () { - test('wrap injects dependencies into closure', () { - container.bind(Logger).to(ConsoleLogger); - var messages = []; - - var wrapped = container.wrap((Logger logger, String message) { - messages.add(message); - }); - - wrapped('Hello world'); // Pass message directly - expect(messages, contains('Hello world')); - }); - - test('wrap preserves provided arguments', () { - container.bind(Logger).to(ConsoleLogger); - var messages = []; - - var wrapped = container.wrap((Logger logger, String message) { - messages.add(message); - }); - - wrapped('Custom message'); // Pass message directly - expect(messages, contains('Custom message')); - }); - - test('wrap throws when required dependency is missing', () { - var wrapped = container.wrap((Logger logger) {}); - - expect(() => wrapped(), throwsA(isA())); - }); - - test('wrap works with optional parameters', () { - container.bind(Logger).to(ConsoleLogger); - var messages = []; - - var wrapped = container.wrap((Logger logger, [String? message]) { - messages.add(message ?? 'default'); - }); - - wrapped(); // No arguments needed - expect(messages, contains('default')); - }); - - test('wrap works with named parameters', () { - container.bind(Logger).to(ConsoleLogger); - var messages = []; - - var wrapped = - container.wrap((Logger logger, {String message = 'default'}) { - messages.add(message); - }); - - wrapped(); // No arguments needed - expect(messages, contains('default')); - }); - }); -} - -class MockReflector extends Reflector { - @override - String? getName(Symbol symbol) => null; - - @override - ReflectedClass? reflectClass(Type clazz) { - if (clazz == ConsoleLogger) { - return MockReflectedClass( - 'ConsoleLogger', [], [], [MockConstructor('', [])], ConsoleLogger); - } - return null; - } - - @override - ReflectedType? reflectType(Type type) { - return reflectClass(type); - } - - @override - ReflectedInstance? reflectInstance(Object? instance) => null; - - @override - ReflectedFunction? reflectFunction(Function function) { - // Create mock parameters based on the function's runtime type - var parameters = []; - - // First parameter is always Logger - parameters.add(MockParameter('logger', Logger, true, false)); - - // Add message parameter based on function signature - if (function.toString().contains('String message')) { - parameters.add(MockParameter('message', String, true, false)); - } else if (function.toString().contains('String? message')) { - parameters.add(MockParameter('message', String, false, false)); - } else if (function.toString().contains('{String message')) { - parameters.add(MockParameter('message', String, false, true)); - } - - return MockFunction('', parameters); - } - - @override - ReflectedType reflectFutureOf(Type type) => throw UnimplementedError(); - - @override - Type? findTypeByName(String name) => null; - - @override - ReflectedFunction? findInstanceMethod(Object instance, String methodName) => - null; - - @override - List getAnnotations(Type type) => []; - - @override - List getParameterAnnotations( - Type type, String constructorName, String parameterName) => - []; -} - -class MockConstructor implements ReflectedFunction { - final String constructorName; - final List constructorParameters; - - MockConstructor(this.constructorName, this.constructorParameters); - - @override - List get annotations => []; - - @override - bool get isGetter => false; - - @override - bool get isSetter => false; - - @override - String get name => constructorName; - - @override - List get parameters => constructorParameters; - - @override - ReflectedType? get returnType => null; - - @override - List get typeParameters => []; - - @override - ReflectedInstance invoke(Invocation invocation) => throw UnimplementedError(); -} - -class MockReflectedClass extends ReflectedType implements ReflectedClass { - @override - final List annotations; - @override - final List constructors; - @override - final List declarations; - - MockReflectedClass( - String name, - List typeParameters, - this.annotations, - this.constructors, - Type reflectedType, - ) : declarations = [], - super(reflectedType.toString(), typeParameters, reflectedType); - - @override - ReflectedInstance newInstance( - String constructorName, List positionalArguments, - [Map namedArguments = const {}, - List typeArguments = const []]) { - if (reflectedType == ConsoleLogger) { - return MockReflectedInstance(ConsoleLogger()); - } - throw UnsupportedError('Unknown type: $reflectedType'); - } - - @override - bool isAssignableTo(ReflectedType? other) { - if (reflectedType == other?.reflectedType) { - return true; - } - if (reflectedType == ConsoleLogger && other?.reflectedType == Logger) { - return true; - } - return false; - } -} - -class MockFunction implements ReflectedFunction { - final String functionName; - final List functionParameters; - - MockFunction(this.functionName, this.functionParameters); - - @override - List get annotations => []; - - @override - bool get isGetter => false; - - @override - bool get isSetter => false; - - @override - String get name => functionName; - - @override - List get parameters => functionParameters; - - @override - ReflectedType? get returnType => null; - - @override - List get typeParameters => []; - - @override - ReflectedInstance invoke(Invocation invocation) => throw UnimplementedError(); -} - -class MockParameter implements ReflectedParameter { - @override - final String name; - @override - final bool isRequired; - @override - final bool isNamed; - final Type paramType; - final bool isVariadic; - - MockParameter(this.name, this.paramType, this.isRequired, this.isNamed, - {this.isVariadic = false}); - - @override - List get annotations => []; - - @override - ReflectedType get type => MockReflectedType(paramType); -} - -class MockReflectedType implements ReflectedType { - @override - final String name; - @override - final Type reflectedType; - - MockReflectedType(this.reflectedType) : name = reflectedType.toString(); - - @override - List get typeParameters => []; - - @override - bool isAssignableTo(ReflectedType? other) { - if (reflectedType == other?.reflectedType) { - return true; - } - if (reflectedType == ConsoleLogger && other?.reflectedType == Logger) { - return true; - } - return false; - } - - @override - ReflectedInstance newInstance( - String constructorName, List positionalArguments, - [Map namedArguments = const {}, - List typeArguments = const []]) => - throw UnimplementedError(); -} - -class MockReflectedInstance implements ReflectedInstance { - final dynamic value; - - MockReflectedInstance(this.value); - - @override - ReflectedClass get clazz => throw UnimplementedError(); - - @override - ReflectedInstance getField(String name) => throw UnimplementedError(); - - @override - dynamic get reflectee => value; - - @override - ReflectedType get type => throw UnimplementedError(); -}