Bueno en este post voy a escribir un ayuda memoria (para mí, no para uds. obvio) de cómo enviar un Patch al core Ruby. Existe un documento que explica los pasos generales para enviar un patch al core de ruby que es el "Improving Ruby, Patch by Patch" lo pueden encontrar acá: Improving Ruby, Patch by Patch
Y después hay un mail que escribió Matz que es una lista de cosas a tener en cuenta para facilitarle a los devs las cosas y que el patch se pueda aplicar fácilmente:
Patch writer's guide to submit
Bueno al grano, todo comenzó así: Ayer estaba leyendo la lista de tickets de rails y me encontré con esto:
todo parece indicar que es un bug en activesupport como indica el ticket, pero con un poquito de investigación podemos ver que esto no es así, el problema real está en la lib CGI que viene con la lib Standard de ruby, particularmente el método CGI::escape, veamos: El archivo en cuestión es ruby_1_8/lib/cgi.rb :
# URL-encode a string.
# url_encoded_string = CGI::escape("'Stop!' said Fred")
# # => "%27Stop%21%27+said+Fred"
def CGI::escape(string)
string.gsub(/([^ a-zA-Z0-9_.-]+)/n) do
'%' + $1.unpack('H2' * $1.size).join('%').upcase
end.tr(' ', '+')
end
El error lo tira exactamente cuando intenta hacer $1.size y $1 es nil :
NoMethodError: undefined method `size' for nil:NilClass from /usr/lib/ruby/1.8/cgi.rb:343:in `escape'
Buscando un poco en google encontré que las variables con dolar no funcionan bien en ciertas situaciones cuando se usan con bloques, acá está la prueba y la explicación:
http://www.justskins.com/forums/bug-when-rerouting-string-gsub-with-a-block-using-1-a-52852.html
Explicado esto, ahora hay que resolver el problema, entonces la idea es reemplazar las variables $1 por un argumento en el bloque del código (al menos esa fué mi idea), pienso en un test que pueda reproducir el problema, mmmmm.... dónde creo que archivo de tests para CGI? (dado que no existe ninguno al día de hoy, recuerdo que estoy ruby_1_8), listo creo que tests/cgi/test_cgi.rb es un buen lugar y lo primero que se me ocurre es esto:
require "cgi" require "test/unit"class String alias : old_gsub :gsub def gsub(*args, &block) old_gsub(*args, &block) end end
class TestCGI < Test::Unit::TestCase
def test_escape_should_work_inside_a_block original_string = "An Interview with Criteri…" escaped_string = "An+Interview+with+Criteri%26%238230%3B" assert escaped_string, CGI.escape(original_string) end
end
Corro el test:
make test-all TESTS='-v cgi/test_cgi.rb'
Y el resultado es:
1) Error:
test_escape_should_work_inside_a_block(TestCGI):
NoMethodError: undefined method `size' for nil:NilClass
/home/gramos/srcs/ruby_1_8/lib/old_cgi.rb:343:in `escape'
/home/gramos/srcs/ruby_1_8/test/cgi/test_cgi.rb:9:in `old_gsub'
/home/gramos/srcs/ruby_1_8/test/cgi/test_cgi.rb:9:in `gsub'
/home/gramos/srcs/ruby_1_8/lib/old_cgi.rb:342:in `escape'
/home/gramos/srcs/ruby_1_8/test/cgi/test_cgi.rb:25:in `test_escape_should_work_inside_a_block'
Genial, el problema está representado en el test, ahora el Fix:
# URL-encode a string.
# url_encoded_string = CGI::escape("'Stop!' said Fred")
# # => "%27Stop%21%27+said+Fred"
def CGI::escape(string)
string.gsub(/([^ a-zA-Z0-9_.-]+)/n) do |s|
'%' + s.unpack('H2' * s.size).join('%').upcase
end.tr(' ', '+')
end
Sencillo. Bueno después de esto hice lo mismo para CGI::unescape, con el test y todo. Luego de chequear que todo esté Ok, creé el patch de esta forma:
svn diff > cgi_escape_work_with_blocks_and_avoid_dollars_variables.patch
Y después envié un mail a la lista de ruby-core adjuntando el patch y con una explicación del problema.
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/27198
Ahora hay que esperar para ver si lo aplican...