Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Add scopeName parameter to popScope #292

Merged
merged 8 commits into from
May 7, 2023
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
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,15 @@ 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,
/// 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.
/// if you passed a dispose function when you pushed this scope it will be
/// called before the scope is dropped.
/// As dispose functions can be async, you should await this function.
Future<void> dropScope(String scopeName);

/// Clears all registered types for the current scope
/// If you provided dispose function when registering they will be called
/// [dispose] if `false` it only resets without calling any dispose
Expand Down
9 changes: 9 additions & 0 deletions lib/get_it.dart
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,15 @@ 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,
/// 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.
/// if you passed a dispose function when you pushed this scope it will be
/// called before the scope is dropped.
/// As dispose functions can be async, you should await this function.
Future<void> dropScope(String scopeName);

/// Returns the name of the current scope if it has one otherwise null
/// if you are already on the baseScope it returns 'baseScope'
String? get currentScopeName;
Expand Down
27 changes: 27 additions & 0 deletions lib/get_it_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -842,6 +842,33 @@ class _GetItImplementation implements GetIt {
return true;
}

/// Disposes all registered factories and singletons in the provided scope,
/// 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.
/// if you passed a dispose function when you pushed this scope it will be
/// called before the scope is dropped.
/// As dispose functions can be async, you should await this function.
@override
Future<void> dropScope(String scopeName) async {
if (currentScopeName == scopeName) {
return popScope();
}
throwIfNot(
_scopes.length > 1,
StateError(
"GetIt: You are already on the base scope. you can't drop this one",
),
);
final scope = _scopes.lastWhere(
(s) => s.name == scopeName,
orElse: () => throw ArgumentError("Scope $scopeName not found"),
);
await scope.dispose();
await scope.reset(dispose: true);
_scopes.remove(scope);
}

@override
String? get currentScopeName => _currentScope.name;

Expand Down
41 changes: 41 additions & 0 deletions test/scope_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,47 @@ void main() {
expect(() => getIt.popScope(), throwsA(const TypeMatcher<StateError>()));
});

test('dropScope', () async {
final getIt = GetIt.instance;

getIt.registerSingleton<TestClass>(TestClass('Basescope'));

getIt.pushNewScope(scopeName: 'scope2');
getIt.registerSingleton<TestClass>(TestClass('2. scope'));
getIt.registerSingleton<TestClass2>(TestClass2('2. scope'));

getIt.pushNewScope();
getIt.registerSingleton<TestClass3>(TestClass3());

final instanceTestClassScope2 = getIt.get<TestClass>();

expect(instanceTestClassScope2 is TestClass, true);
expect(instanceTestClassScope2.id, '2. scope');

await getIt.dropScope('scope2');

final instanceTestClassScope1 = getIt.get<TestClass>();

expect(instanceTestClassScope1.id, 'Basescope');
expect(
() => getIt.get<TestClass2>(),
throwsA(const TypeMatcher<StateError>()),
);

final instanceTestClass3Scope3 = getIt.get<TestClass3>();
expect(instanceTestClass3Scope3 is TestClass3, true);
});

test('dropScope throws if scope with name not found', () async {
final getIt = GetIt.instance;

getIt.pushNewScope(scopeName: 'scope2');
await expectLater(
() => getIt.dropScope('scope'),
throwsA(const TypeMatcher<ArgumentError>()),
);
});

test('resetScope', () async {
final getIt = GetIt.instance;
constructorCounter = 0;
Expand Down