Skip to content

Commit

Permalink
Very basic implemetation, can inject Values and Classes, fixes to sca…
Browse files Browse the repository at this point in the history
…n and dependency identifications. Unit tests
  • Loading branch information
Voiteh committed Jun 21, 2019
1 parent 9e0ac10 commit 6554624
Show file tree
Hide file tree
Showing 25 changed files with 354 additions and 105 deletions.
8 changes: 8 additions & 0 deletions source/herd/depin/api/Creator.ceylon
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import ceylon.language.meta.declaration {
Declaration
}

shared interface Creator{
shared formal Anything create(Declaration declaration);

}
7 changes: 4 additions & 3 deletions source/herd/depin/api/Dependency.ceylon
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import ceylon.language.meta.declaration {
OpenType
}
shared abstract class Dependency(
shared class Dependency(
shared OpenType type,
shared Identification identification

Expand All @@ -10,7 +10,7 @@ shared abstract class Dependency(
shared actual Boolean equals(Object that) {
if (is Dependency that) {
return type==that.type &&
identification.containsEvery(that.identification);
identification==that.identification;
}
else {
return false;
Expand All @@ -23,8 +23,9 @@ shared abstract class Dependency(
hash = 31*hash + identification.hash;
return hash;
}


string => identification.fold("")((String start, Annotation annotation) => "``start`` ``annotation``").plus(" ``type``");
string =>"``type`` ``identification``";


}
17 changes: 16 additions & 1 deletion source/herd/depin/api/Identification.ceylon
Original file line number Diff line number Diff line change
@@ -1 +1,16 @@
shared alias Identification=> {Annotation*};
shared class Identification(shared Annotation* annotations){


shared actual Boolean equals(Object that) {
if (is Identification that) {
return annotations.containsEvery(that.annotations);
}
else {
return false;
}
}

shared actual Integer hash => annotations.hash;

string => annotations.string;
}
6 changes: 4 additions & 2 deletions source/herd/depin/api/Injectable.ceylon
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ import ceylon.language.meta.declaration {
}


shared abstract class Injectable(){
shared abstract class Injectable(Declaration declaration){
throws (`class Error`)
shared formal Anything inject(Provider provider,Resolver resolver);
shared formal Anything inject(Creator injector);



shared class Error(Declaration declaration,Type<> type,Dependency description,Throwable? cause=null)
extends Exception("Can't inject ``declaration`` of type ``type`` described as ``description``",cause){}

string => declaration.string;
}

5 changes: 0 additions & 5 deletions source/herd/depin/api/Injector.ceylon

This file was deleted.

7 changes: 0 additions & 7 deletions source/herd/depin/api/Register.ceylon

This file was deleted.

21 changes: 21 additions & 0 deletions source/herd/depin/engine/DefaultCreator.ceylon
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import herd.depin.api {
Registry,
Creator,
Resolver
}
import ceylon.language.meta.declaration {
Declaration
}
shared class DefaultCreator(Registry registry,Resolver resolver) satisfies Creator{
shared actual Anything create(Declaration declaration) {
value dependency = resolver.resolve(declaration);
if(exists injectable = registry.get(dependency)){
return injectable.inject(this);
}
throw Exception("Dependency [``dependency``] not found in registry did You made a scan ? Available dependencies:\n +``registry``");
}




}
10 changes: 0 additions & 10 deletions source/herd/depin/engine/DefaultInjector.ceylon

This file was deleted.

91 changes: 83 additions & 8 deletions source/herd/depin/engine/DefaultProvider.ceylon
Original file line number Diff line number Diff line change
@@ -1,18 +1,93 @@
import ceylon.language.meta.declaration {
Declaration,
FunctionOrValueDeclaration,
FunctionDeclaration,
ValueDeclaration,
CallableConstructorDeclaration,
ClassDeclaration,
NestableDeclaration,
ConstructorDeclaration,
GenericDeclaration
}

import herd.depin.api {
Provider,
Injectable,
Dependency,
Registry
Registry,
Creator
}
import ceylon.language.meta.model {
Type
shared class DefaultProvider(Registry registry) satisfies Provider{
shared actual Injectable provide(Declaration declaration, Dependency dependency) {
if(is GenericDeclaration declaration,!declaration.typeParameterDeclarations.empty){
throw Exception("Type parameters are not supported yet in dependencies ``declaration``");
}
switch(declaration)
case (is FunctionDeclaration) {
return FunctionInjectable(declaration);
}
case( is ValueDeclaration){
return ValueInjectable(declaration);
}
case (is CallableConstructorDeclaration){
return ConstructorInjectable(declaration);
}
case (is ClassDeclaration){
if(exists defaultConstructor= declaration.defaultConstructor){
return ConstructorInjectable(defaultConstructor);
}
value constructors=declaration.constructorDeclarations().select((ConstructorDeclaration element) => element.annotated<TargetAnnotation>());
if(constructors.size==0){
throw Exception("Can't select injection target, no default constructor or annotated `` `class TargetAnnotation` ``");
}
else if(constructors.size>1){
throw Exception("Can't select injection target, multiple constructors annotated `` `class TargetAnnotation` ``");
}
assert(is CallableConstructorDeclaration targetConstructor=constructors.first);
return ConstructorInjectable(targetConstructor);
}
else{
throw Exception("Declaration ``declaration``not supported ");
}
}

}
import ceylon.language.meta.declaration {
Declaration
class ConstructorInjectable(CallableConstructorDeclaration declaration) extends Injectable(declaration){
shared actual Anything inject(Creator injector) {
value parameters = declaration.parameterDeclarations.collect((FunctionOrValueDeclaration element) => injector.create(element));
if(declaration.container.container is NestableDeclaration){
assert(is Object container = injector.create(declaration.container));
return declaration.memberInvoke(container,[], parameters);
}

return declaration.invoke([],*parameters);
}


}
shared class DefaultProvider(Registry registry) satisfies Provider{
shared actual Injectable provide(Declaration declaration, Dependency dependency) => nothing;
class FunctionInjectable(FunctionDeclaration declaration) extends Injectable(declaration){
shared actual Anything inject(Creator injector) {
value parameters = declaration.parameterDeclarations.collect((FunctionOrValueDeclaration element) => injector.create(element));
if(is NestableDeclaration containerDeclaration=declaration.container){
assert(exists container = injector.create(containerDeclaration));
return declaration.memberInvoke(container,[],parameters);
}else{
return declaration.invoke([],*parameters);
}
}


}
class ValueInjectable(ValueDeclaration declaration) extends Injectable(declaration){
shared actual Anything inject(Creator injector) {
if(is NestableDeclaration containerDeclaration=declaration.container){
assert(exists container = injector.create(containerDeclaration));
return declaration.memberGet(container);
}else{
return declaration.get();
}
}


}

}
11 changes: 5 additions & 6 deletions source/herd/depin/engine/DefaultRegistry.ceylon
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import herd.depin.api {
Registry,
Injectable,
Dependency,
Register
Dependency
}
import ceylon.collection {
MutableMap,
Expand All @@ -15,13 +14,13 @@ import ceylon.language.meta.declaration {
import ceylon.language.meta.model {
Type
}
shared class DefaultRegistry(MutableMap<OpenType,Register> registries= HashMap<OpenType,Register>(),shared actual Type<Annotation>[] controls=[]) satisfies Registry{
shared class DefaultRegistry(shared actual Type<Annotation>[] controls=[`NamedAnnotation`],MutableMap<OpenType,Register> registries= HashMap<OpenType,Register>()) satisfies Registry{
shared actual Injectable? add(Dependency description, Injectable injectable) {
value get = registries.get(description.type);
if (exists get) {
return get.add(description,injectable);
}
value register=DefaultRegister();
value register=Register();
registries.put(description.type,register);
return register.add(description, injectable);

Expand All @@ -33,9 +32,9 @@ shared class DefaultRegistry(MutableMap<OpenType,Register> registries= HashMap<O
if (exists get = registries.get(description.type)) {
return get.get(description);
}
value newRegister=DefaultRegister();
value newRegister=Register();
registries.put(description.type,newRegister);
return null;
}

string => registries.fold("")((String initial, OpenType type -> Register register) => initial + "``type``: ``register``\n\r" );
}
27 changes: 24 additions & 3 deletions source/herd/depin/engine/DefaultResolver.ceylon
Original file line number Diff line number Diff line change
@@ -1,14 +1,35 @@
import herd.depin.api {
Resolver,
Dependency,
Registry
Registry,
Identification
}
import ceylon.language.meta.declaration {
Declaration
Declaration,
AnnotatedDeclaration,
TypedDeclaration
}
import ceylon.language.meta {
type
}


shared class DefaultResolver(Registry registry) satisfies Resolver{
shared actual Dependency resolve(Declaration declaration) => nothing;
shared actual Dependency resolve(Declaration declaration) {
if(is TypedDeclaration&AnnotatedDeclaration declaration){

value annotations = declaration.annotations<Annotation>()
.select((Annotation element) => registry.controls.contains(type(element)));
return Dependency{
type = declaration.openType;
identification = if (annotations.empty && registry.controls.contains(`NamedAnnotation`))
then Identification(NamedAnnotation(declaration.name))
else Identification(*annotations);

};
}
throw Exception("``declaration`` not supported");
}


}
35 changes: 14 additions & 21 deletions source/herd/depin/engine/DefaultScanner.ceylon
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import herd.depin.api {
Scope,
Scanner,
Registry
Dependency
}
import ceylon.language.meta.declaration {
Declaration,
Expand All @@ -13,37 +13,30 @@ import ceylon.language.meta.declaration {
}

shared class DefaultScanner() extends Scanner() {
{Declaration*} single(Scope element) {
switch(element)

{Declaration*} single(Scope element) {
switch (element)
case (is ClassDeclaration) {
return element.constructorDeclarations()
.filter((ConstructorDeclaration element) => !element.annotations<TargetAnnotation>().empty)
.chain(element.memberDeclarations<FunctionOrValueDeclaration>().flatMap((FunctionOrValueDeclaration element) => single(element)));
return (if (element.annotated<DependencyAnnotation>()) then { element }
else element.constructorDeclarations().filter((ConstructorDeclaration element) => element.annotated<DependencyAnnotation>()))
.chain(element.memberDeclarations<ClassDeclaration|FunctionOrValueDeclaration>()
.flatMap((Scope element) => single(element)));
}
case (is FunctionOrValueDeclaration){
value annotations = element.annotations<DependencyAnnotation>();
if(!annotations.empty){
return {element};
}
return empty;
case (is FunctionOrValueDeclaration) {
return if (element.annotated<DependencyAnnotation>()) then { element } else empty;
}
case (is Package){
case (is Package) {
return element.members<ClassDeclaration|FunctionOrValueDeclaration>()
.flatMap((ClassDeclaration|FunctionOrValueDeclaration element) => single(element));
.flatMap((Scope element) => single(element));
}
case (is Module){
case (is Module) {
return element.members.flatMap((Package element) => single(element));
}
}


shared actual {Declaration*} scan({Scope*} inclusions, {Scope*} exclusions) {
value excluded = exclusions.flatMap((Scope element) => single(element)).sequence();
return inclusions.flatMap((Scope element) => single(element))
.filter((Declaration element) => !excluded.contains(element));
}



}
}
Loading

0 comments on commit 6554624

Please sign in to comment.