使用动态对象组配置gradle插件扩展的正确方法 [英] Correct way to configure gradle plugin extensions with groups of dynamic objects

查看:197
本文介绍了使用动态对象组配置gradle插件扩展的正确方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写我自己的gradle插件,它需要能够配置一组对象 - 这些对象中的多少以及它们被称为是由用户决定的。

I am trying to write my own gradle plugin and it needs to be able to configure a set of objects - how many of these objects and what they're called is up to the user.

用于创建具有高级自定义功能的定制gradle插件的doco相当糟糕。它提到 project.container()方法来做这种事情,但我不知道如何使它在我的用例中工作。

The doco for creating custom gradle plugins with advanced customisability is quite poor. It mentions project.container() method to do this kind of thing, but I couldn't figure out how to make it work in my usecase.

这是我插件配置DSL的一个示例,它代表着:

This is an example of my plugin's configuration DSL as it stands:

teregrin {
  terraformVersion = '0.6.6'

  root("dev"){
    accessKey = "flobble"
  }

  root("prd"){
  }
}

这是我的插件扩展对象允许我配置它:

And this is my plugin extension object that allows me to configure it:

class TeregrinPluginExtension {
  boolean debug = false
  boolean forceUnzip = false
  String terraformVersion = null

  Set<TeregrinRoot> roots = []

  def root(String name, Closure c){
    def newRoot = new TeregrinRoot(name)
    c.setDelegate(newRoot)
    c()
    roots << newRoot
  }

}

插件以标准方式:

The extensions wired up in my plugin in the standard way:

 project.extensions.create("teregrin", TeregrinPluginExtension)

这很好,但是它的配置风格非常丑,并不像典型的gradle DSL那样。

This works ok, but it's a pretty ugly configuration style, not really in the style of the typical gradle DSL.

如何将我的插件配置DSL更改为如下所示:

How can I change my plugin configuration DSL to be something like this:

teregrin {
  terraformVersion = '0.6.6'

  roots {
    dev {
      accessKey = "flobble"
    }

    prd {
    }
  }
}


推荐答案

实现这种DSL的gradle方法是使用扩展 containers

The gradle way of implementing such DSL is by using extensions and containers:

apply plugin: SamplePlugin

whatever {
  whateverVersion = '0.6.6'
  conf {
    dev {}
    qa {}
    prod {
      accessKey = 'prod'
    }
  }
}

task printWhatever << {
  println whatever.whateverVersion
  whatever.conf.each { c ->
    println "$c.name -> $c.accessKey"
  }
}

class SamplePlugin implements Plugin<Project> {
  void apply(Project project) {
    project.extensions.create('whatever', SampleWhatever)
    project.whatever.extensions.conf = project.container(SampleConf)
    project.whatever.conf.all {
      accessKey = 'dev'
    }
  }
}

class SampleWhatever {
  String whateverVersion
}

class SampleConf {
  final String name
  String accessKey

  SampleConf(String name) {
    this.name = name
  }
}

实现此类DSL的常规方式是元编程 - 在这种特殊情况下,您需要实现 methodMissing 。下面是一个非常简单的例子,演示了它是如何工作的:

while groovy way of doing implementing such DSL is meta programming - you need to implement methodMissing in this particular case. Below is a very simple example that demonstrates how it works:

class SomeExtension {
  def devConf = new SomeExtensionConf()

  void methodMissing(String name, args) {

    if ('dev'.equals(name)) {
        def c = args[0]
        c.resolveStrategy = Closure.DELEGATE_FIRST
        c.delegate = devConf
        c()
    } else {
      throw new MissingMethodException("Could not find $name method")
    }
  }

  def getDev() {
    devConf
  }
}

class SomeExtensionConf {
  def accessKey
}

project.extensions.create('some', SomeExtension)

some {
  dev {
    accessKey = 'lol'
  }
}

assert 'lol'.equals(some.dev.accessKey)

当然,它没有错误检查 - 所以需要验证每个参数的大小和类型 args - 它被忽略为了 为了简洁起见。

Of course it has no error checking - so the args size and type of each argument need to be validated - it's omitted for the sake of brevity.

当然,不需要为每个配置创建一个单独的类(我的意思是 dev prod 等)。创建一个保存配置的类,并将它们全部存储在 Map 中,其中键是配置名称。

Of course there's no need to create a separate class for each configuration (I mean dev, prod, etc.). Create a single class that holds configuration and store them all in a Map where key is configuration name.

您可以此处

这篇关于使用动态对象组配置gradle插件扩展的正确方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆