Categorías

Introducción

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 objects use(). You can use any class (or a list of classes for that matter) as a parameter for use(), the point is that all methods on that class are candidates to be categorized methods if they follow these two rules:

The class is called a Category if all its methods hold these two properties. The methods are called category methods.

The method pounces() is added to Integer because it is static and the first parameter is of type Integer.

The pounces() method is available only in the scope of the use() block, if you try to call it before or after the block you'll get an exception.

Cadenas con Conversión Automática a Números

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

DOMCategory

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.



Subsecciones
Casiano Rodríguez León
2010-04-30