Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 27 additions & 7 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,29 @@
[7.6.5] - 25.09.2023 updated Discord link
[7.6.4] -04.09.2023 fixed the throwing of a StateError that was previously thrown as String
[7.6.3] -04.09.2023 push new version because pub didn't list this one
[7.6.2] -31.08.2023 fix linter error
[7.6.1] - 31.08.2023 version bump of dependencies and updates readme
[7.6.0] - 09.05.2023
## [7.6.6] - 04.01.2024

* `getIt.reset, getIt.popScope, getIt.dropScope` now dispose services in the reverse order in which they were registered.

## [7.6.5] - 25.09.2023

* updated Discord link

## [7.6.4] - 04.09.2023

* fixed the throwing of a StateError that was previously thrown as String

## [7.6.3] - 04.09.2023

* push new version because pub didn't list this one

## [7.6.2] - 31.08.2023

* fix linter error

## [7.6.1] - 31.08.2023

* version bump of dependencies and updates readme

## [7.6.0] - 09.05.2023

* merged PR by lacopiroty https://github.com/fluttercommunity/get_it/pull/297 which now allows to access objects inside GetIt by runtime type too like
```Dart
getIt.registerSingleton(TestClass());
Expand All @@ -16,7 +36,7 @@
* fix for https://github.com/fluttercommunity/get_it/issues/300


[7.5.0] - 07.05.2023
## [7.5.0] - 07.05.2023

* new function `dropScope(scopeName)` which allows to remove and dispose any named scope even if it's not the top one. Great PR by @olexale https://github.com/fluttercommunity/get_it/pull/292 which fixes sort of race conditions if you create scopes just for the life time of a widget.
## [7.4.1]
Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,8 @@ void resetLazySingleton<T>({Object instance,
### Resetting GetIt completely

```Dart
/// Clears all registered types. Handy when writing unit tests
/// Disposes all registered types in the reverse order in which they were registered.
/// Handy when writing unit tests or before quitting your application.
/// If you provided dispose function when registering they will be called
/// [dispose] if `false` it only resets without calling any dispose
/// functions
Expand Down Expand Up @@ -245,7 +246,7 @@ Another example could be a shopping basket where you want to ensure that not a c
/// If no scope with [name] exists, nothing is popped and `false` is returned
Future<bool> popScopesTill(String name, {bool inclusive = true});

/// Disposes all registered factories and singletons in the provided scope,
/// Clears all registered factories and singletons in the provided scope,
/// then destroys (drops) the scope. If the dropped scope was the last one,
/// the previous scope becomes active again.
/// if you provided dispose functions on registration, they will be called.
Expand All @@ -257,7 +258,7 @@ Another example could be a shopping basket where you want to ensure that not a c
/// Tests if the scope by name [scopeName] is registered in GetIt
bool hasScope(String scopeName);

/// Clears all registered types for the current scope
/// Clears all registered types for the current scope in the reverse order in which they were registered.
/// If you provided dispose function when registering they will be called
/// [dispose] if `false` it only resets without calling any dispose
/// functions
Expand Down
2 changes: 1 addition & 1 deletion doc/api/get_it/GetIt/reset.html
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ <h5>GetIt class</h5>

</section>
<section class="desc markdown">
<p>Clears all registered types. Handy when writing unit tests</p>
<p>Clears all registered types in the reverse order in which they were registered. Handy when writing unit tests and when you need to dispose services that depend on each other.</p>
</section>

<section class="summary source-code" id="source">
Expand Down
9 changes: 6 additions & 3 deletions lib/get_it.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
library get_it;

import 'dart:async';
import 'dart:collection';

import 'package:async/async.dart';
import 'package:collection/collection.dart' show IterableExtension;
Expand Down Expand Up @@ -359,14 +360,15 @@ abstract class GetIt {
/// is registered inside GetIt
bool isRegistered<T extends Object>({Object? instance, String? instanceName});

/// Clears all registered types. Handy when writing unit tests
/// 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
/// [dispose] if `false` it only resets without calling any dispose
/// functions
/// As dispose functions can be async, you should await this function.
Future<void> reset({bool dispose = true});

/// Clears all registered types for the current scope
/// Clears all registered types for the current scope in the reverse order of registering them.
/// If you provided dispose function when registering they will be called
/// [dispose] if `false` it only resets without calling any dispose
/// functions
Expand Down Expand Up @@ -419,7 +421,8 @@ abstract class GetIt {
/// If no scope with [name] exists, nothing is popped and `false` is returned
Future<bool> popScopesTill(String name, {bool inclusive = true});

/// Disposes all registered factories and singletons in the provided scope,
/// Disposes all registered factories and singletons in the provided scope
/// (in the reverse order in which they were registered),
/// then destroys (drops) the scope. If the dropped scope was the last one,
/// the previous scope becomes active again.
/// if you provided dispose functions on registration, they will be called.
Expand Down
15 changes: 9 additions & 6 deletions lib/get_it_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -302,14 +302,15 @@ class _Scope {
final String? name;
final ScopeDisposeFunc? disposeFunc;
bool isFinal = false;
final factoriesByName =
<String?, Map<Type, _ServiceFactory<Object, dynamic, dynamic>>>{};
// ignore: prefer_collection_literals
final factoriesByName = LinkedHashMap<String?,
LinkedHashMap<Type, _ServiceFactory<Object, dynamic, dynamic>>>();

_Scope({this.name, this.disposeFunc});

Future<void> reset({required bool dispose}) async {
if (dispose) {
for (final factory in allFactories) {
for (final factory in allFactories.reversed) {
await factory.dispose();
}
}
Expand Down Expand Up @@ -753,7 +754,7 @@ class _GetItImplementation implements GetIt {
await resetScope(dispose: dispose);
}

/// Clears all registered types of the current scope.
/// Clears all registered types of the current scope in the reverse order in which they were registered.
@override
Future<void> resetScope({bool dispose = true}) async {
if (dispose) {
Expand Down Expand Up @@ -829,6 +830,7 @@ class _GetItImplementation implements GetIt {
}

/// Disposes all factories/Singletons that have been registered in this scope
/// (in the reverse order in which they were registered)
/// and pops (destroys) the scope so that the previous scope gets active again.
/// if you provided dispose functions on registration, they will be called.
/// if you passed a dispose function when you pushed this scope it will be
Expand Down Expand Up @@ -875,7 +877,8 @@ class _GetItImplementation implements GetIt {
return true;
}

/// Disposes all registered factories and singletons in the provided scope,
/// Disposes all registered factories and singletons in the provided scope
/// (in the reverse order in which they were registered),
/// then drops (destroys) the scope. If the dropped scope was the last one,
/// the previous scope becomes active again.
/// if you provided dispose functions on registration, they will be called.
Expand Down Expand Up @@ -985,7 +988,7 @@ class _GetItImplementation implements GetIt {

factoriesByName.putIfAbsent(
instanceName,
() => <Type, _ServiceFactory<Object, dynamic, dynamic>>{},
() => LinkedHashMap<Type, _ServiceFactory<Object, dynamic, dynamic>>(),
);
factoriesByName[instanceName]![T] = serviceFactory;

Expand Down
112 changes: 112 additions & 0 deletions test/get_it_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,24 @@ class TestClassParam {
TestClassParam({this.param1, this.param2});
}

class TestClassDisposableWithDependency with Disposable {
final TestClassDisposable testClass;
TestClassDisposableWithDependency(this.testClass) {
constructorCounter *=
3; // with this multiplication we can detect the order of the constructor.
}

void dispose() {
disposeCounter *=
3; // with this multiplication we can detect the order of disposal.
}

@override
void onDispose() {
dispose();
}
}

void main() {
setUp(() async {
// make sure the instance is cleared before each test
Expand Down Expand Up @@ -936,6 +954,100 @@ void main() {

expect(instance, const TypeMatcher<Injector>());
});

test('deregister in the same order of registering', () async {
final getIt = GetIt.instance;
disposeCounter = 0;
constructorCounter = 0;

getIt.registerSingleton<TestClassDisposable>(TestClassDisposable());

final instance1 = getIt.get<TestClassDisposable>();

expect(instance1 is TestClassDisposable, true);

expect(constructorCounter, 1);

getIt.registerSingleton<TestClassDisposableWithDependency>(
TestClassDisposableWithDependency(getIt.get<TestClassDisposable>()),
);

final instance2 = getIt.get<TestClassDisposableWithDependency>();
expect(constructorCounter, 3);
expect(instance1 == instance2.testClass, true);

await getIt.unregister<TestClassDisposable>();
expect(disposeCounter, 1);

final instance3 = getIt.get<TestClassDisposableWithDependency>();

expect(instance2.testClass == instance3.testClass, true);

await getIt.unregister<TestClassDisposableWithDependency>();
expect(disposeCounter, 3);
});

test('deregister in reverse order of registering', () async {
final getIt = GetIt.instance;
disposeCounter = 0;
constructorCounter = 0;

getIt.registerSingleton<TestClassDisposable>(TestClassDisposable());

final instance1 = getIt.get<TestClassDisposable>();

expect(instance1 is TestClassDisposable, true);

expect(constructorCounter, 1);

getIt.registerSingleton<TestClassDisposableWithDependency>(
TestClassDisposableWithDependency(getIt.get<TestClassDisposable>()),
);

final instance2 = getIt.get<TestClassDisposableWithDependency>();
expect(constructorCounter, 3);
expect(instance1 == instance2.testClass, true);

await getIt.unregister<TestClassDisposableWithDependency>();
expect(disposeCounter, 0);

expect(
() => getIt<TestClassDisposableWithDependency>(),
throwsA(const TypeMatcher<StateError>()),
);

await getIt.unregister<TestClassDisposable>();
expect(disposeCounter, 1);
});

test('deregister in reverse order of registering using reset', () async {
final getIt = GetIt.instance;
disposeCounter = 0;
constructorCounter = 0;

getIt.registerSingleton<TestClassDisposable>(TestClassDisposable());

final instance1 = getIt.get<TestClassDisposable>();

expect(instance1 is TestClassDisposable, true);

expect(constructorCounter, 1);

getIt.registerSingleton<TestClassDisposableWithDependency>(
TestClassDisposableWithDependency(getIt.get<TestClassDisposable>()),
);

final instance2 = getIt.get<TestClassDisposableWithDependency>();
expect(constructorCounter, 3);
expect(instance1 == instance2.testClass, true);

await getIt.reset();
expect(
disposeCounter,
1,
reason: "getIt.reset() did not dispose in reverse order",
);
});
}

class SingletonInjector {
Expand Down