Skip to content

Commit

Permalink
Merge pull request #31 from DoclerLabs/develop
Browse files Browse the repository at this point in the history
prepare 0.21.0
  • Loading branch information
aliokan authored May 16, 2017
2 parents 2ed2bd7 + 3bc9c93 commit bbc7f4d
Show file tree
Hide file tree
Showing 4 changed files with 318 additions and 42 deletions.
96 changes: 70 additions & 26 deletions src/hex/annotation/AnnotationReplaceBuilder.hx
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,26 @@ class AnnotationReplaceBuilder
}).array();
}

static function processParam(e:Expr):Expr
public static function processParam(e:Expr):Expr
{
switch(e.expr)
{
case EField(_.expr => EConst(CIdent(i)), str):
return processConst(i, str, e.pos);
return processConst(getId(i, str), processForeignConst.bind(i, str, e.pos), e.pos);
case EField(e, str):
function getPath(expr:Expr):String
{
return switch(expr.expr)
{
case EField(e, str): '${getPath(e)}.$str';
case EConst(CIdent(i)): i;
case _: null;
}
}
var path = getPath(e);
return processConst(getId(path, str), processForeignConst.bind(path, str, e.pos), e.pos);
case EConst(CIdent(i)) if (i != "null"):
return processConst(getLocalId(i), processLocalConst.bind(i, e.pos), e.pos);
case EConst(c):
return e;
case _:
Expand All @@ -63,45 +77,75 @@ class AnnotationReplaceBuilder
}
}

static function processConst(clss:String, field:String, pos:Position):Expr
static inline function getLocalId(field:String):String
{
return getId(Context.getLocalClass().get().name, field);
}

static inline function getId(clss:String, field:String)
{
return '$clss.$field';
}

static function processConst(id:String, findFunc:Void->Expr, pos:Position):Expr
{
if (staticsCache == null)
{
staticsCache = new Map<String, Expr>();
}
var id = '$clss.$field';
if (!staticsCache.exists(id))
{
var statics = Context.getType(clss).getClass().statics.get();
var found = false;
for (stat in statics)
var e = findFunc();
if(e != null)
{
if (stat.isPublic && stat.name == field)
{
found = true;
switch(stat.expr().expr)
{
case TConst(TString(v)):
staticsCache.set(id, macro $v{v});
case TConst(TInt(v)):
staticsCache.set(id, macro $v{v});
case TConst(TBool(v)):
staticsCache.set(id, macro $v{v});

case _:
logger.debug(stat);
Context.error('Unhandled constant type: ${stat}', pos);
}
break;
}
staticsCache.set(id, e);
}
if (!found)
else
{
Context.error('Constant "$id" not found', pos);
}
}
return staticsCache.get(id);
}

static function processLocalConst(field:String, pos:Position):Expr
{
var matchingFields = Context.getBuildFields().filter(function (f) return f.access.indexOf(AStatic) != -1 && f.name == field );
if(matchingFields.length == 1)
{
return switch(matchingFields[0].kind)
{
case FieldType.FVar(ct, e): macro $v{e.getValue()};
case _: null;
}
}
return null;
}

static function processForeignConst(clss:String, field:String, pos:Position):Expr
{
var statics = Context.getType(clss).getClass().statics.get();
for (stat in statics)
{
if (stat.isPublic && stat.name == field)
{
return switch(stat.expr().expr)
{
case TConst(TString(v)):
macro $v{v};
case TConst(TInt(v)):
macro $v{v};
case TConst(TBool(v)):
macro $v{v};
case _:
logger.debug(stat);
Context.error('Unhandled constant type: ${stat}', pos);
null;
}
}
}
return null;
}

}
#end
16 changes: 13 additions & 3 deletions src/hex/annotation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,19 @@ public var injectedOne:String;
Expressions that are already constants wil remain unouched so `@Inject("one")` will stay the same. That also applies for combinations of expressions so `@Inject(MyConstants.NAME_ONE, "two")` changes to `@Inject("one", "two")`

Currently supported values of expressions:
- String
- Bool
- Int
- `String`
- `Bool`
- `Int`

Curretnly supported expressions that will be replaced:
- Constant in current class
- `@Meta(TEST)`
- Constant in different class
- `@Meta(MyClass.TEST)`
- Constant in different class (with reference using FQCN)
- `@Meta(my.pack.MyClass.TEST)`

Note that the only expressions that are replaced are `[public] static var`. Non-static variables are not being searched so they won't be found.

**Important: If used with `IInjectorContainer` the order matters:**

Expand Down
146 changes: 135 additions & 11 deletions test/hex/annotation/AnnotationReplaceTest.hx
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package hex.annotation;
import haxe.rtti.Meta;
import hex.annotation.MockMetadataClass.MockMetadataClassWithFQCN;
import hex.annotation.MockMetadataClass.MockMetadataClassWithInjectorContainerWithFQCN;
import hex.annotation.MockMetadataClass.MockMetadataClassWithInjectorContainerWithLocalVars;
import hex.annotation.MockMetadataClass.MockMetadataClassWithLocalVars;
import hex.di.reflect.ClassDescription;
import hex.di.reflect.FastClassDescriptionProvider;
import hex.di.reflect.PropertyInjection;
import hex.annotation.MockMetadataClass.MockInjectorContainerExtendsMockMetadata;
import hex.annotation.MockMetadataClass.MockMetadataClassWithInjectorContainer;
import hex.unittest.assertion.Assert;

Expand Down Expand Up @@ -46,6 +49,68 @@ class AnnotationReplaceTest
Assert.deepEquals(expectedMeta, meta);
}

@Test("Metadata transformed with FQCN")
public function testMetadataTransformedWithFQCN()
{
var expectedMeta = {
injected_one : {
Inject : [injected_one.n]
},
injected_two : {
Inject : [injected_two.n]
},
injected_optional : {
Inject : [injected_optional.n],
Optional : [injected_optional.o]
},
method : {
PostConstruct : [method.o]
},
methodWithMultipleArgs : {
Inject : [methodWithMultipleArgs.a[0].n, methodWithMultipleArgs.a[1].n]
},
methodWithMultipleArgsMixed : {
Inject : [null, methodWithMultipleArgsMixed.a[1].n]
}
};

var meta = Meta.getFields(MockMetadataClassWithFQCN);

Assert.isNotNull(meta);
Assert.deepEquals(expectedMeta, meta);
}

@Test("Metadata transformed - local vars")
public function testMetadataTransformedLocalVars()
{
var expectedMeta = {
injected_one : {
Inject : [injected_one_local.n]
},
injected_two : {
Inject : [injected_two_local.n]
},
injected_optional : {
Inject : [injected_optional_local.n],
Optional : [injected_optional_local.o]
},
method : {
PostConstruct : [method_local.o]
},
methodWithMultipleArgs : {
Inject : [methodWithMultipleArgs_local.a[0].n, methodWithMultipleArgs_local.a[1].n]
},
methodWithMultipleArgsMixed : {
Inject : [null, methodWithMultipleArgsMixed_local.a[1].n]
}
};

var meta = Meta.getFields(MockMetadataClassWithLocalVars);

Assert.isNotNull(meta);
Assert.deepEquals(expectedMeta, meta);
}

@Test("Class description transformed")
public function testClassDescriptionTransformed()
{
Expand All @@ -54,25 +119,29 @@ class AnnotationReplaceTest

Assert.isNotNull( description, "description should not be null" );

Assert.arrayDeepContainsElementsFrom([injected_optional], description.p);
Assert.arrayDeepContainsElementsFrom(description.p, [injected_optional]);
}

@Test("Class description transformed extends")
public function testClassDescriptionTransformedExtends()
@Test("Class description transformed with local vars")
public function testClassDescriptionTransformedWithLocalVars()
{
var provider = new FastClassDescriptionProvider();
var description = provider.getClassDescription( MockInjectorContainerExtendsMockMetadata );
var description = provider.getClassDescription( MockMetadataClassWithInjectorContainerWithLocalVars );

Assert.isNotNull( description, "description should not be null" );

// Check properties
Assert.arrayDeepContainsElementsFrom([injected_one, injected_two, injected_optional], description.p);
Assert.arrayDeepContainsElementsFrom(description.p, [injected_optional_local]);
}

@Test("Class description transformed with FQCN")
public function testClassDescriptionTransformedWithFQCN()
{
var provider = new FastClassDescriptionProvider();
var description = provider.getClassDescription( MockMetadataClassWithInjectorContainerWithFQCN );

// Check methods
Assert.arrayDeepContainsElementsFrom([methodWithMultipleArgs, methodWithMultipleArgsMixed], description.m);
Assert.isNotNull( description, "description should not be null" );

//Check postConstruct
Assert.arrayDeepContainsElementsFrom([method], description.pc);
Assert.arrayDeepContainsElementsFrom(description.p, [injected_optional]);
}

// Expected reflected data:
Expand Down Expand Up @@ -129,4 +198,59 @@ class AnnotationReplaceTest
o:1
};

//------------ local vars expected values

static var injected_one_local = {
p:"injected_one",
t:"String",
n:"local one",
o:false
};

static var injected_two_local = {
p:"injected_two",
t:"String",
n:"local two",
o:false
};

static var injected_optional_local = {
p:"injected_optional",
t:"String",
n:"local three",
o:true
};


static var methodWithMultipleArgs_local = {
m: "methodWithMultipleArgs",
a: [{
t:"String",
n:"local one",
o:false
},{
t:"String",
n:"local two",
o:false
}]
};
static var methodWithMultipleArgsMixed_local = {
m: "methodWithMultipleArgsMixed",
a:[{
t:"String",
n:"",
o:false
},{
t:"String",
n:"local three",
o:false
}]
};

static var method_local = {
m:"method",
a:[],
o:1
};

}
Loading

0 comments on commit bbc7f4d

Please sign in to comment.