我正在使用
kotlin-dsl
插件用 Kotlin 语言编写一个 Gradle 插件:
plugins {
`kotlin-dsl`
}
我创建了一个插件类和一个扩展:
class MyPlugin : Plugin<Project> {
private lateinit var extension: MyPluginExtension
override fun apply(project: Project) {
extension = project.extensions.create("myPluginExtension")
...
}
}
我的扩展类中有一个中缀函数
foo
:
open class MyPluginExtension {
infix fun String.foo(other: String) {
...
}
}
插件用户应该如何使用我的插件(使用 Kotlin DSL):
plugins {
id("my-plugin")
}
myPluginExtension {
"first" foo "second"
}
我想为使用 Groovy 语言的插件用户提供相同的语法:
myPluginExtension {
'first' foo 'second' // cannot call Kotlin infix function using Groovy
'first'.foo('second') // this is not working too
foo('first', 'second') // ok, but not desired syntax for me
}
我不太了解 Groovy,但我听说它有 扩展方法。如何让我的插件对 Groovy 爱好者来说看起来很酷?
如果不能直接进行函数调用,我相信有一种方法可以用 Groovy 语言创建一个包装器扩展方法来调用 Kotlin 扩展函数。
我发现了一个类似的问题Kotlin function parameter with receiver, called from Groovy,但这并不是我所需要的。
我不熟悉 kotlin,所以,我将参考 java 作为基准
这是 groovy 世界中
String
类的扩展方法:
String.metaClass.foo = { x-> " foo( first:${delegate}, second:${x} ) "}
"aaa".foo "bbb" //returns: foo( first:aaa, second:bbb )
在 java 中,您可以使用大约这段代码来为某些类注册扩展方法:
class MethodFoo extends groovy.lang.Closure{
public MethodFoo(Object owner){
super(owner);
}
Object doCall(String second){
return "foo( first:" + getDelegate() + ", second:" + second + " )";
}
}
//-------------------------------
var mc = GroovySystem.getMetaClassRegistry().getMetaClass(String.class);
Class []argTypes = { String.class };
String methodName = "foo"
if( !mc.hasMetaMethod(methodName, argTypes) ){
//instead of null it could be a reference to a gradle project if you want to access it inside a method with getOwner()
mc.registerInstanceMethod(methodName, new MethodFoo(null));
}
//---- after this point in groovy you can make this call:
"aaa".foo "bbb" //should return: foo( first:aaa, second:bbb )
PS:语法实现还是可以的
"aaa" foo "bbb"
groovy 会将这一行翻译成大致如下代码:
plugin."aaa"( plugin.getProperty("foo") ).getProperty("bbb")
// where plugin."aaa" -> invoke method with name `"aaa"`
只要“aaa”是动态的——您可以在您的插件中实现GroovyObect invokeMethod,它将在任何未知方法调用时被调用
这种方法很棘手但可行。 我懒得用java实现它。这是一个可以在 groovy 控制台中运行的 groovy 代码:
class MethodFoo{
String first
Object getProperty(String name){
println( "foo( first: $first, second: $name )" )
}
}
class Plugin{
MethodFoo getFoo(){
return new MethodFoo()
}
Object invokeMethod(String name, Object args){
if(args.length==1 && args[0] instanceof MethodFoo){
args[0].first = name
return args[0]
}
throw new Exception("method not found: $name")
}
}
new Plugin().with{
"aaa" foo "bbb" //prints: foo( first: aaa, second: bbb )
}