您可以将 gradle 构建脚本视为一些代码委托给可以响应方法调用的对象写在其中。
该脚本使用了大量 Groovy 语法糖,因此删除它们,它应该如下所示:
apply( [plugin: 'com.android.application'] );
android({
compileSdkVersion( 21 );
buildToolsVersion( "21.1.2" );
defaultConfig({
applicationId( "com.crittercism" );
minSdkVersion( 15 );
targetSdkVersion( 21 );
versionCode( 5 );
versionName( "5.0" );
});
});
dependencies({
compile( fileTree([dir: 'libs', include: ['*.jar']]) );
});
所以脚本实际上是一堆方法调用:
def apply(Map)
def android(Closure)
def dependencies(Closure)
This android(Closure)
将接收一个闭包并将其中调用的方法委托给一个可以响应这些方法的对象:
def compileSdkVersion(Integer)
def buildToolsVersion(String)
...
鉴于此,我们可以parse脚本,将其委托给某个对象,然后执行它。
委托使用DelegatingBaseScript http://mrhaki.blogspot.com.br/2013/11/groovy-goodness-set-delegating-class.html是一种方法(不确定 Gradle 是否这样做)。这是一个简化的工作版本:
import org.codehaus.groovy.control.CompilerConfiguration
gradleScript = '''
apply plugin: 'com.android.application'
android({
compileSdkVersion( 21 )
buildToolsVersion( "21.1.2" )
})'''
class PocketGradle {
def config = [apply:[]].withDefault { [:] }
def apply(map) {
config.apply << map.plugin
}
def android(Closure closure) {
closure.delegate = new Expando(
compileSdkVersion: { Integer version ->
config.android.compileSdkVersion = version
},
buildToolsVersion : { String version ->
config.android.buildToolsVersion = version
},
)
closure()
}
}
def compiler = new CompilerConfiguration(scriptBaseClass: DelegatingScript.class.name)
shell = new GroovyShell(this.class.classLoader, new Binding(), compiler)
script = shell.parse gradleScript
script.setDelegate( gradle = new PocketGradle() )
script.run()
assert gradle.config == [
apply: ['com.android.application'],
android: [
compileSdkVersion: 21,
buildToolsVersion: '21.1.2'
]
]
您可以执行以下脚本Groovy Web Console https://groovyconsole.appspot.com/script/5670666258874368(单击“在控制台中编辑”,然后单击“执行脚本”)。
大部分语法解释都在DSL部分 http://groovy-lang.org/dsls.html:
- 命令链
Groovy 允许您省略顶级语句的方法调用参数周围的括号。 “命令链”功能扩展了这一点,允许我们链接这种无括号的方法调用,既不需要参数周围有括号,也不需要链接调用之间的点。
还有格罗维ConfigSlurper http://mrhaki.blogspot.com.br/2014/05/groovy-goodness-extend-configslurper.html,但我不确定它是否能达到 Gradle 想要的程度。