Skip to content

Commit

Permalink
changeTypeInstanceName added
Browse files Browse the repository at this point in the history
  • Loading branch information
escamoteur committed Jun 25, 2024
1 parent f536845 commit 98b7d28
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
## [8.0.0-pre-5] - 25.06.2024 adding `changeTypeInstanceName`
## [8.0.0-pre-4] - 03.06.2024 fixing bug in `unregister` that happened if you tried to unregister a named registration by providing an istance instead of the type and the instance name
## [8.0.0-pre-3] - 31.05.2024 releaseInstance will now throw if the instance isn't registered
## [8.0.0-pre-2] - 29.05.2024 fixing negitiv reference count
Expand Down
18 changes: 18 additions & 0 deletions lib/get_it.dart
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,24 @@ abstract class GetIt {
/// is registered inside GetIt
bool isRegistered<T extends Object>({Object? instance, String? instanceName});

/// In some cases it can be necessary to change the name of a registered instance
/// This avoids to unregister and reregister the instance which might cause trouble
/// with disposing functions.
/// IMPORTANT: This will only change the the first instance that is found while
/// searching the scopes.
/// If the new name is already in use in the current scope it will throw a
/// StateError
/// [instanceName] the current name of the instance
/// [newInstanceName] the new name of the instance
/// [instance] the instance itself that can be used instead of
/// providing the type and the name. If [instance] is null the type and the name
/// have to be provided
void changeTypeInstanceName<T extends Object>({
String? instanceName,
required String newInstanceName,
T? instance,
});

/// Clears all registered types in the reverse order in which they were registered.
/// Handy when writing unit tests or when disposing services that depend on each other.
/// If you provided dispose function when registering they will be called
Expand Down
51 changes: 50 additions & 1 deletion lib/get_it_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class _ServiceFactory<T extends Object, P1, P2> {
final DisposingFunc<T>? disposeFunction;

/// In case of a named registration the instance name is here stored for easy access
final String? instanceName;
String? instanceName;

/// true if one of the async registration functions have been used
final bool isAsync;
Expand Down Expand Up @@ -1034,6 +1034,55 @@ class _GetItImplementation implements GetIt {
}
}

/// In some cases it can be necessary to change the name of a registered instance
/// This avoids to unregister and reregister the instance which might cause trouble
/// with disposing functions.
/// IMPORTANT: This will only change the the first instance that is found while
/// searching the scopes.
/// If the new name is already in use in the current scope it will throw a
/// StateError
/// [instanceName] the current name of the instance
/// [newInstanceName] the new name of the instance
/// [instance] the instance itself that can be used instead of
/// providing the type and the name. If [instance] is null the type and the name
/// have to be provided
@override
void changeTypeInstanceName<T extends Object>({
String? instanceName,
required String newInstanceName,
T? instance,
}) {
assert(instance != null || instanceName != null,
'You have to provide either an instance or an instanceName');

final factoryToRename = instance != null
? _findFactoryByInstance(instance)
: _findFactoryByNameAndType<T>(instanceName);

if (instance != null) {
instanceName = factoryToRename.instanceName;
}

throwIfNot(
factoryToRename.isNamedRegistration,
StateError(
'This instance $instance is not registered with a name',
),
);

final typeRegistration = factoryToRename.registeredIn;
throwIf(
typeRegistration.namedFactories.containsKey(newInstanceName),
StateError(
'There is already an instance of type ${factoryToRename.registrationType} registered with the name $newInstanceName',
),
);

typeRegistration.namedFactories[newInstanceName] = factoryToRename;
typeRegistration.namedFactories.remove(instanceName);
factoryToRename.instanceName = newInstanceName;
}

/// Clears the instance of a lazy singleton,
/// being able to call the factory function on the next call
/// of [get] on that type again.
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: get_it
description: Simple direct Service Locator that allows to decouple the interface from a concrete implementation and to access the concrete implementation from everywhere in your App"
version: 8.0.0-pre-4
version: 8.0.0-pre-5
maintainer: Thomas Burkhart (@escamoteur)
homepage: https://github.com/fluttercommunity/get_it
funding:
Expand Down
71 changes: 71 additions & 0 deletions test/get_it_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1019,6 +1019,77 @@ void main() {
throwsA(const TypeMatcher<StateError>()),
);
});
test('change registration name with type and name', () async {
final getIt = GetIt.instance;
disposeCounter = 0;

getIt.registerSingleton(TestClass(), instanceName: 'instanceName');

final TestClass instance1 = getIt.get(instanceName: 'instanceName');

expect(instance1 is TestClass, true);

getIt.changeTypeInstanceName<TestClass>(
instanceName: 'instanceName',
newInstanceName: 'instanceName2',
);

expect(disposeCounter, 0);

expect(
() => getIt<TestClass>(instanceName: 'instanceName'),
throwsA(const TypeMatcher<StateError>()),
);
expect(
getIt<TestClass>(instanceName: 'instanceName2'),
const TypeMatcher<TestClass>(),
);
});

test('change registration name with type and name existing name', () async {
final getIt = GetIt.instance;

getIt.registerSingleton(TestClass(), instanceName: 'instanceName');
getIt.registerSingleton(TestClass(), instanceName: 'instanceNameExisting');

final TestClass instance1 = getIt.get(instanceName: 'instanceName');

expect(instance1 is TestClass, true);

expect(() {
getIt.changeTypeInstanceName<TestClass>(
instanceName: 'instanceName',
newInstanceName: 'instanceNameExisting',
);
}, throwsA(const TypeMatcher<StateError>()));
});

test('change registration name of instance', () async {
final getIt = GetIt.instance;
disposeCounter = 0;

getIt.registerSingleton(TestClass(), instanceName: 'instanceName');

final TestClass instance1 = getIt.get(instanceName: 'instanceName');

expect(instance1 is TestClass, true);

getIt.changeTypeInstanceName(
instance: instance1,
newInstanceName: 'instanceName2',
);

expect(disposeCounter, 0);

expect(
() => getIt<TestClass>(instanceName: 'instanceName'),
throwsA(const TypeMatcher<StateError>()),
);
expect(
getIt<TestClass>(instanceName: 'instanceName2'),
const TypeMatcher<TestClass>(),
);
});

test(
'can register a singleton with instanceName and retrieve it with generic parameters and instanceName',
Expand Down

0 comments on commit 98b7d28

Please sign in to comment.