Groovy proporciona el método use
el cual permite aumentar la disponibilidad
de métodos dinámicos utilizando las llamadas categorías.
Categories are a mechanism to extend existing types (even final classes from the JDK or third-party libraries), to add new methods to them.
Véase este ejemplo tomado de MetaProgramming with Groovy I en http://groovy.dzone.com/::
~/Lgroovy/objects$ cat pouncer.groovy class Pouncer { static pounces( Integer self ){ (0..<self).inject("") { s, n -> s += "boing! " } } } use( Pouncer ) { println 3.pounces() } ~/Lgroovy/objects$ groovy pouncer.groovy boing! boing! boing!
The magic part happens in
use( Pouncer ) { println 3.pounces() }
where we use a method available to all objectsuse()
. You can use any class (or a list of classes for that matter) as a parameter foruse()
, the point is that all methods on that class are candidates to be categorized methods if they follow these two rules:
public static
method is a candidate to be a category method
The class is called a Category if all its methods hold these two properties. The methods are called category methods.
The methodpounces()
is added toInteger
because it isstatic
and the first parameter is of typeInteger
.
Thepounces()
method is available only in the scope of theuse()
block, if you try to call it before or after the block you'll get an exception.
Veamos otro ejemplo inspirado en uno tomado del libro de König [1]. Aumentamos las cadenas con una suma y producto similares a los de Perl, de manera que cadenas que contienen números puedan sumarse y multiplicarse directamente, sin necesidad de conversiones explícitas:
~/Lgroovy/objects$ cat -n perlPlus.groovy 1 class PerlPlus { 2 static def plus(String self, String operand) { 3 try { 4 (self.toBigDecimal()+operand.toBigDecimal()).toString() 5 } 6 catch (NumberFormatException e) { 7 (self << operand).toString() 8 } 9 } 10 11 static def multiply(String self, String operand) { 12 try { 13 (self.toBigDecimal()*operand.toBigDecimal()).toString() 14 } 15 catch (NumberFormatException e) { 16 (self * operand.toInteger()).toString() 17 } 18 } 19 } 20 21 use(PerlPlus) { 22 println '1'+'2'*'3' 23 println '3'*'2'+'4' 24 println 'x'+'4' 25 println 'x'*'8' 26 }Este es el resultado de la ejecución:
~/Lgroovy/objects$ groovy perlPlus.groovy 7 10 x4 xxxxxxxx
La categoría DOMCategory nos permite tratar objetos DOM como si fueran arrays y maps de modo que los podemos utilizar en conjunción con el lenguaje de expresiones de caminos Groovy y manejarlos como JavaBeans. Sigue un ejemplo en el que los objetos DOM se manejan como si fueran JavaBeans y son accedidos con expresiones GPath8.1:
~/Lgroovy/objects$ cat -n categories1.groovy 1 import groovy.xml.* 2 3 def html = DOMBuilder.newInstance().html { 4 head { 5 title (class:'mytitle', 'Test') 6 } 7 body { 8 p (class:'mystyle', 'This is a test.') 9 } 10 } 11 12 use (groovy.xml.dom.DOMCategory) { 13 assert html.head.title.text() == 'Test' 14 assert html.body.p.text() == 'This is a test.' 15 assert html.find{ it.tagName == 'body' }.tagName == 'body' 16 assert html.getElementsByTagName('*').grep{ it.'@class' }.size() == 2 17 } 18 19 try { 20 html.head 21 } catch(MissingPropertyException mpe) { 22 println "Categories wear off" 23 }
Véase la sección Groovy Categories en Codehaus.