2010-03-22 15 views
40

Estoy aprendiendo a usar class_eval en los módulos (estoy algo familiarizado con class_eval) y me encontré con this helpful class in resource_controller. Allí tienen cosas como esta:¿Qué significa class_eval << - "end_eval", __FILE__, __LINE__ en Ruby?

class_eval <<-"end_eval", __FILE__, __LINE__ 

    def #{block_accessor}(*args, &block) 
    unless args.empty? && block.nil? 
     args.push block if block_given? 
     @#{block_accessor} = [args].flatten 
    end 

    @#{block_accessor} 
    end 

end_eval 

¿Qué __FILE__ y __LINE__ hacer en ese contexto? Sé que __FILE__ hace referencia al archivo actual, pero ¿qué hace exactamente todo eso? Realmente no sé cómo buscar eso :).

Respuesta

50

__FILE__ y __LINE__ son un tipo de constantes dinámicas que contienen el archivo y la línea que se están ejecutando actualmente. Pasarlos aquí permite errores para informar adecuadamente su ubicación.

instance_eval <<-end_eval, __FILE__, __LINE__ 
    def foo 
    a = 123 
    b = :abc 
    a.send b 
    end 
end_eval 

foo 

Cuando se ejecuta este

$ ruby foo.rb 
foo.rb:5:in `send': undefined method `abc' for 123:Fixnum (NoMethodError) 
    from foo.rb:5:in `foo' 
    from foo.rb:11 

Nota que dice el archivo y la línea # 5 a pesar de que era sólo de texto en una eval. Sin esos el archivo/línea de engañar a la salida se vería así:

$ ruby foo.rb 
(eval):5:in `send': undefined method `abc' for 123:Fixnum (NoMethodError) 
    from (eval):5:in `foo' 
    from foo.rb:11 

El seguimiento de la pila simplemente muestra (eval) que no es tan útil.

+1

Podría ser bueno mencionar que usar 'define_method' en su lugar no necesitará este tipo de trucos, más no abrirá vulnerabilidades (ver http://stackoverflow.com/questions/3003328/how-do-i-use-class-eval/3003509#3003509) –

3

El << es el comienzo de un heredoc. Esa línea es el comienzo de una cadena multilínea. La cuerda es evacuada para crear la función. La función class_eval usa __FILE__ y __LINE__ para agregar información de depuración.

+1

Pero, pero, pero ... ¿no es el asistente de golf del campo de la anarquía? ¡Deberías conocer a Ruby como la palma de tu mano! :-D (Ese fue un comentario sobre el mal humor de tu afirmación sobre el comportamiento de 'class_eval'. Si tu intención no era sonar incierta, retiro mi comentario.) –

+0

Jaja ... yo nunca necesitaba esa función porque era demasiados caracteres. –

+0

¿qué tipo de información de depuración? ¿como lo uso? –

2

Observemos también que eval -ling cadenas deben evitarse siempre que sea posible. En su caso particular, en sustitución de #class_eval con #class_exec es posible, y debe preferirse:

class_exec do 
    define_method block_accessor do |*args, &block| 
    unless args.empty? && block.nil? 
     args.push block if block_given? 
     instance_variable_set "@#{block_accessor}", [args].flatten 
    end 
    instance_variable_get "@#{block_accessor}" 
    end 
end