class Klass
annotation Test; end
@[Test(val: 1)]
@[Test(val: 2)]
property test : Int32?
def get
{% for ivar in @type.instance_vars %}
pp {{ivar.annotation(Test).stringify}} #= => "@[Test(val: 2)]"
{% end %}
end
end
Klass.new.get
Currently the .annotation method returns the last defined annotation of that type. However there are cases where there could be multiple annotations of the same type on a property/method, but with different values. For example:
@[Athena::Routing::Get(path: "users/:id/posts/:post_id")]
@[Athena::Routing::ParamConverter(param: "user", type: User, converter: Exists)]
@[Athena::Routing::ParamConverter(param: "post", type: Post, converter: Exists)]
def self.get_user(user : User, post : Post) : String
"User_id: #{user.id}....Post_id: #{post.id}"
end
Currently this isn't possible since the last ParamConverter would override the first.
I propose a new method be added annotations(Type) which would return all of the annotations defined, not just the last. The current annotation method could be altered to just return the last annotation from the array to maintain current behavior.
I'd be happy to give this a shot, but some hints of what would need to be done would be nice :)
I think it's a good idea. In C# annotations can have multiplicity. In Crystal we could always store all of them and have annotation(...) return the last one, and annotations(...) return all of them.
Also in C# annotations are annotated with expected target and multiplicity. And give compiler time errors if are wrongly applied.
GetCustomAttribute,GetCustomAttributes is the API used there, so I think annotation/annotations is a good design.
Most helpful comment
Also in C# annotations are annotated with expected target and multiplicity. And give compiler time errors if are wrongly applied.
GetCustomAttribute,GetCustomAttributesis the API used there, so I thinkannotation/annotationsis a good design.