Bueno, continuando con mi anterior post , hoy nos meteremos de lleno en el código del robot, y cómo manipular todas las posibilidades de un Wave.
Si hacemos un poco de memoria en el anterior post hablamos de definir qué eventos escuchamos y qué funciones llama cuando se da ése evento :
facey.RegisterHandler(events.WAVELET_PARTICIPANTS_CHANGED, OnParticipantsChanged) facey.RegisterHandler(events.WAVELET_SELF_ADDED, OnRobotAdded) facey.RegisterHandler(events.BLIP_SUBMITTED, OnBlipSubmit)
Vemos que los eventos a escuchar en éste caso son 1) cuando los participantes cambian, 2) cuando el robot se añade al Wave y 3) cuando alguien escribe un blip (texto).
Vamos a ver primero el evento que pasa antes, cuando añadimos el robot a un Wave se llama la función OnRobotAdded:
def OnRobotAdded(properties, context):
"""El robot ha sido añadido."""
root_wavelet = context.GetRootWavelet()
root_wavelet.CreateBlip().GetDocument().SetText("Hi I'm Lasty, if you have a Last.fm account you can type 'YourLastFMUser-is-listening' and I will tell you what song are you listening! Example Beldar-is-listening")
Debemos tener claro la estructura de un Wave: está formado de Wavelets (agrupación de blips) y de Blips que son el texto que escribimos, pero en todo Wave hay un Wavelet raíz, que es el que tendremos que conseguir para añadir un nuevo blip al final del resto.
Así pues vemos que en la línea 3 conseguimos el Wavelet raíz, y a continuación creamos un nuevo blip e insertamos un texto dentro, en éste caso, cuál es la función del robot y cómo se usa.
Hemos visto un ejemplo muy sencillo de cómo crear un blip e insertar texto dentro, pero algo que debéis saber es que las conversaciones en Wave se envían y guardan en XML puro, por lo que hay una separación total de contenido y formato, es decir se guarda el texto pero no si es un link, está en negrita o qué tamaño tiene, eso se hace mediante las Annotations (anotaciones).
Ahora mismo están muy limitadas las opciones de formato en Wave, ya que se basan en su editor de texto WYSIWYG y siguen unas opciones un tanto extrañas, así como la forma de aplicar un estilo en el editor es seleccionar el texto y darle al botón de negrita, para hacerlo vía código tenemos que hacerlo de la misma forma, definiendo el rango de texto al que queremos aplicar estilo.
Como expliqué en el anterior artículo tenemos que importar el objeto Range para usarlo:
from waveapi.document import Range
La forma de aplicar una Anotación es un poco incómoda porqué siempre debemos saber el tamaño del string que queremos transformar, tomaremos por ejemplo el blip que genera el robotito Lasty, que tiene ésta pinta:
Como vemos haremos un repaso a cómo insertar negritas, diferentes tamaños de letras, links e imágenes.
Explicaré sólo el trozo de código que se refiere a las anotaciones, aunque podéis ver el código completo en Google Code que intento mantener actualizado.
Como he dicho, en el XML del Wave no se guardan los estilos del texto, pero tampoco las imágenes y otros elementos embebidos, ya que el protocolo de Wave guarda éstas anotaciones como operaciones que el editor aplica una vez cargado el texto, así lo hace en todos los editores y es una de las razones por las cuales se puede dar un intercambio de información a tiempo real tan rápido, ya que no se envía el contenido y el formato por separado, aunque esto signifique hacerle la vida más complicada a los desarrolladores.
Vamos a ver el extracto de código de la función OnBlipSubmit que escucha al evento cuando alguien escribe un nuevo blip:
#0: intro #1: artist, #2: song, #3:album, #4: songlink, #5: albumart
blip = oblip.GetDocument().AppendInlineBlip()
doc = blip.GetDocument()
frase = '\n'+song[2]+'\n'+song[1]+'\n'+song[3]+'\nYou can hear it here\n'
doc.AppendText(song[0])
image = document.Image(song[5])
doc.AppendElement(image)
doc.AppendText(frase)
startpos = 0
stuff = blip.GetDocument()
stuff.SetAnnotation(Range(startpos,20+len(user)), "style/fontWeight", "bold")
startpos += 23+len(user)
logger.debug(song[2])
logger.debug(song[3])
stuff.SetAnnotation(Range(startpos,startpos+len(song[2])), "style/fontSize", "22pt")
startpos += len(song[2])
stuff.SetAnnotation(Range(startpos,startpos+1+len(song[1])), "style/fontSize", "18pt")
startpos += len(song[1])+1
stuff.SetAnnotation(Range(startpos,startpos+2+len(song[3])), "style/fontSize", "16pt")
startpos += len(song[3])+2
stuff.SetAnnotation(Range(startpos,startpos+22), "link/manual", song[4])
startpos += 22
Como podéis ver tenemos el array song que contiene los datos definidos en la línea 0, a partir de éstos datos crearemos el texto, primero a diferencia del ejemplo anterior ahora creamos un Blip Inline, que no es nada más que un blip anidado dentro de otro blip, que tiene la ventaja que se puede minimizar si no quieres verlo.A continuación creamos la frase que irá dentro del blip y luego insertamos la intro que versa “Tal usuario está escuchando:”, entonces insertamos la frase que hemos creado antes.
Ahora que tenemos el texto insertado podemos empezar las Anotaciones, la primera trata de poner negrita a la intro, para eso tenemos que crear un Range que va de 0 a la longitud de la frase “está escuchando:” + la longitud del nick del usuario y como vemos la anotación es un style/fontWeight que definimos como bold.
Las siguientes anotaciones la posición inicial (startpos) y el Range se tiene que ir calculando según la longitud del texto que vayamos tratando, pero la metodología es la misma, podemos ver que las siguientes 3 son cambios de tamaño de fuente (style/fontSize), y al final definimos el link de la misma manera pero definiéndolo como link/manual.
Me he saltado un punto y es el de la inserción de la imagen que se produce en la línea 6 y 7, en la línea 6 creamos la imagen pasándole la URL de la misma y en la línea 7 la insertamos, como vemos el proceso es muy sencillo.
También como veis en las líneas 13 y 14, podemos pintar variables de debug que luego podremos ver en el log en App Engine.
Bueno creo que de momento hasta aquí llega la cosa, si a alguien le interesa saber algo más o tiene dudas dejad un comentario!
Posts relacionados:



#1 por David el 5 de Septiembre de 2009
| Citar
No estaría nada mal crear el mismo ejemplo en Java. Que haga exactamente lo mismo pero mostrando las diferencias (por ejemplo, no hay sistema de Handlers como aquí, lo cual lo considero un atraso, pero bueno, ellos sabrán…)
#2 por shakaran el 28 de Noviembre de 2009
| Citar
Muy buena explicación. Realmente parece bastante sencillo y fácil de hacer en unos pocos pasos. Te felicito por el artículo.