Echemos un vistazo a cómo funciona la asignación constante internamente. El código que sigue se extrae de una fuente tarball de ruby-1.9.3-p0. En primer lugar nos fijamos en la definición de la instrucción VM setconstant
(que se utiliza para asignar constantes):
# /insns.def, line 239
DEFINE_INSN
setconstant
(ID id)
(VALUE val, VALUE cbase)
()
{
vm_check_if_namespace(cbase);
rb_const_set(cbase, id, val);
INC_VM_STATE_VERSION();
}
No hay posibilidad de colocar un gancho en vm_check_if_namespace
o INC_VM_STATE_VERSION
aquí. Así que nos fijamos en rb_const_set
(variable.c: 1886), la función que se llama cada vez que se asigna una constante:
# /variable.c, line 1886
void
rb_const_set(VALUE klass, ID id, VALUE val)
{
rb_const_entry_t *ce;
VALUE visibility = CONST_PUBLIC;
# ...
check_before_mod_set(klass, id, val, "constant");
if (!RCLASS_CONST_TBL(klass)) {
RCLASS_CONST_TBL(klass) = st_init_numtable();
}
else {
# [snip], won't be called on first assignment
}
rb_vm_change_state();
ce = ALLOC(rb_const_entry_t);
ce->flag = (rb_const_flag_t)visibility;
ce->value = val;
st_insert(RCLASS_CONST_TBL(klass), (st_data_t)id, (st_data_t)ce);
}
me quita todo el código que ni siquiera se llama la primera vez que se asigna una constante dentro de un modulo Luego busqué en todas las funciones llamadas por este y no encontré un solo punto donde podríamos colocar un gancho del código de Ruby. Esto significa que la verdad es que, a menos que me haya perdido algo, hay no forma de enganchar una asignación constante (al menos en MRI).
actualización
Para aclarar: La clase anónima hace no mágicamente obtener un nuevo nombre tan pronto como se asigna (como se indica correctamente en la respuesta de Andrew). Por el contrario, el nombre de la constante junto con el ID del objeto de la clase se almacena en la tabla de búsqueda constante interna de Ruby. Si, después de eso, se solicita el nombre de la clase, ahora se puede resolver con un nombre propio (y no solo con Class:0xXXXXXXXX...
).
Así que lo mejor que puede hacer para reaccionar a esta asignación es comprobar la name
de la clase en un bucle de un subproceso de trabajo de fondo hasta que no es nil
(que es un enorme desperdicio de recursos, en mi humilde opinión).
Pregunta muy interesante. –
AFAIK todavía no hay enganche para asignaciones variables, constantes o de otra manera ([ver aquí la misma pregunta hace mucho tiempo] (http://www.ruby-forum.com/topic/65720)). Globales, sí. –