Skip to content

Commit fc062a7

Browse files
committed
Initial super lame version
0 parents  commit fc062a7

8 files changed

+227
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules
2+
packages
3+
pubspec.lock

Gruntfile.coffee

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
spawn = require('child_process').spawn
2+
3+
DART_VM = process.env.DART_VM or '../dart-sdk/bin/dart'
4+
5+
module.exports = (grunt) ->
6+
grunt.initConfig
7+
watch:
8+
tests:
9+
files: ['test/**/*.dart', 'lib/**/*.dart']
10+
tasks: ['dart']
11+
dart:
12+
tests:
13+
entry: 'test/main.dart'
14+
15+
grunt.registerMultiTask 'dart', 'run dart program', ->
16+
spawn(DART_VM, [@data.entry], {stdio: 'inherit'}).on 'close', @async()
17+
18+
grunt.loadNpmTasks 'grunt-contrib-watch'

lib/di.dart

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import 'mirrors.dart';
2+
import 'dart:async';
3+
4+
class Injector {
5+
// should be <Type,Type>
6+
Map<String, String> providers = new Map<String, String>();
7+
// should be <Type, dynamic>
8+
Map<String, dynamic> instances = new Map<String, dynamic>();
9+
10+
Injector([Map types]) {
11+
if (types != null) {
12+
// create <String,String> map, because Dart is stupid and makes us deal with strings rather than types
13+
types.forEach((key, value) {
14+
providers[key.toString()] = value.toString();
15+
});
16+
}
17+
}
18+
19+
ClassMirror _getClassMirrorByTypeName (String typeName) {
20+
// overriden provider
21+
if (providers.containsKey(typeName)) {
22+
typeName = providers[typeName];
23+
}
24+
25+
for (var lib in currentMirrorSystem().libraries.values) {
26+
if (lib.classes.containsKey(typeName)) {
27+
return lib.classes[typeName];
28+
}
29+
}
30+
}
31+
32+
ClassMirror _getClassMirrorFromType(Type type) {
33+
// terrible hack because we can't get a qualified name from a Type
34+
// dartbug.com/8041
35+
// dartbug.com/9395
36+
return _getClassMirrorByTypeName(type.toString());
37+
}
38+
39+
40+
dynamic _getInstanceByTypeName(String typeName) {
41+
if (instances.containsKey(typeName)) {
42+
return instances[typeName];
43+
}
44+
45+
ClassMirror cm = _getClassMirrorByTypeName(typeName);
46+
MethodMirror ctor = cm.constructors.values.first;
47+
48+
resolveArgument(p) {
49+
return _getInstanceByTypeName(p.type.simpleName);
50+
}
51+
52+
var positionalArgs = ctor.parameters.map(resolveArgument).toList();
53+
var namedArgs = null;
54+
var instance = deprecatedFutureValue(cm.newInstance(ctor.constructorName, positionalArgs, namedArgs));
55+
56+
instances[typeName] = instance;
57+
58+
return instance;
59+
}
60+
61+
62+
// PUBLIC API
63+
dynamic get(Type type) {
64+
return _getInstanceByTypeName(type.toString()).reflectee;
65+
}
66+
}

lib/mirrors.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// just to get rid of the warning
2+
library mirrors;
3+
4+
export 'dart:mirrors';

package.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"name": "dart-di",
3+
"version": "0.0.0",
4+
"description": "ERROR: No README.md file found!",
5+
"main": "index.js",
6+
"dependencies": {},
7+
"devDependencies": {
8+
"grunt": "~0.4",
9+
"grunt-contrib-watch": "~0.3"
10+
},
11+
"scripts": {
12+
"test": "grunt dart:test"
13+
},
14+
"repository": "",
15+
"author": "Vojta Jina <[email protected]>",
16+
"license": "MIT"
17+
}

pubspec.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
name: di
2+
description: A prototype of Dependency Injection framework.
3+
version: 0.0.1
4+
author: "Vojta Jina <[email protected]>"
5+
homepage: https://github.com/dart-lang/dado
6+
7+
dev_dependencies:
8+
unittest: any

test/fixed-unittest.dart

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
library unittest;
2+
3+
import 'package:unittest/unittest.dart';
4+
import '../lib/mirrors.dart';
5+
6+
export 'package:unittest/unittest.dart';
7+
8+
// fix the testing framework ;-)
9+
void it(String spec, TestFunction body) => test(spec, body);
10+
void xit(String spec, TestFunction body) {}
11+
void iit(String spec, TestFunction body) => solo_test(spec, body);
12+
13+
Matcher toEqual(expected) => equals(expected);
14+
Matcher toBe(expected) => same(expected);
15+
Matcher instanceOf(Type t) => new IsInstanceOfTypeMatcher(t);
16+
17+
18+
// Welcome to Dart ;-)
19+
class IsInstanceOfTypeMatcher extends BaseMatcher {
20+
Type t;
21+
22+
IsInstanceOfTypeMatcher(Type t) {
23+
this.t = t;
24+
}
25+
26+
bool matches(obj, MatchState matchState) {
27+
// we should at least compare qualifiedName, but there's no way to get it from Type
28+
return reflect(obj).type.simpleName == t.toString();
29+
}
30+
31+
Description describe(Description description) =>
32+
description.add('an instance of ${t.toString()}');
33+
}

test/main.dart

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import 'fixed-unittest.dart';
2+
import 'package:di/di.dart';
3+
4+
// just some classes for testing
5+
class Abc {
6+
String id = 'abc-id';
7+
8+
void greet() {
9+
print('HELLO');
10+
}
11+
}
12+
13+
class MockAbc implements Abc {
14+
String id = 'mock-id';
15+
16+
void greet() {
17+
print('MOCK HELLO');
18+
}
19+
}
20+
21+
class Complex {
22+
Abc value;
23+
24+
Complex(Abc val) {
25+
value = val;
26+
}
27+
28+
dynamic getValue() {
29+
return value;
30+
}
31+
}
32+
33+
34+
// pretend, you don't see this main method
35+
void main() {
36+
37+
it('should instantiate a type', () {
38+
var injector = new Injector();
39+
var instance = injector.get(Abc);
40+
41+
expect(instance, instanceOf(Abc));
42+
expect(instance.id, toEqual('abc-id'));
43+
});
44+
45+
46+
it('should resolve basic dependencies', () {
47+
var injector = new Injector();
48+
var instance = injector.get(Complex);
49+
50+
expect(instance, instanceOf(Complex));
51+
expect(instance.getValue().id, toEqual('abc-id'));
52+
});
53+
54+
55+
it('should allow modules and overriding providers', () {
56+
// module is just a Map<Type, Type>
57+
var module = new Map<Type, Type>();
58+
module[Abc] = MockAbc;
59+
60+
// injector is immutable
61+
// you can't load more modules once it's instantiated
62+
// (you can create a child injector)
63+
var injector = new Injector(module);
64+
var instance = injector.get(Abc);
65+
66+
expect(instance.id, toEqual('mock-id'));
67+
});
68+
69+
70+
it('should only create a single instance', () {
71+
var injector = new Injector();
72+
var first = injector.get(Abc);
73+
var second = injector.get(Abc);
74+
75+
expect(first, toBe(second));
76+
});
77+
78+
}

0 commit comments

Comments
 (0)