Groovy 2.0 принес нам модули расширения. Модуль расширения представляет собой файл JAR с классами, которые предоставляют дополнительные методы для существующих других классов, таких как JDK или сторонние библиотеки. Groovy использует этот механизм для добавления, например, дополнительных методов в Fileкласс. Мы можем реализовать наш собственный модуль расширения для добавления новых методов расширения в существующие классы. После того, как мы написали модуль, мы можем добавить его в путь к классам нашего кода или приложения, и все новые методы будут сразу же доступны.
Мы определяем новые методы расширения в вспомогательных классах, которые являются частью модуля. Мы можем создавать экземпляры и статические методы расширения, но нам нужен отдельный вспомогательный класс для каждого типа метода расширения. Мы не можем смешивать статические и методы расширения экземпляра в одном вспомогательном классе. Сначала мы создаем очень простой класс с методом расширения для Stringкласса. Первый аргумент метода расширения определяет тип или класс, к которому мы хотим добавить метод. Следующий код показывает метод likeAPirate. Метод расширения должен быть, publicи staticхотя мы создаем метод расширения экземпляра.
// File: src/main/groovy/com/mrhaki/groovy/PirateExtension.groovy
package com.mrhaki.groovy
class PirateExtension {
static String likeAPirate(final String self) {
// List of pirate language translations.
def translations = [
["hello", "ahoy"], ["Hi", "Yo-ho-ho"],
['are', 'be'], ['am', 'be'], ['is', 'be'],
['the', "th'"], ['you', 'ye'], ['your', 'yer'],
['of', "o'"]
]
// Translate the original String to a
// pirate language String.
String result = self
translations.each { translate ->
result = result.replaceAll(translate[0], translate[1])
}
result
}
}
Далее нам нужно создать файл дескриптора модуля расширения. В этом файле мы определяем имя вспомогательного класса, поэтому Groovy будет знать, как его использовать. Файл дескриптора должен быть размещен в META-INF/servicesкаталоге нашего архива модуля или пути к классам. Имя файла есть org.codehaus.groovy.runtime.ExtensionModule. В файле мы определяем имя нашего модуля, версию и имя вспомогательного класса. Имя вспомогательного класса определяется с помощью свойства extensionClasses:
# File: src/main/resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule moduleName = pirate-module moduleVersion = 1.0 extensionClasses = com.mrhaki.groovy.PirateExtension
Теперь модуль расширения готов. Самый простой способ распространения модуля — это упаковать файл кода и дескриптора в файл JAR и поместить его в менеджер репозитория артефактов. Затем другие разработчики могут использовать инструменты сборки, такие как Gradle или Maven, чтобы включить модуль расширения в свои проекты и приложения. Если мы используем Gradle для создания JAR-файла, нам нужен только этот небольшой скрипт сборки:
/ File: build.gradle
apply plugin: 'groovy'
repositories.mavenCentral()
dependencies {
// Since Gradle 1.4 we don't use the groovy configuration
// to define dependencies. We can simply use the
// compile and testCompile configurations.
compile 'org.codehaus.groovy:groovy-all:2.0.6'
}
Теперь мы можем вызвать $ gradle buildи получили модуль расширения.
Давайте добавим тест для нашего нового метода расширения. Поскольку мы используем Gradle, тестовый путь к классам уже будет содержать вспомогательный класс нашего модуля расширения и файл дескриптора. В нашем тесте мы можем просто вызвать метод и проверить результаты. Мы собираемся использовать Спока, чтобы написать простую спецификацию:
// File: src/test/groovy/com/mrhaki/groovy/PirateExtensionSpec.groovy
package com.mrhaki.groovy
import spock.lang.Specification
class PirateExtensionSpec extends Specification {
def "likeAPirate method should work as instance method on a String value"() {
given:
final String originalText = "Hi, Groovy is the greatest language of the JVM."
expect:
originalText.likeAPirate() == "Yo-ho-ho, Groovy be th' greatest language o' th' JVM."
}
}
Мы добавляем зависимость к Споку в нашем файле сборки Gradle:
/ File: build.gradle
apply plugin: 'groovy'
repositories.mavenCentral()
dependencies {
// Since Gradle 1.4 we don't use the groovy configuration
// to define dependencies. We can simply use the
// compile and testCompile configurations.
compile 'org.codehaus.groovy:groovy-all:2.0.6'
testCompile 'org.spockframework:spock-core:0.7-groovy-2.0'
}
Мы можем запустить $ gradle testдля запуска спецификации Spock и протестировать наш новый метод расширения.
Чтобы добавить статический метод в существующий класс, нам нужно добавить дополнительный вспомогательный класс в наш модуль расширения и дополнительное свойство в наш файл дескриптора для регистрации вспомогательного класса. Первый аргумент метода расширения определяет тип, к которому мы хотим добавить статический метод. В следующем вспомогательном классе мы добавляем talkLikeAPirate()в Stringкласс метод расширения .
/ File: src/main/groovy/com/mrhaki/groovy/PirateStaticExtension.groovy
package com.mrhaki.groovy
class PirateStaticExtension {
static String talkLikeAPirate(final String type) {
"Arr, me hearty,"
}
Мы изменим файл дескриптора и добавим staticExtensionClassesсвойство:
# File: src/main/resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule moduleName = pirate-module moduleVersion = 1.0 extensionClasses = com.mrhaki.groovy.PirateExtension staticExtensionClasses = com.mrhaki.groovy.PirateStaticExtension
В нашей спецификации Spock мы добавляем дополнительный тест для нашего нового статического метода talkLikeAPirate()в Stringклассе:
// File: src/test/groovy/com/mrhaki/groovy/PirateExtensionSpec.groovy
package com.mrhaki.groovy
import spock.lang.Specification
class PirateExtensionSpec extends Specification {
def "likeAPirate method should work as instance method on a String value"() {
given:
final String originalText = "Hi, Groovy is the greatest language of the JVM."
expect:
originalText.likeAPirate() == "Yo-ho-ho, Groovy be th' greatest language o' th' JVM."
}
def "talkLikeAPirate method should work as static method on String class"() {
expect:
"Arr, me hearty, Groovy rocks!" == String.talkLikeAPirate() + " Groovy rocks!"
}
}
Написано с Groovy 2.1