On Monday, 16 September 2013 at 07:36:13 UTC, simendsjo wrote:
I don't have a full example without adding a lot of code, but
this partial
example might give you the gist of it.
// This is the type that validates
struct matches(string mustMatch)
{
alias re = ctRegex!(mustMatch);
static string[] validate(T)(const ref T t)
{
static if(!isSomeString!T)
static assert(0, "matches only works on strings,
not "~T.stringof);
return match(t, re).empty ? ["no match"] : null;
}
}
// and this is the code that runs all validators for a variable
void validate(alias T)(ref Appender!(string[]) app)
{
static if(isTupleWrapper!T)
{
validate!(T.Head)(app);
validate!(T.Tail)(app);
}
else
{
foreach(memberAttr; getValidaterAttrs!T)
{
foreach(attr; memberAttr.Tail)
{
foreach(msg; attr.validate(T))
if(msg.length)
app.put(msg);
}
}
}
}
// .. And here is some of the plumbing
string[] validate(Vars...)()
{
auto app = appender!(string[])();
validate!Vars(app);
return app.data();
}
// The getMembersAndAttributesWhere are templates in my little
library that isn't released. Uses quite some custom __traits
stuff, but it's basically __traits(getAttributes
template getValidaterAttrs(alias T)
{
alias getValidaterAttrs =
TypeTuple!(getMembersAndAttributesWhere!(T,
isValidationAttr).Elements,
getMembersAndAttributesWhere!(TypeOf!T,
isValidationAttr).Elements);
}
// Well.. Incomplete
template isValidationAttr(alias T)
{
enum isValidationAttr = hasMember!(TypeOf!T, "validate");
}
Can I explicitly specify when I can use attribute? Something like
this:
@attribute("field")
struct matches(string mustMatch)
{
}
string wrongAttribute
{
}
class Foo
{
@matches("[0-9]+")
string someNumber; //OK, it's a field
}
@matches("[0-9]+") //Error, it's a class, not a field
class Bar
{
}
@wrongAttribute //Error, this attribute doesn't exist
class C
{
}