Skip to content

Commit

Permalink
Introduce dropScope
Browse files Browse the repository at this point in the history
  • Loading branch information
olexale committed May 5, 2023
1 parent 0d3a8d1 commit b9ba69c
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 41 deletions.
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
12 changes: 10 additions & 2 deletions lib/get_it.dart
Original file line number Diff line number Diff line change
Expand Up @@ -402,8 +402,7 @@ abstract class GetIt {
/// if you passed a dispose function when you pushed this scope it will be
/// called before the scope is popped.
/// As dispose functions can be async, you should await this function.
/// If [scopeName] is provided, only the scope with that name will be popped.
Future<void> popScope({String? scopeName});
Future<void> popScope();

/// if you have a lot of scopes with names you can pop (see [popScope]) all
/// scopes above the scope with [name] including that scope unless [inclusive]= false
Expand All @@ -412,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
78 changes: 39 additions & 39 deletions test/scope_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -365,45 +365,6 @@ void main() {
throwsA(const TypeMatcher<AssertionError>()),
);
});
test('popscope named', () async {
final getIt = GetIt.instance;
constructorCounter = 0;

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.popScope(scopeName: 'scope2');

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

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

final instanceTestClass3Scope3 = getIt.get<TestClass3>();
expect(instanceTestClass3Scope3 is TestClass3, true);
});
test('popscope throws if scope with name not found', () async {
final getIt = GetIt.instance;
constructorCounter = 0;

getIt.pushNewScope(scopeName: 'scope2');
await expectLater(
() => getIt.popScope(scopeName: 'scope'),
throwsA(const TypeMatcher<ArgumentError>()),
);
});
test('popscopeuntil inclusive=true', () async {
final getIt = GetIt.instance;
constructorCounter = 0;
Expand Down Expand Up @@ -521,6 +482,45 @@ 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<AssertionError>()),
);

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;
Expand Down

0 comments on commit b9ba69c

Please sign in to comment.