2010-03-22 14 views
40

Ich lerne, wie man class_eval in Modulen verwendet (ich bin etwas vertraut mit class_eval) und stieß auf this helpful class in resource_controller. Dort haben sie Dinge wie diese:Was bedeutet class_eval << - "end_eval", __FILE__, __LINE__ in 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 

Was bedeutet __FILE__ und __LINE__ in diesem Zusammenhang tun? Ich weiß __FILE__ verweist auf die aktuelle Datei, aber was genau macht das Ganze? Ich weiß nicht wirklich, wie ich danach suchen soll.

Antwort

50

__FILE__ und __LINE__ sind eine Art von dynamischen Konstanten, die die Datei und die Zeile enthalten, die gerade ausgeführt werden. Wenn Sie sie hier eingeben, können Fehler ihren Standort korrekt melden.

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

foo 

Wenn Sie diese laufen

$ 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 

Hinweis sagt, dass es die Datei und Linie 5, obwohl das nur Text in einem eval war. Ohne diese die Datei/Zeile Trick, um die Ausgabe wie folgt aussehen:

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

Der Stack-Trace einfach (eval) zeigt, welche nicht so hilfreich ist.

+1

Es ist vielleicht gut zu erwähnen, dass die Verwendung von 'define_method' stattdessen diese Art von Tricks plus benötigt Es werden keine Sicherheitslücken geöffnet (siehe http://stackoverflow.com/questions/3003328/how-doi-i-use-class-eval/3003509#3003509) –

3

Die << ist der Anfang einer heredoc. Diese Zeile ist der Anfang einer mehrzeiligen Zeichenfolge. Die Zeichenfolge wird ausgewertet, um die Funktion zu erstellen. Die class_eval-Funktion verwendet die __FILE__ und __LINE__, um Debuginformationen hinzuzufügen.

+1

Aber, aber, aber ... sind Sie nicht der Golf-Assistent von Anarchie Golf? Du solltest Ruby wie deine Westentasche kennen! :-D (Das war ein Kommentar zu der Wischei-Waschheit deiner Aussage darüber, was 'class_eval's Verhalten ist. Wenn deine Absicht nicht unsicher klingen sollte, nehme ich meinen Kommentar zurück.) –

+0

Haha ... ich nie brauchte diese Funktion, weil es zu viele Zeichen waren. –

+0

welche Art von Debug-Informationen? Wie benutze ich es? –

2

Bitte beachten Sie, dass eval -ling Saiten wo möglich vermieden werden sollten. In Ihrem Fall ist #class_eval mit #class_exec ersetzen möglich und sollte bevorzugt werden:

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