Por ejemplo el código siguiente: (mktime y local da igual, he estado
probando con mktime asà que lo dejo, sorry).
Time.mktime(2,2) => No peta
Time.mktime(2,“feb”) => Tampoco peta
Time.mktime(2,‘2’) => No peta
Time.mktime(2,“Febrero”) => PETA, se esperan 3 caracteres
correspondientes
al mes.
Time.mktime(2,“xxx”) => No le gusta el porno asà que vuelve a petar. xxx
no
es un mes válido.
class Mes
def to_s
“feb”
end
def to_i
2
end
end
Time.mktime(2,Mes.new) => Peta. Quiere String o Integer, pero no cosas
raras.
Time.mktime(2,Mes.new.to_i) = Funciona
Time.mktime(2,Mes.new.to_s) = Funciona
class Mes
def to_str
to_s
end
end
Time.mktime(2,Mes.new.to_i) => Funciona
Time.mktime(2,Mes.new.to_s) => Funciona
Time.mktime(2,Mes.new) => Se arma la gorda. Crees que es Mes es un
String
(inocente…), y claro empieza a tocar las cosas internas de Mes como si
este fuese un String.
A fines prácticos, da igual que fuese una clase Mes o una clase Integer,
ya
que lo primero que comprueba es si es un String, viendo si existen el
atributo to_str.
¿Por qué pasa esto?
El problema está como dices en la linea 352, cuando dice.
strcasecmp(months[i], RSTRING(v[1])->ptr) == 0) {
RSTRING(v[1])->ptr
que significa
struct RString v[1]->ptr
EstarÃamos intentando meter por moldeado un (lo que sea que responde a
to_str) en un molde para RString.
Obviamente nuestro Objeto, no tiene el puntero ptr (a la cadena de
caracteres), o si lo tiene, igual no lo tiene en la misma posición y ni
el
mismo contenido. Que pasa, que vete tu a saber a que cacho de memoria le
habrá mandando vete tu a saber que puntero.
Si seguimos investigando, la función de time.c time_arg, hará esto, por
que
piensa que le estamos pasando un string… ¿Pero por que piensa eso? AhÃ
tenemos que irnos a rb_check_string_type, definida en string.c. Esta
función
devuelve NIL o NULL, en caso de que no sea un string. Esta función llama
a
la genérica (Que putada el DRY en estos momentos coño)
rb_check_conver_type(str, T_STRING, “String”, “to_str”);
Ahora bien sigues bajando el nivel y llegas hasta rb_obj_respond_to (en
eval.c) , y por lo que veo se queda en que si responde a to_str es una
string.
Aquà el bug ( A mi juicio en toda regla), está donde indicas, ya que se
comprueba que responde a str, pero no se afirma que es una STRING.
Es decir, que ruby alegremente piensa que todo lo que responde a to_str
es
un string.
Ahora ya entra los patrones que se hayan seguido de diseño para saber
donde
está el error, y la verdad es la primera vez que miro el código de ruby
y de
un lenguaje de programación asà que paso de intentar hacer un parche,
por
que no sabrÃa donde parchear.
Puede pasar dos cosas:
a) La implementación de time_arg está incorrecta. En este caso, se
interpreta que rb_check_string_type, indica si es capaz de responder a
to_str y no indica que es un String.
b)La implementación de rb_check_string_type es incorrecta, ya que solo
chequea si responde a to_str.
c)Somos unos bocazas y to_str es un palabro reservado solo para strings.
Asà que si hay alguien que sepa algo más al respecto, que se plantee
hacer
un patch de verdad.
Notas: He estado usando los sources de ruby-1.8.6