Forum: Rails-ES consulta sobre codigo ¿? :-(

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Javier A. (Guest)
on 2008-11-19 03:03
(Received via mailing list)
Hola a todos los miembros de la lista, hace un par de dias que estoy
analizando un codigo (concretamente de metasploit 3.2) y he llegado a
lib/rex/text.rb. Luego de ver unos cuantos metodos me he trabado en uno
(self.converge_sets), aca se los dejo libre para que lo vean. Lo he
traceado
con NetBeans para ver si lo entendia pero me sigo trabando en la linea
marcado con <---------, las otras partes ya las tengo bastante claras
pero
no puedo entender que utilidad tiene ese bucle while.

Este metodo lo que hace es devolver un string con un tamaño igual a la
cantidad de elementos de sets, agarra cada caracter basandose en el
offsets,
me ha costado un poco analizarla ya que no tengo mucha experiencia con
recursividad pero ya he logrado entender como trabaja. Aunque la linea
que
les marque me esta dando fuertes dolores de cabeza, cualquier ayuda sera
agradecida.

def converge_sets(sets, idx, offsets, length) # :nodoc:
        buf = sets[idx][offsets[idx]].chr

        if (sets[idx + 1])
                buf += converge_sets(sets, idx + 1, offsets, length)
        else

                while (idx >= 0 and ((offsets[idx] = (offsets[idx] + 1)
%
sets[idx].length)) == 0) <-------
                        idx -= 1
                end

                if (idx < 0)
                        raise RuntimeError, "Maximum permutations
reached"
                end
        end

        buf
end

puts converge_sets(["ABCDEFGHIJKLMNOPQRSTUVWXYZ",
"abcdefghijklmnopqrstuvwxyz", "0123456789"],0,[0,0,0],0)
# Esto se puede llamar con sets asi: [Rex::Text::UpperAlpha,
Rex::Text:::LowerAlpha, Rex::Text::Numerals]
# pero lo deje asi para mirarlo mas rapidamente con NetBeans

Antes que nada les doy gracias por su tiempo, y quedo a la espera de una
pronta respuesta. Atentamente Gustavo Javier desde Argentina.

P.D.: Si necesitan algo o no quedo clara la pregunta, diganlo que lo
comentare con mas tiempo.
Juan M. (Guest)
on 2008-11-19 04:26
(Received via mailing list)
Estuve mirando un poco, hay otra función que llama a converge_sets
tantas
veces como 'lenght' le indiques aparte de las veces que se llama
recursivamente. La idea es armar una ensalada de caracteres según las
cadenas que le pasás con 'sets', no?. Lo que ví que hace con offsets,
como
dijiste, es tomar, cuando inicia, el primer caracter de cada cadena de
'sets' y lo acumulla en 'buf', cambia los valores de offsets y asi puede
elegir otros caracteres de la cadena. Si borras la parte 'else' del if,
en
converge_sets, te genera una cadena usando siempre los primeros
caracteres
de las cadenas de 'sets'. Parece que esa parte del while es un algoritmo
de
permutación para mezclar las cadenas.  El array 'offsets' varía por que
se
pasa como copia.
No sé si ayudó en algo, avisá!

Yo lo probé así:

(esto está extraido de
http://metasploit.com/dev/trac/browser/framework3/...)

UpperAlpha   = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
LowerAlpha   = "abcdefghijklmnopqrstuvwxyz"
Numerals     = "0123456789"


def converge_sets(sets, idx, offsets, length) # :nodoc:
        buf = sets[idx][offsets[idx]].chr
        if (sets[idx + 1])
                buf += converge_sets(sets, idx + 1, offsets, length)
        else

                while (idx >= 0 and ((offsets[idx] = (offsets[idx] + 1)
%
sets[idx].length)) == 0)
                        idx -= 1
                end

                if (idx < 0)
                        raise RuntimeError, "Maximum permutations
reached"
                end
        end

        buf
end


def pattern_create(length, sets = [ UpperAlpha, LowerAlpha, Numerals ])
                     buf = ''
                     idx = 0
                     offsets = []

                     sets.length.times { offsets << 0 }

                     until buf.length >= length
                             begin
                                     buf += converge_sets(sets, 0,
offsets,
length)
                             rescue RuntimeError
                                     break
                             end
                     end

                     # Maximum permutations reached, but we need more
data
                     if (buf.length < length)
                             buf = buf * (length / buf.length.to_f).ceil
                     end

                     buf[0,length]
end


pattern_create(1000)



On Tue, Nov 18, 2008 at 11:03 PM, Javier A.
Xavier N. (Guest)
on 2008-11-19 11:03
(Received via mailing list)
On Wed, Nov 19, 2008 at 2:03 AM, Javier A.
<removed_email_address@domain.invalid> wrote:

>                 while (idx >= 0 and ((offsets[idx] = (offsets[idx] + 1) %
> sets[idx].length)) == 0) <-------

Por una parte esta la logica del algoritmo mismo, pero podria ser que
lo que dificulta que entiendas esa condicion es que hay contiene una
asignacion:

   offsets[idx] = ...

Si es el caso, piensa por ejemplo en

   if user = User.find_by_login(params[:login])
     # hay user, y se asigno a la variable "user"
   end

Sucede que en Ruby las asignaciones son expresiones, evaluan al valor
(o array de valores) que es asignado.

Hay gente a la que no le gusta asignar en una condicion porque se
puede deslizar un bug si en realidad querias "==", algunas IDEs lo
marcan como warning. Esta bien. A mi en particular me gusta usarlo por
lo compacto que queda, y Rails lo usa por todas partes.
Juan M. (Guest)
on 2008-11-19 11:24
(Received via mailing list)
Perdón, 'offset' no se pasa como copia. Se pasa como referencia.

2008/11/19 Juan Matías <removed_email_address@domain.invalid>
Javier A. (Guest)
on 2008-11-19 11:39
(Received via mailing list)
Claro, ahi tengo el problema yo, vos decis que se pasa como referencia,
entonces la modificacion que le hago a offsets dentro de converge_sets
queda
accesible desde los otros lados?????.

Y Juan tenias razon con tu suposicion es un metodo que se encarga de
hacer
una permutacion de caracteres indicandoles un tamaño, y cualquier ayuda
o
punto de vista viene bien!

El 19 de noviembre de 2008 6:24, Juan Matías 
<removed_email_address@domain.invalid>
escribió:
Javier A. (Guest)
on 2008-11-19 11:42
(Received via mailing list)
Ah, disculpen que no responda ahora pero me tengo que ir a trabajar.

Otra cosa, mi problema no es con la asignacion, lo que me pasa con ese
while
es que no entiendo para que usa el modulo, ya que al usarlo como esta
ahi
solo seria true (o diferente de nil ;-)) cuando el offsets este
apuntando al
ultimo caracter???

El 19 de noviembre de 2008 6:38, Javier A.
<removed_email_address@domain.invalid>escribió:
Juan M. (Guest)
on 2008-11-19 12:37
(Received via mailing list)
while (idx >= 0 and ((offsets[idx] = (offsets[idx] + 1) %
sets[idx].length)) == 0)
   idx -= 1
end

Ahora sí! , mirá, si probás en una consola:
Suponiendo una cadena de 5 caracteres
>> 1 % 5
=> 1
>> 2 % 5
=> 2
>> 3 % 5
=> 3
>> 4 % 5
=> 4
>> 5 % 5
=> 0

Cuando el valor de 'offsets', en este caso el tercer elemento, alcanza
el
valor igual a la longitud de la tercer cadena lo pone en 0 y pasa al
segundo
elemento del offset, le suma 1 y vuelva a alternar sobre el tercer
elemento
de 'offsets'.

Cadenas             Offsets    Buf+=
ABC, abc, 012    [0,0,0]     Aa0
ABC, abc, 012    [0,0,1]     Aa1
ABC, abc, 012    [0,0,2]     Aa2  #Acá 'offsets[2]' se pone en cero
porque
es el resultado del módulo y suma 1 a offsets[1]
ABC, abc, 012    [0,1,0]     Ab0
ABC, abc, 012    [0,1,1]     Ab1
ABC, abc, 012    [0,1,2]     Ab2  #Acá 'offsets[2]' se pone en cero
porque
es el resultado del módulo y suma 1 a offsets[1]
ABC, abc, 012    [0,2,0]     Ac0
ABC, abc, 012    [0,2,1]     Ac1
ABC, abc, 012    [0,2,2]     Ac2  #Acá 'offsets[2]' se pone en cero
porque
es el resultado del módulo y suma 1 a offsets[1]
etc...etc...

Está muy bueno, y muy simple. Bah, simple, ahora que lo entiendo. Nunca
se
me hubiese ocurrido.


2008/11/19 Javier A. <removed_email_address@domain.invalid>
Javier A. (Guest)
on 2008-11-19 18:36
(Received via mailing list)
ahhhhhhh, ahora si estamos. Hay que decir que al que se le ocurrio ese
codigo no tenia mucho tiempo libre, ejjejeeje. Gracias a todos por su
ayuda!

El 19 de noviembre de 2008 7:36, Juan Matías 
<removed_email_address@domain.invalid>
escribió:
Javier A. (Guest)
on 2008-11-19 19:20
(Received via mailing list)
Consulte en san google y no pude sacarme la ultima duda, perdon si soy
muy
pesado.

Pero Juan, como sabes cuando un mensaje (argumento en C) es mandado por
referencia en vez de por valor. Me refiero al tipico ejemplo del C. que
pasando el argumento como puntero como &variable te permite modificarla.
Como se hace esto con ruby.

En otras palabras como sabes que offsets se paso por referencia???

El 19 de noviembre de 2008 13:35, Javier A.
<removed_email_address@domain.invalid>escribió:
Xavier N. (Guest)
on 2008-11-19 19:40
(Received via mailing list)
2008/11/19 Javier A. <removed_email_address@domain.invalid>:

> Pero Juan, como sabes cuando un mensaje (argumento en C) es mandado por
> referencia en vez de por valor. Me refiero al tipico ejemplo del C. que
> pasando el argumento como puntero como &variable te permite modificarla.
> Como se hace esto con ruby.

Ruby, C y Java solo tienen paso por valor. Perl solo tiene paso por
referencia.

Cuando en C usas & estas pasando un puntero por valor. En Java y en
Ruby uno pasa referencias por valor.
Juan M. (Guest)
on 2008-11-19 20:32
(Received via mailing list)
Se llama referencia por valor como dijo Xavier.  Estás pasando la
instancia
del array y modificándola dentro de otra función, estás tocando la
instancia.

Si!, soy amante de la consola. Ejemplo:

>> def modificar(string); string[3] = '-' ;end
>> a = "123456789"
=> "123456789"
>> modificar(a)
=> "-"
>> a
=> "123-56789"

Que no es lo mismo que:

>> a = "123456789"
>> def modificar(string); string = "123-56789"; end
>> modificar(a)
=> "123-56789"
>> a
=> "123456789"

A esto se refiere Xavier con referencia por valor, no?

Como te dije borré el while y ví que los caracteres no se mezclaban, ahí
recordé esta cuestión de la referencia y la copia.

2008/11/19 Xavier N. <removed_email_address@domain.invalid>
Guillermo Álvarez Fernández (Guest)
on 2008-11-19 21:08
(Received via mailing list)
El 19/11/2008, a las 19:31, Juan Matías
escribió:> Se llama referencia por valor como dijo Xavier.  Estás pasando la
> instancia del array y modificándola dentro de otra función, estás
> tocando la instancia.

Para evitar que una función modifique el valor, se suele usar dup

funcion_que_modifica_variable(variable.dup)

Aunque en ruby no suele ser necesario.
Xavier N. (Guest)
on 2008-11-19 21:40
(Received via mailing list)
2008/11/19 Juan Matías <removed_email_address@domain.invalid>:

>>> a = "123456789"
>>> def modificar(string); string = "123-56789"; end
>>> modificar(a)
> => "123-56789"
>>> a
> => "123456789"
>
> A esto se refiere Xavier con referencia por valor, no?

Exacto.

Al pasar referencias, si el objeto al que apuntan es mutable puede
suceder que el metodo cambie su estado. Pero eso no tiene que ver con
el argot "paso por referencia/valor".

Como las referencias se pasan por valor, lo que no podras hacer es
cambiarle la referencia misma al caller. Es lo que ilustra el segundo
ejemplo.
Javier A. (Guest)
on 2008-11-19 21:43
(Received via mailing list)
Agradezco su ayuda, ya he entendido como viene la cosa.

Bueno, aunque sea por un rato!!!!

Gracias a todos

El 19 de noviembre de 2008 16:40, Xavier N. 
<removed_email_address@domain.invalid>
escribió:
Guillermo Álvarez Fernández (Guest)
on 2008-11-19 22:54
(Received via mailing list)
El 19/11/2008, a las 20:07, Guillermo Álvarez Fernández
escribió:> Para evitar que una función modifique el valor, se suele usar dup
>
> funcion_que_modifica_variable(variable.dup)
>
> Aunque en ruby no suele ser necesario.

Perdón por la tremenda gilipollez que acabo de poner. :-(
Isaac Feliu Pérez (Guest)
on 2008-11-20 18:28
(Received via mailing list)
Buenas gente,

Lanzo un request a los que esteis utilizando gettext en la sala (a
poder ser la 1.93.0) para ver si os ocurre lo mismo que a mi (y os doy
la solución).

Escenario:
- Un modelo con varios campos (pongamos 15)
- Con algunos campos "obligatorios" (validates_presence_of ...)
- Con un formulario normalillo utilizando el helper "error_message_on"
en el template.
- Provad a intentar grabar un registro sin nada rellenado (para que
salten las validaciones)

Contad los segundos que tarda en renderizarse el template con los
errores, si te dá más de 30 segundos, has ganado un gallifante.

En nuestro caso en producción la cosa se lleva 120 segundos en
renderizar.

¡¡¡¡ 120 segundos !!!!!

Cosas del gettext. Si os mirais las vueltas que da para mostrar el
error_message_on os puede pasar algo. (Todavia me estoy recuperando).

Total, si has llegado hasta aqui después de hacer la prueba y te ha
tardado muuuucho en renderizar los errores, puedes buscarte la vida tu
mismo, o aplicar el hack que me acabo de sacar de la manga:


------------ CUT HERE -----------------
module ActiveRecord
   class Errors
     def localize_error_messages(append_field = true) # :nodoc:
       # e.g.) foo field: "%{fn} foo" => "Foo foo", "foo" => "Foo foo".
       return @__errors unless @__errors.nil?
       @__errors = {}
       each {|attr, msg|
         next if msg.nil?
         @__errors[attr] ||= []
         @__errors[attr] << localize_error_message(attr, msg,
append_field)
       }
       @__errors
     end
   end
end
------------ CUT HERE -----------------

Básicamente sobreescribimos el método localize_error_messages de
gettext para que "cachee" el resultado de los errores localizados, si
quereis investigar más y os atreveis a echarle mas mano a gettext, el
pollo está en gettext/active_record.rb, en las lineas 281 a 336 aprox.

Espero vuestras pruebas y comentarios.

Salutaciones,
--
Isaac Feliu
This topic is locked and can not be replied to.