diff --git a/lib/src/scopes/scope_methods/scope_push.dart b/lib/src/scopes/scope_methods/scope_push.dart new file mode 100644 index 0000000..cbcd931 --- /dev/null +++ b/lib/src/scopes/scope_methods/scope_push.dart @@ -0,0 +1,9 @@ + +import 'dart:async'; + +import '../configurables/configurable.dart'; +import '../scopes/scope.dart'; + +abstract class ScopePush { + FutureOr push(List configure); +} diff --git a/lib/src/scopes/scopes.dart b/lib/src/scopes/scopes.dart index aadd735..2d0bddd 100644 --- a/lib/src/scopes/scopes.dart +++ b/lib/src/scopes/scopes.dart @@ -2,5 +2,6 @@ export 'configurables/configurable.dart'; export 'scope_methods/scope_get.dart'; export 'scope_methods/scope_expose.dart'; +export 'scope_methods/scope_push.dart'; export 'scopes/configurable_scope.dart'; export 'scopes/scope.dart'; diff --git a/lib/src/scopes/scopes/configurable_scope.dart b/lib/src/scopes/scopes/configurable_scope.dart index d319e9c..e608728 100644 --- a/lib/src/scopes/scopes/configurable_scope.dart +++ b/lib/src/scopes/scopes/configurable_scope.dart @@ -1,7 +1,10 @@ +import 'dart:async'; import 'package:meta/meta.dart'; import 'package:typedef_foundation/typedef_foundation.dart'; +import '../configurables/configurable.dart'; import '../scope_methods/scope_expose.dart'; +import '../shared/build_scope.dart'; import 'scope.dart'; abstract class ConfigurableScope implements Scope, ScopeExpose { @@ -9,11 +12,17 @@ abstract class ConfigurableScope implements Scope, ScopeExpose { factory ConfigurableScope() = _ConfigurableScopeImpl; } +typedef _Storage = Map>; + class _ConfigurableScopeImpl implements ConfigurableScope { _ConfigurableScopeImpl(): _storage = {}; - final Map> _storage; + _ConfigurableScopeImpl._fromStorage(_Storage storage): + _storage = storage + .map((key, value) => MapEntry(key, Map.of(value))); + + final _Storage _storage; @override T? getOrNull({ @@ -40,5 +49,11 @@ class _ConfigurableScopeImpl implements ConfigurableScope { } _storage[T]![name] = expose; } + + @override + FutureOr push(List configure) { + final scope = _ConfigurableScopeImpl._fromStorage(_storage); + return buildScope(configure, scope); + } } diff --git a/lib/src/scopes/scopes/scope.dart b/lib/src/scopes/scopes/scope.dart index 604bee6..abc0cf9 100644 --- a/lib/src/scopes/scopes/scope.dart +++ b/lib/src/scopes/scopes/scope.dart @@ -3,11 +3,12 @@ import 'dart:async'; import '../configurables/configurable.dart'; import '../scope_methods/scope_get.dart'; +import '../scope_methods/scope_push.dart'; import '../shared/build_scope.dart'; import 'configurable_scope.dart'; -abstract class Scope implements ScopeGet { +abstract class Scope implements ScopeGet, ScopePush { static FutureOr root(List configure) => _scopeRoot(configure); } diff --git a/test/scopes/scope_methods/scope_push_test.dart b/test/scopes/scope_methods/scope_push_test.dart new file mode 100644 index 0000000..7592ef4 --- /dev/null +++ b/test/scopes/scope_methods/scope_push_test.dart @@ -0,0 +1,78 @@ + +import 'package:test/test.dart'; +import 'package:scopes/scopes.dart'; + +import '../../toolbox/mock_configurable.dart'; + +void main() { + + test('`scope.push` return sync scope if it only has sync configuration', () async { + + final parent = await Scope.root([]); + + final scope = parent.push([ + MockConfigurable((_) {}), + ]); + + expect(scope, isA()); + }); + + test('`scope.push` return async scope if it has async configuration', () async { + + final parent = await Scope.root([]); + + final scope = parent.push([ + MockConfigurable((_) async {}), + ]); + + expect(scope, isA>()); + }); + + test('`scope.push` returned scope has no value if value not exposed', () async { + + final parent = await Scope.root([]); + + final scope = await parent.push([]); + + final hasValue = scope.has(); + final value = scope.getOrNull(); + + expect(hasValue, false); + expect(value, null); + }); + + test('`scope.push` returned scope has value if value exposed', () async { + + final parent = await Scope.root([]); + + final scope = await parent.push([ + MockConfigurable((scope) { + scope.expose(expose: () => 'a'); + }), + ]); + + final hasValue = scope.has(); + final value = scope.getOrNull(); + + expect(hasValue, true); + expect(value, 'a'); + }); + + test('`scope.push` returned scope inherit values from parent scope', () async { + + final parent = await Scope.root([ + MockConfigurable((scope) { + scope.expose(expose: () => 'parent'); + }), + ]); + + final scope = await parent.push([]); + + final hasValue = scope.has(); + final value = scope.getOrNull(); + + expect(hasValue, true); + expect(value, 'parent'); + }); + +} diff --git a/test/scopes/scopes/scope_test.dart b/test/scopes/scopes/scope_test.dart index d561b64..86ce638 100644 --- a/test/scopes/scopes/scope_test.dart +++ b/test/scopes/scopes/scope_test.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'package:test/test.dart'; import 'package:scopes/scopes.dart'; @@ -152,4 +153,9 @@ class _MockScope implements Scope { bool has({ Object? name, }) => throw UnimplementedError(); + + @override + FutureOr push( + List configure, + ) => throw UnimplementedError(); } diff --git a/test/scopes/scopes_test.dart b/test/scopes/scopes_test.dart index dd893e4..7c466fa 100644 --- a/test/scopes/scopes_test.dart +++ b/test/scopes/scopes_test.dart @@ -1,6 +1,8 @@ +import 'scope_methods/scope_push_test.dart' as scope_push_test; import 'scopes/scope_test.dart' as scope_test; void main() { + scope_push_test.main(); scope_test.main(); }