Skip to content

Commit

Permalink
Merge pull request #65 from LoveCommunity/feature/final
Browse files Browse the repository at this point in the history
add `Final`
  • Loading branch information
beeth0ven committed Jul 7, 2022
2 parents 65550c3 + 57bdcc1 commit 45e0628
Show file tree
Hide file tree
Showing 5 changed files with 240 additions and 0 deletions.
88 changes: 88 additions & 0 deletions lib/src/scopes/configurables/final.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import 'dart:async';
import 'package:disposal/disposal.dart';
import 'package:typedef_foundation/typedef_foundation.dart';

import '../scopes/configurable_scope.dart';
import '../shared/typedefs.dart';

import 'configurable.dart';

class Final<T> extends _Final<T> {

const Final({
Object? name,
required Equal<T> equal,
InstanceExpose<T>? expose,
InstanceDispose<T>? dispose,
}): super(
name: name,
equal: equal,
expose: expose,
dispose: dispose,
late: false,
);
}

class LateFinal<T> extends _Final<T> {

const LateFinal({
Object? name,
required Equal<T> equal,
InstanceExpose<T>? expose,
InstanceDispose<T>? dispose,
}): super(
name: name,
equal: equal,
expose: expose,
dispose: dispose,
late: true,
);
}

class _Final<T> implements Configurable {

const _Final({
Object? name,
required Equal<T> equal,
InstanceExpose<T>? expose,
InstanceDispose<T>? dispose,
required bool late,
}): _name = name,
_equal = equal,
_expose = expose,
_dispose = dispose,
_late = late;

final Object? _name;
final Equal<T> _equal;
final InstanceExpose<T>? _expose;
final InstanceDispose<T>? _dispose;
final bool _late;

@override
FutureOr<void> configure(ConfigurableScope scope) {

final Getter<T> getter;
if (!_late) {
final instance = _equal(scope);
getter = () => instance;
} else {
late final instance = _equal(scope);
getter = () => instance;
}

if (_expose != null) {
_expose!(scope, getter);
} else {
scope.expose<T>(name: _name, expose: getter);
}

if (_dispose != null) {
scope.addDisposable(Disposable(() {
_dispose!(getter());
}));
}

}
}

2 changes: 2 additions & 0 deletions lib/src/scopes/scopes.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@

export 'configurables/configurable.dart';
export 'configurables/final.dart';
export 'errors/scope_value_not_exposed_error.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';
export 'shared/typedefs.dart';
9 changes: 9 additions & 0 deletions lib/src/scopes/shared/typedefs.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

import 'package:typedef_foundation/typedef_foundation.dart';

import '../scope_methods/scope_expose.dart';
import '../scope_methods/scope_get.dart';

typedef InstanceDispose<T> = void Function(T);
typedef InstanceExpose<T> = void Function(ScopeExpose scope, Getter<T> getter);
typedef Equal<T> = T Function(ScopeGet scope);
139 changes: 139 additions & 0 deletions test/scopes/configurables/final_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@

import 'package:test/test.dart';
import 'package:scopes/scopes.dart';

import '../../toolbox/mock_configurable.dart';

void main() {

test('`Final` is sync configuration', () {

final scope = Scope.root([
Final<String>(equal: (_) => 'a'),
]);

expect(scope, isA<Scope>());

});

test('`Final` share same instance in scope', () async {

final scope = await Scope.root([
Final<Object>(equal: (_) => Object()),
]);

final object1 = scope.get<Object>();
final object2 = scope.get<Object>();

final isIdentical = identical(object1, object2);

expect(isIdentical, true);

});

test('`Final` share same instance in scope with name', () async {

final scope = await Scope.root([
Final<Object>(name: 'object', equal: (_) => Object()),
]);

final object1 = scope.get<Object>(name: 'object');
final object2 = scope.get<Object>(name: 'object');

final isIdentical = identical(object1, object2);

expect(isIdentical, true);

});

test('`Final` assign value which depends on other scope value', () async {

final scope = await Scope.root([
MockConfigurable((scope) {
scope.expose<int>(expose: () => 0);
}),
Final<String>(
equal: (scope) => scope.get<int>().toString(),
),
]);

final string = scope.get<String>();

expect(string, '0');

});

test('`Final` expose value using custom `expose`', () async {

final scope = await Scope.root([
Final<String>(
equal: (_) => 'a',
expose: (scope, getter) {
scope.expose<Object>(expose: getter);
},
),
]);

final string = scope.getOrNull<String>();
final object = scope.getOrNull<Object>();

expect(string, null);
expect(object, 'a');

});

test('`Final` register instance dispose logic using `dispose`', () async {

int invokes = 0;

final scope = await Scope.root([
Final<Disposable>(
equal: (_) => Disposable(() {
invokes += 1;
}),
dispose: (instance) => instance.dispose(),
),
]);

expect(invokes, 0);
scope.dispose();
expect(invokes, 1);

});

test('`Final` assign instance immediately', () async {

int invokes = 0;

await Scope.root([
Final<Object>(
equal: (_) {
invokes += 1;
return Object();
},
),
]);

expect(invokes, 1);

});

test('`LateFinal` assign instance lazily', () async {

int invokes = 0;

final scope = await Scope.root([
LateFinal<Object>(
equal: (_) {
invokes += 1;
return Object();
},
),
]);

expect(invokes, 0);
scope.get<Object>();
expect(invokes, 1);

});
}
2 changes: 2 additions & 0 deletions test/scopes/scopes_test.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

import 'configurables/configurable_combine_test.dart' as configurable_combine_test;
import 'configurables/configurable_function_test.dart' as configurable_function_test;
import 'configurables/final_test.dart' as final_test;
import 'scope_methods/disposable_test.dart' as disposable_test;
import 'scope_methods/scope_get_test.dart' as scope_get_test;
import 'scope_methods/scope_push_test.dart' as scope_push_test;
Expand All @@ -9,6 +10,7 @@ import 'scopes/scope_test.dart' as scope_test;
void main() {
configurable_combine_test.main();
configurable_function_test.main();
final_test.main();
disposable_test.main();
scope_get_test.main();
scope_push_test.main();
Expand Down

0 comments on commit 45e0628

Please sign in to comment.