Gastón Ramos

Blog personal

← Volver al blog

Colaborando con Ruby

Recuperado del archivo original de WordPress.

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:

https://rails.lighthouseapp.com/projects/8994/tickets/3475-activesupportmultibytecharsgsub-fails-while-stringgsub-works

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...

También puede interesarte

Los comentarios históricos se conservan como archivo. Para conversar hoy, podés escribirme.