Creación de builders y
  DSL's con Groovy
    @neodevelop - @synergyj
Agenda
Groovy
Metaprogramación
Builders
DSL
{}
{}
Metaprogramación

•   Programas que escriben
    programas...

•   Soporte para agregar
    métodos y propiedades
    a un...
Meta-object protocol
“Interpreta la semantica de un programa
abierto y extensible. Determina que
significa un programa y qu...
MOP de Groovy
Todos los accesos a los métodos,
propiedades, constructores, operadores,
etc., pueden ser interceptados
El c...
Meta-object Protocol
GroovyObject
 En Groovy se trabaja con 3 tipos de
 objetos:
    POJOs
    POGOs
    Groovy Intercepto...
GroovyObject
package groovy.lang;

public interface GroovyObject {
    Object invokeMethod(String name, Object args);
    ...
MetaClass
public interface MetaClass extends MetaObjectProtocol {
     Object invokeMethod(...);
     Object getProperty(....
Intercepción de métodos - GroovyInterceptable
   // Definamos una clase que implemente GroovyInterceptable
   class ClaseI...
Intercepción de métodos - ExpandoMetaClass
   //Ahora usemos un interceptor en una clase que no es de nosotros
   Float.me...
MOP - Inyección de métodos(Categorías)
  //Definimos la clase que permitira ser la categoria
  class VerificaGramatica{
  ...
MOP - Inyección de métodos(ExpandoMetaClass)


         //Podemos inyectar métodos estaticos
         Integer.metaClass.es...
MOP - Síntesis de métodos(MethodMissing)
    class Persona{
    	   String nombre
    	   Map relaciones = [:]
    	
    	...
MOP - Síntesis de métodos(ExpandoMetaClass)
     import java.text.NumberFormat

     def valoresDeConversion = ['USD':0.07...
Creación dinámica de clases con Expando
  def file = new File("migracion.csv")
  /*
   * Empresa,Nombre,Apellido,Puesto,co...
¿Qué es un
 builder?
Builders
Son DSL’s internos que proveen trabajar facilmente
con ciertos tipos de problemas
De entrada, si tenemos la neces...
Metaprogramación   Builders   BuilderSupport
//Instanciamos un builder
sqlBuilder = new MiSqlBuilder()
//Ejecutamos nuestro builder
sqlBuilder.build{
	 selecciona("cam...
class MiSqlBuilder{
	   def result = new StringWriter()
	   def build(closure){
	   	   closure.delegate = this
	   	   cl...
Lenguajes de dominio específico
DSL
Están enfocados a un cierto tipo de problema
La sintaxis está orientada al negocio(hay
expertos)
No lo usamos para res...
¿Cómo desarrollar un DSL?
 Tipado dinámico y opcional
 La facilidad de usar Scripts
 ExpandoMetaClass
 Closures
 Sobrecarg...
tomar 4.pastillas, de: lsd, en: 12.horas
class Droga {
	   String nombre
	   String toString() { nombre
	   }
}

class CantidadDeDroga {
	   int cantidad
	   Strin...
Referencias
           groovy.codehaus.org
        grails.org.mx - @grailsmx
http://delicious.com/neodevelop/groovy
   Pro...
¡Gracias!
  Q &A
@neodevelop
Creación de Builders y DSL's con Groovy
Creación de Builders y DSL's con Groovy
Creación de Builders y DSL's con Groovy
Upcoming SlideShare
Loading in...5
×

Creación de Builders y DSL's con Groovy

654

Published on

Una breve introducción a la Metaprogramación, sus características y como nos ayudamos de ella para crear Builders y DSL's con Groovy

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
654
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
14
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide































  • Creación de Builders y DSL's con Groovy

    1. 1. Creación de builders y DSL's con Groovy @neodevelop - @synergyj
    2. 2. Agenda Groovy Metaprogramación Builders DSL
    3. 3. {}
    4. 4. {}
    5. 5. Metaprogramación • Programas que escriben programas... • Soporte para agregar métodos y propiedades a un objeto en tiempo de ejecución... • Soporte de intercepción de llamadas, como AOP
    6. 6. Meta-object protocol “Interpreta la semantica de un programa abierto y extensible. Determina que significa un programa y que comportamiento tiene, así también, maneja objetos que manipulan, crean, describen o implementan otros objetos” En Groovy podemos usar el MOP para invocar métodos dinámicamente y sintetizar clases y métodos al vuelo
    7. 7. MOP de Groovy Todos los accesos a los métodos, propiedades, constructores, operadores, etc., pueden ser interceptados El comportamiento en Java esta fuertemente atado al tiempo de compilación, en Groovy, el comportamiento es adaptable en tiempo de ejecución
    8. 8. Meta-object Protocol GroovyObject En Groovy se trabaja con 3 tipos de objetos: POJOs POGOs Groovy Interceptors
    9. 9. GroovyObject package groovy.lang; public interface GroovyObject { Object invokeMethod(String name, Object args); Object getProperty(String propertyName); void setProperty(String propertyName, Object newValue); MetaClass getMetaClass(); void setMetaClass(MetaClass metaClass); }
    10. 10. MetaClass public interface MetaClass extends MetaObjectProtocol { Object invokeMethod(...); Object getProperty(...); void setProperty(...); Object invokeMissingMethod(...); Object invokeMissingProperty(...); Object getAttribute(...); void setAttribute(...); void initialize(); List<MetaProperty> getProperties(); List<MetaMethod> getMethods(); ClassNode getClassNode(); List<MetaMethod> getMetaMethods(); int selectConstructorAndTransformArguments(...); }
    11. 11. Intercepción de métodos - GroovyInterceptable // Definamos una clase que implemente GroovyInterceptable class ClaseInterceptada implements GroovyInterceptable{ def doMetodo(param){ "Hola $param" } //Tenemos que implementar este metodo de la interfaz def invokeMethod(String nombre, args){ System.out.println "Ejecutando el metodo '$nombre' con argumentos '$args'" //Obtenemos el metodo a ejecutar de la clase def metodoValido = ClaseInterceptada.metaClass.getMetaMethod(nombre,args) //Si encontro el metodo a ejecutar... if(metodoValido != null){ //Lo invocamos desde el metodo que encontro metodoValido.invoke(this, args) }else{ //Si no lo encuentra simplemente llamamos al mŽtodo convencionalmente ClaseInterceptada.metaClass.invokeMethod(this, nombre, args) } } } def c = new ClaseInterceptada() println c.doMetodo("@grailsmx")
    12. 12. Intercepción de métodos - ExpandoMetaClass //Ahora usemos un interceptor en una clase que no es de nosotros Float.metaClass.invokeMethod = { String nombre, args -> //Al igual desplegamos algo de informacion System.out.println "Ejecutando el metodo '$nombre' con argumentos '$args'" //Obtenemos el metodo del metaClass def metodoValido = Float.metaClass.getMetaMethod(nombre,args) //Si no existe dicho metodo if(metodoValido == null){ //Entonces regresamos la ejecucion convencional return Float.metaClass.invokeMissingMethod(delegate,nombre,args) } //Invocamos al metodo original con sus parametros resultado = metodoValido.invoke(delegate,args) //Regresamos la ejecucion del metodo resultado } //Usemos los metodos de la clase que no es propietaria println 10F.intValue() println 100F.toString() try{ 50F.empty() }catch(Exception e){ println e.message }
    13. 13. MOP - Inyección de métodos(Categorías) //Definimos la clase que permitira ser la categoria class VerificaGramatica{ //Para que un metodo pueda ser categorizado, debe ser static def static esPalindrome(String frase){ //Implementamos nuestra categoria if(frase == new StringBuilder(frase).reverse().toString()) true else false } } //Con ayuda de la palabra reservada 'use' aplicamos la categoria use(VerificaGramatica){ def frase = "anitalavalatina" println frase.class.name println "Es palindrome?: " + frase.esPalindrome() println frase.class.name }
    14. 14. MOP - Inyección de métodos(ExpandoMetaClass) //Podemos inyectar métodos estaticos Integer.metaClass.esPar = { -> delegate % 2 == 0 } //Probemos nuestro método estatico println "2 es Par? " + 2.esPar() println "3 es Par? " + 3.esPar()
    15. 15. MOP - Síntesis de métodos(MethodMissing) class Persona{ String nombre Map relaciones = [:] def methodMissing(String relacion, personas){ if(relaciones.containsKey(relacion)){ personas.each{ persona -> relaciones.get(relacion).add(persona) } }else{ relaciones.put(relacion,personas as List) } } } def juan = new Persona(nombre:'Juan') juan.trabajaEn("SynergyJ") juan.trabajaCon("Manuel","Jorge") juan.esAmigoDe("Domingo") juan.trabajaCon("Andres") juan.esAmigoDe("George") juan.conoceA("Susana","Perla","Cassandra","Alejandra") println juan.relaciones
    16. 16. MOP - Síntesis de métodos(ExpandoMetaClass) import java.text.NumberFormat def valoresDeConversion = ['USD':0.07973, 'EUR':0.0644, 'GBP':0.0538, 'JPY':7.2361] BigDecimal.metaClass.methodMissing = { String methodName, args -> tipoDeConversion = methodName[2..-1] valorDeConversion = valoresDeConversion[tipoDeConversion] if(valorDeConversion){ NumberFormat nf = NumberFormat.getCurrencyInstance(Locale.US) nf.setCurrency(Currency.getInstance(tipoDeConversion)) return nf.format(delegate * valorDeConversion) } "No hay conversion de Pesos a ${tipoDeConversion}" } println 13.00.enUSD() println 16.00.enEUR() println 1.00.enXYZ()
    17. 17. Creación dinámica de clases con Expando def file = new File("migracion.csv") /* * Empresa,Nombre,Apellido,Puesto,correo... * 42 Claps,CŽsar,Salazar Hern‡ndez,CEO,c@42claps.com... * 4D Hispano,Dominique,Coste,Country Manager,d@4dhispano.com... */ def sql = groovy.sql.Sql.newInstance("jdbc:hsqldb:file:/devDB","sa","","org.hsqldb.jdbcDriver") lines = file.readLines() atributos = lines[0].tokenize(",") //Creaci—n de Expando def persona = new Expando() atributos.each{ //Creando atributos con Expando, tmb se pueden crear mŽtodos persona."${it.toLowerCase()}" = "${it.toLowerCase()}" } def insert = "insert into user(VERSION,PASSWD,ENABLED,USERNAME,EMAIL_SHOW,EMAIL,USER_REAL_NAME) " insert += "values(0,'7c4a8d09ca3762af61e59520943dc26494f8941b',true,?,true,?,?)" lines.each{ line -> valores = line.tokenize(",") index = 0 atributos.each{ persona."${it.toLowerCase()}" = "${valores[index]}" index++ } //Uso de Expando sql.execute(insert,[persona.correo,persona.correo,"${persona.nombre} ${persona.apellido}"]) }
    18. 18. ¿Qué es un builder?
    19. 19. Builders Son DSL’s internos que proveen trabajar facilmente con ciertos tipos de problemas De entrada, si tenemos la necesidad de trabajar con ciertos tipos de estructuras o representaciones, los builders son la mejor opción Proveen una sintaxis que no ata con dicha estructura o implementación Solo son fachadas, por que en realidad no están reemplazando la implementación, solamente proveen una manera elegante de usarla Groovy ya provee algunos, pero podemos hacer los propios
    20. 20. Metaprogramación Builders BuilderSupport
    21. 21. //Instanciamos un builder sqlBuilder = new MiSqlBuilder() //Ejecutamos nuestro builder sqlBuilder.build{ selecciona("campo1","campo2","campo3") tabla("nombreDeTabla") donde("1=1") insertar('tabla',['campo1','campo2','campo3'],['valor1','valor2','valor3']) ultimoInsert }
    22. 22. class MiSqlBuilder{ def result = new StringWriter() def build(closure){ closure.delegate = this closure() println result } def methodMissing(String name,args){ switch(name){ case 'selecciona': result << "nSELECT ${args.join(',')}" break case 'tabla': result << " FROM ${args.join(',')}" break case 'donde': result << " WHERE ${args[0]}n" break case 'insertar': result << "nINSERT INTO ${args[0]}(${args[1].join(',')}) " result << "VALUES('${args[2].join('','')}')n" break } } def propertyMissing(String name){ if(name=="ultimoInsert"){ result << "nSELECT last_insert_id() n" } } }
    23. 23. Lenguajes de dominio específico
    24. 24. DSL Están enfocados a un cierto tipo de problema La sintaxis está orientada al negocio(hay expertos) No lo usamos para resolver problemas de propósito general como lo haría Java Es pequeño, simple, expresivo y enfocado a cierta área Son manejados por el contexto y elocuentes Con ayuda del MOP podemos crear DSL’s
    25. 25. ¿Cómo desarrollar un DSL? Tipado dinámico y opcional La facilidad de usar Scripts ExpandoMetaClass Closures Sobrecarga de operadores Soporte de Builders Work-around de paréntesis
    26. 26. tomar 4.pastillas, de: lsd, en: 12.horas
    27. 27. class Droga { String nombre String toString() { nombre } } class CantidadDeDroga { int cantidad String toString() { cantidad == 1 ? "1 pastilla" : "$cantidad pastillas" } } class TiempoDeDuracion { Number numero String unidad } Integer.metaClass.getPastillas = { -> new CantidadDeDroga(cantidad: delegate) } Number.metaClass.getHoras = { -> new TiempoDeDuracion(numero: delegate, unidad: "horas") } def tomar(Map m, CantidadDeDroga cdd) { println "Tomar $cdd de $m.de en $m.en.numero $m.en.unidad" } def oxicodona = new Droga(nombre: "Oxicodona") def lsd = new Droga(nombre: "LSD") tomar 2.pastillas, de: oxicodona, en: 6.horas tomar 4.pastillas, de: lsd, en: 12.horas
    28. 28. Referencias groovy.codehaus.org grails.org.mx - @grailsmx http://delicious.com/neodevelop/groovy Programming Groovy - Venkat S.
    29. 29. ¡Gracias! Q &A @neodevelop
    1. A particular slide catching your eye?

      Clipping is a handy way to collect important slides you want to go back to later.

    ×