groovy-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Marcin Zajączkowski <msz...@wp.pl>
Subject Re: Smarter Closure delegation detection in annotation parameters
Date Tue, 07 Jan 2020 21:44:13 GMT
On 2020-01-02 17:50, Marcin Zajączkowski wrote:
> Hi,
> 
> TL;TR. I would like to have a way to inform IDE that a passed in an
> annotation Closure's execution is in fact delegated to a specific object
> (type). E.g. "@Requires({ jvm.java11 })" should allow to write "jv" and
> see jvm in IDE (once a delegate has that field/getter).

Having no reply within a few days I assume it is problematic to do that
right now. Therefore, I will narrow down my question.

Do you think it is worth to extend @DelegatesTo to be able use it for
Closures returned from a method:

> public @interface MyRequires {
>   @DelegatesTo(PreconditionContext.class) Class<? extends Closure> value();
> }

to instruct IDE what is a delegate for a Closure placed in an annotation
(and have code completion)?

> @Requires({ jvm.java11 && os.linux })


Marcin



> More detailed version.
> 
> One of the nice features of Spock is an ability to define conditions in
> Closure when test(s) should (not) be executes with @Required/@IgnoreIf.
> 
> @Requires({ isSpecialConditionFulfilled() })
> def "some test"() {}
> 
> The annotation itself is defined as:
> 
> @Retention(RetentionPolicy.RUNTIME)
> @Target({ElementType.TYPE, ElementType.METHOD})
> @ExtensionAnnotation(RequiresExtension.class)
> public @interface Requires {
>   Class<? extends Closure> value();
> }
> 
> Down the line the execution is delegated to PreconditionContext which
> provides convenient methods/objects such as os.linux, jvm.java11, env, etc.
> 
> @Requires({ jvm.java11 && os.linux })
> 
> Unfortunately, there is no code completion as IDE doesn't know about
> that delegation (and jvm, os fields/methods). Groovy 2 introduced
> @DelegatesTo, however it cannot be used with other annotations or methods.
> 
> It can be tricked by creating a static final instance of
> PreconditionContext (it's stateless) somewhere (e.g. in the
> Specification super class), but people has to know to refer it, e.g:
> 
> @Requires({ CTX.jvm.java11 })
> 
> Alternatively, I was thinking about a method in the base Spock class:
> 
>     protected static def ctx(@DelegatesTo(PreconditionContext) Closure
> closure) {
>         closure()
>     }
> 
> which could be referenced as:
> 
>     @Requires({ ctx { jvm.java10Compatible } })
> 
> It works, but again "ctx" has to be referenced on demand.
> 
> The best long-term solution would be to allow to use @DelegatesTo at the
> method level:
> 
> public @interface MyRequires {
>   @DelegatesTo(PreconditionContext.class) Class<? extends Closure> value();
> }
> 
> It would provide code completion out of the box (once IDEs have support
> for that :) ). The second main drawback I see is being not very
> intuitive declaration and limited usage.
> 
> 
> Having Groovy 3.0 on the horizon (with breaking changes postponed to
> Groovy 4) I wonder do you see any elegant solution to deal with the
> aforementioned case in Spock itself (Spock 2 could potentially break
> compatibility if needed) or in Groovy (that potentially could be
> implemented before 3.0-final)?
> 
> Marcin
> 

Mime
View raw message