Si no leiste la introducción a pyphiverses, puede ser un buen momento para hacerlo.
Se trata de cuestiones técnicas que a un autor de Ficción Interactiva pueden no interesarle en principio, y no es necesario que las comprenda a nivel profundo, pero si es deseable que se vaya familiarizando con ciertos conceptos y detalles, aunque sea solo de oidas.
A aquéllos que deseen participar en el desarrollo de pyphiverses les será necesario comprender estas interioridades. Se empieza con algo sencillo, no os preocupéis.
Si teneis alguna duda sobre el tema aquí tratado podéis utilizar el hilo en el foro del CAAD enlazado al final de este documento. Os responderemos gustosamente.
Dicho esto, desmontemos attoMOLE...
En palabras de su creador, Zak McKracken:
Zak diseñó attoMOLE para paliar determinadas deficiencias en la gestión de ganchos por parte de Inform, ya que éste utiliza rutinas para ellos. Los problemas de utilizar rutinas se ponían especialmente de manifiesto en la creación de librerías, sobre todo las que utilizan Glk. (La documentación de attoMOLE describe los problemas detalladamente).
Este documento trata la parte del "mecanismo genérico de ganchos" y no sobre Inform o Glk. El concepto de cadena se aprovechará en la creación de acciones en pyphiverses, uso que se detallará en subsiguientes documentos, demostrando su flexibilidad.
La idea de gancho se divide en dos conceptos íntimamente ligados...
En attoMOLE, una función puede interrumpir la ejecución de la cadena en la que se encuentra según el valor que devuelva. Con un parámetro se indica, en el momento de añadirse la función a la cadena, si True ó False, siempre o nunca, dependiendo de una constante.
Puede recibir parámetros extra. Además se permite la inserción dentro de la cadena en una posición determinada, con
Se propone la implementación de una "cadena de responsabilidad compartida" que no contempla dos de las características de attoMOLE. La inserción en puntos intermedios y el paso de parámetros extra a las funciones, ya que no son necesarias o deseables en esta fase del proyecto.
La inserción en puntos intermedios puede provocar "peleas" entre las distintas funciones que se enganchan a la cadena del hook (varias pueden querer ser la primera, la útima, o la enésima), aumentando la complejidad del sistema y generando cierto indeterminismo, cuando aquí se pretende lo contrario. La pelea la gana el último, dentro del orden del código fuente, que solicite una posición.
El paso de parámetros puede ser sustituido por "propiedades" (miembros) de clase cuando sea necesario.
Se amplía la capacidad de comunicación con el exterior, de forma que se pueda obtener información sobre el éxito o fracaso de cada elemento de la cadena más flexiblemente, gracias a la asignación de múltiples posibles valores de devolución (no solo True ó False), lo que permitirá conocer los motivos exactos de parada o continuación.
La clase FunctionContext representa el tipo de objeto de los elementos que se pueden añadir a una cadena. Contiene dos funciones en sus miembros. En Python, una función es un objeto más, y puede "almacenarse" (guardar una referencia de ella) como cualquier otro tipo de dato, en una "variable".
function es una función en Python, que se ejecutará cuando le llegue su turno a lo largo de la ejecución secuencial de la cadena.
check_callback es otra función que devolverá True o False dependiendo de si el valor pasado (el devuelto por .function()) permite la continuación de la ejecución de la cadena o si, por el contrario, detiene la misma. Su existencia permite tener varias situaciones "positivas" y/o "negativas", que en instancias superiores de la aplicación tendrán significados diferentes y concretos. Por ejemplo, no se puede coger un objeto porque pesa mucho, porque el inventario está lleno, porque no es un objeto que se pueda coger, etc... Esta lógica depende del uso concreto de cada cadena y por eso se delega su comprobación a la función .check_callback().
Veamos ahora la clase FunctionChain, que implementa la cadena:
Se utiliza una implementación sencilla, sin utilizar herencias ni declarar la clase de "tipo" callable. Ambas mejoras se dejarán para la implementación definitiva y se omiten aquí por claridad.
La linea if( f_context.check_callback(result) != True ) es la que se encarga de llamar a la función callback de comprobacion check_callback. Si la callback da el visto bueno (devuelve True) la cadena continua. Si no lo da, la cadena se corta, ejecutandose el return False.
Creando un nuevo objeto derivado de FunctionChain, al que se le añaden uno o varios FunctionContext via .append_function_context() podemos definir en la aplicación un hook incluyendo una linea que llame a .run(). Éste nos devolverá True si la cadena se completó o False si se detuvo por algún motivo.
La información sobre la ejecución de cada uno de los elementos de la cadena estará disponible en .rl de la FunctionChain.
En siguientes entregas ejemplificaremos el uso de estas clases.
Hasta entonces, como dijimos al principio, estamos a vuestra disposición, atendiendo dudas y comentarios sobre esta "cadena de responsabilidad compartida" en este hilo del foro del CAAD.
Gracias por la atención prestada. dddddd.-