Статьи

Условные обозначения Gradle Plugin: Groovy Magic объяснил

Хакергартен в прошлую пятницу имел большой успех. Около 10 человек (не все Canooies !) Не ложились спать поздно и создали плагин Announce для Gradle . В версии 0.9 вы сможете анонсировать события сборки в Twitter , Snarl и сервис уведомлений Ubuntu (извините, пока нет Growl, он скоро появится ). Это было весело, познавательно и энергично, и вы должны зарегистрироваться в Google Group и приехать на следующее мероприятие.

При написании плагина мы ненадолго задержались из-за технических деталей. Руководство пользователяобъясняет, как передать простые параметры плагину, но не объясняет, как вкладывать параметры в замыкание. Например, в плагине анонса вы указываете имя пользователя и пароль Twitter в блоке анонса:

announce {
username 'your-username'
password 'your-password'
}

Оказывается, это легко (просто не задокументировано, но мы скоро это исправим). Вот полная сборка Gradle, которая показывает вам, как это сделать, с подробным объяснением того, как это работает ниже. В качестве примера мы расширим пользовательский плагин Gradle для документации Gradle. Все это можно запустить из командной строки с помощью «gradle hello»:

apply plugin: GreetingPlugin

greet {
message = 'Hi from Gradle'
}

class GreetingPlugin implements Plugin<Project> {
def void apply(Project project) {

project.convention.plugins.greeting = new GreetingPluginConvention()
project.task('hello') << {
println project.convention.plugins.greeting.message
}
}
}

class GreetingPluginConvention {
String message

def greet(Closure closure) {
closure.delegate = this
closure()
}
}

Начиная сверху … в блоке «greet» есть объявление свойства «message». Это гораздо более приятный вариант конфигурации, чем просто использование глобальных переменных сборки, и ваш плагин должен сделать что-то вроде этого. Важно понимать, что это за блок на самом деле и как он работает. В Groovy круглые скобки для вызовов методов являются необязательными, а фигурные скобки объявляют закрытие. Таким образом, этот блок greet на самом деле является вызовом метода с типом «Object greet (Closure)». Чтобы прочитать и перехватить эту переменную сообщения, вы должны где-то объявить и подключить этот метод «Object greet (Closure)» в вашем плагине.

Переходя к объявлению плагина. Конфигурация плагина фиксируется в чем-то, что Gradle называет объектом «Конвенции». Это просто старый Groovy-объект, и в нем нет магии Gradle … все волшебство происходит в стандартном Groovy. Давайте внимательно рассмотрим метод apply ():

def void apply(Project project) {

project.convention.plugins.greeting = new GreetingPluginConvention()
project.task('hello') &lt;&lt; {
println project.convention.plugins.greeting.message
}
}

На этапе настройки (перед выполнением каких-либо целей) вам будет предоставлен
объект
Project , и у этого объекта Project есть
объект
Convention, который содержит карту
всех соглашений проекта . Три части волшебства Groovy: доступ к получателям можно получить с помощью нотации свойств, записи на карте можно получить с помощью точечной нотации, а Map.put можно вызвать со знаком =. Итак, эта строка:

project.convention.plugins.greeting = new GreetingPluginConvention()

Так же, как эквивалент Java:

project.getConvention().getPlugins().put("greeting", new GreetingPluginConvention());

Во время сборки Gradle собирается выполнить скрипт сборки. Каждый раз, когда присваивается неизвестное свойство или вызывается необъявленный метод, Gradle просматривает карту этих плагинов и использует
метод
responseTo, чтобы проверить, принимает ли какое-либо из соглашений плагинов эту переменную. Если это так, то ваш объект конвенции вызывается и эта переменная устанавливается. Gradle заботится о переводе вызова неизвестного метода «Object greet (Closure)» в вызов
вашего объекта соглашения. Все, что вам нужно сделать, это убедиться, что метод greet (Closure) определен правильно:

class GreetingPluginConvention {
String message

def greet(Closure closure) {
closure.delegate = this
closure()
}
}

Теперь вам нужно отправить параметры, объявленные в замыкании, в поля вашего объекта соглашения. Если вы просто попытаетесь выполнить замыкание, то получите красивое исключение PropertyMissingException, поскольку поле «сообщение» нигде не объявлено. Вы можете обойти это, определив поле «message» на вашем объекте, а затем установив «this» делегату замыкания. Groovy метод отправки является гибким (сложным?). У замыканий есть объект-делегат, который будет действовать как своего рода ссылка «this» при выполнении замыкания. Таким образом, поле сообщения находилось вне области действия при создании замыкания, но добавление делегата превращает поле сообщения из объекта соглашения в область действия. Когда замыкание присваивает сообщению значение, оно будет сообщением в вашем объекте Конвенции.Проверьте мой старый пост в блоге Fun with Closuresдля более глубокого объяснения.

Теперь ваш объект конвенции имеет сообщение String, ура! Вы можете сделать что-нибудь интересное с ним, например распечатать его на консоли:

println project.convention.plugins.greeting.message

Или, может быть, у вас есть что-то более интересное для вашего крутого плагина. Будем надеяться.

Кстати, вы можете так же легко объявить переменную настроек. Это эквивалентная реализация apply:

def settings = new GreetingPluginConvention()
project.convention.plugins.greeting = settings
project.task('hello') << {
println settings.message
}

И теперь остался необъяснимый последний кусочек Groovy-магии:

apply plugin: GreetingPlugin

Это тоже просто старый Groovy. Скобки метода являются необязательными. Параметры метода могут быть переданы в виде пар имя-значение. И на литералы класса можно ссылаться без расширения .class. Оператор применения плагина на самом деле является простым скрытым вызовом метода и является вызовом метода apply (Map). Заявление apply может быть написано на Java как:

Map map = new HashMap();
map.put("plugin", GreetingPlugin.class);
apply(map);
 

Отличная магия это хорошо. Спасибо, что нашли время, чтобы понять это. Надеюсь, этот пример попадет в руководство пользователя Gradle в ближайшие несколько дней.

От http://hamletdarcy.blogspot.com/2010/03/gradle-plugin-conventions-groovy-magic.html