Skip to content

Commit

Permalink
Merge pull request #6 from utopia-dart/feat-refactor
Browse files Browse the repository at this point in the history
Feat refactor
  • Loading branch information
lohanidamodar authored Sep 20, 2024
2 parents 58690eb + e8c7423 commit 0fac0db
Show file tree
Hide file tree
Showing 9 changed files with 153 additions and 79 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ void main() {
di.setResource(
'dependentResource',
(String resource1, int number1) => '$resource1 and $number1',
injections: ['resource1', 'number1'],
dependencies: ['resource1', 'number1'],
);

print(di.getResource('resource1'));
Expand Down
12 changes: 7 additions & 5 deletions example/utopia_di_example.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import 'package:utopia_di/utopia_di.dart';

void main() {
final di = DI.i;
di.set('resource1', () => 'this is resource 1');
di.set('number1', () => 10);
di.set(Dependency('resource1', () => 'this is resource 1'));
di.set(D('number1', () => 10));
di.set(
'dependentResource',
(String resource1, int number1) => '$resource1 and $number1',
injections: ['resource1', 'number1'],
D(
'dependentResource',
(String resource1, int number1) => '$resource1 and $number1',
dependencies: ['resource1', 'number1'],
),
);

print(di.get('resource1'));
Expand Down
78 changes: 78 additions & 0 deletions lib/src/container.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import 'dart:collection';

import 'dependency.dart';

class Container {
// Store dependencies and instances
final Map<String, Dependency> _dependencies = HashMap();
final Map<String, dynamic> _instances = HashMap();

// Constructor
Container() {
Dependency di = Dependency('di', () => this);
_dependencies[di.name] = di;
}

// Set a dependency
Container set(Dependency dependency) {
if (_instances.containsKey(dependency.name)) {
_instances.remove(dependency.name);
}

_dependencies[dependency.name] = dependency;
return this;
}

// Get a dependency
dynamic get<T>(String name) {
if (!has(name)) {
throw Exception('Failed to find dependency: "$name"');
}

final resource = inject(_dependencies[name]!);
if (resource is T) {
return resource;
}
throw Exception('Resource type doesn\'t match');
}

// Check if a dependency exists
bool has(String name) {
return _dependencies.containsKey(name);
}

// Resolve the dependencies of a given injection
dynamic inject(Dependency injection, {bool fresh = false}) {
if (_instances.containsKey(injection.name) && !fresh) {
return _instances[injection.name];
}

List<dynamic> arguments = [];

for (String dependency in injection.dependencies) {
if (_instances.containsKey(dependency)) {
arguments.add(_instances[dependency]);
continue;
}

if (!_dependencies.containsKey(dependency)) {
throw Exception('Failed to find dependency: "$dependency"');
}

arguments.add(get(dependency));
}

var resolved = Function.apply(injection.callback, arguments);
_instances[injection.name] = resolved;
return resolved;
}

// Refresh a dependency
Container refresh(String name) {
if (_instances.containsKey(name)) {
_instances.remove(name);
}

return this;
}
}
22 changes: 22 additions & 0 deletions lib/src/dependency.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/// Dependency
/// Define your dependency, name and a callback
class Dependency {
final String name;
final Function callback;
final List<String> dependencies;

Dependency(this.name, this.callback, {this.dependencies = const []});

Dependency inject(String name) {
if (dependencies.contains(name)) {
throw Exception('Dependency already declared for $name');
}
dependencies.add(name);
return this;
}
}

/// Another shorter name for Dependency
class D extends Dependency {
D(super.name, super.callback, {super.dependencies});
}
76 changes: 32 additions & 44 deletions lib/src/di.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import 'resource_callback.dart';
import 'dart:collection';

import 'dependency.dart';
import 'container.dart';

/// Dependency injection
///
Expand All @@ -10,8 +13,12 @@ import 'resource_callback.dart';
class DI {
static const defaultContext = 'utopia';
static DI? _instance;
final Map<String, Map<String, dynamic>> _resources = {};
final Map<String, Map<String, ResourceCallback>> _resourceCallbacks = {};

final Map<String, Container> _containers = HashMap();

DI() {
_containers[defaultContext] = Container();
}

/// Get singleton instance
static DI get instance {
Expand All @@ -23,15 +30,13 @@ class DI {
static DI get i => DI.instance;

/// Set a resource callback
void set(
String name,
Function callback, {
List<String> injections = const [],
DI set(
Dependency dependency, {
String context = defaultContext,
}) {
_resourceCallbacks[context] ??= {};
_resourceCallbacks[context]![name] =
ResourceCallback(name, injections, callback, reset: true);
_containers[context] ??= Container();
_containers[context]!.set(dependency);
return this;
}

/// Get all the resources set in the context
Expand All @@ -50,47 +55,30 @@ class DI {
/// Get a resource
dynamic get<T>(String name,
{String context = defaultContext, bool fresh = false}) {
_resources[context] ??= <String, dynamic>{};
_resourceCallbacks[context] ??= {};

final resources = _resources[context]!;
var resourceCallbacks = _resourceCallbacks[context]!;
if (resourceCallbacks.isEmpty || resourceCallbacks[name] == null) {
// use default context when not found in the context
resourceCallbacks = _resourceCallbacks[defaultContext] ?? {};
if (!_containers.containsKey(context)) {
throw Exception('Context $context does not exist.');
}
if (resources[name] == null ||
fresh ||
(resourceCallbacks[name]?.reset ?? true)) {
if (resourceCallbacks[name] == null) {
throw Exception('Failed to find resource: "$name"');
}

final params = getAll(resourceCallbacks[name]!.injections);
resources[name] = Function.apply(
resourceCallbacks[name]!.callback,
[...params.values],
);
}
resourceCallbacks[name] = resourceCallbacks[name]!.copyWith(reset: false);
final resource = resources[name];
if (resource is T) {
return resource;
if (fresh) {
_containers[context]!.refresh(name);
}
throw Exception('Resource type doesn\'t match');
return _containers[context]!.get<T>(name);
}

Container? getContainer(String context) {
return _containers[context];
}

/// Reset cached resources
void resetResources([String? context]) {
if (context != null) {
(_resources[context] ?? {}).clear();
return;
DI resetContext(String context) {
if (_containers.containsKey(context)) {
_containers.remove(context);
}
_resources.clear();
return this;
}

/// Resets all the dependencies
void reset() {
_resourceCallbacks.clear();
DI reset() {
_containers.clear();
_containers[defaultContext] = Container();
return this;
}
}
18 changes: 0 additions & 18 deletions lib/src/resource_callback.dart

This file was deleted.

2 changes: 2 additions & 0 deletions lib/utopia_di.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ library utopia_di;
export 'src/di.dart';
export 'src/hook.dart';
export 'src/param.dart';
export 'src/dependency.dart';
export 'src/container.dart';
6 changes: 3 additions & 3 deletions pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
name: utopia_di
description: Light & Fast Dart Dependency Injection library. Easy to use and powerful for all kinds of needs, with no external dependencies.
version: 0.2.1
version: 0.3.0
repository: https://github.com/utopia-dart/utopia_di

environment:
sdk: '>=2.19.2 <4.0.0'

dev_dependencies:
lints: ^3.0.0
test: ^1.25.2
lints: ^4.0.0
test: ^1.25.8
16 changes: 8 additions & 8 deletions test/unit/di_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@ import 'package:utopia_di/utopia_di.dart';

void main() async {
final di = DI();
di.set('rand', () => Random().nextInt(100));
di.set(
di.set(D('rand', () => Random().nextInt(100)));
di.set(D(
'first',
(String second) => 'first-$second',
injections: ['second'],
);
di.set('second', () => 'second');
dependencies: ['second'],
));
di.set(D('second', () => 'second'));

di.set('second', () => 'another second', context: 'another');
di.set('third', () => 'another third', context: 'another');
di.set(D('second', () => 'another second'), context: 'another');
di.set(D('third', () => 'another third'), context: 'another');

group('Utopia DI', () {
test('resource', () async {
Expand All @@ -36,7 +36,7 @@ void main() async {
isA<Exception>().having(
(error) => error.toString(),
'',
'Exception: Failed to find resource: "third"',
'Exception: Failed to find dependency: "third"',
),
),
);
Expand Down

0 comments on commit 0fac0db

Please sign in to comment.