44 votes

Que signifie class_eval << - "end_eval", __FILE__, __LINE__ en Ruby?

Je suis en train d'apprendre comment utiliser class_eval dans les modules (je suis un peu familiarisé avec class_eval) et suis tombé sur ce utile de classe dans resource_controller. De là, ils ont des choses de ce genre:

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'est - __FILE__ et __LINE__ faire dans ce contexte? Je connais __FILE__ références le fichier en cours, mais ce n'est que tout faire exactement? Ne sais pas vraiment comment rechercher pour ça :).

54voto

Alex Wayne Points 58113

__FILE__ et __LINE__ sont en quelque sorte des constantes dynamiques qui maintiennent le fichier et la ligne actuellement en cours d'exécution. En les passant dans les ici de permettre aux erreurs de rapporter correctement leur emplacement.

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

foo

Lorsque vous exécutez cette

$ 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

Remarque: il dit que le fichier et la ligne n ° 5, même si c'était juste le texte dans un eval. Sans ces le fichier/ligne de tromper la sortie devrait ressembler à ceci:

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

La trace de la pile de montre, tout simplement, (eval) ce qui n'est pas utile.

4voto

Mark Byers Points 318575

Le << est le début d'un hérédoc . Cette ligne est le début d'une chaîne multiligne. La chaîne est évaluée pour créer la fonction. La fonction class_eval utilise __FILE__ et __LINE__ pour ajouter des informations de débogage.

2voto

Boris Stitnicky Points 5409

Notons également que les chaînes eval --ling doivent être évitées autant que possible. Dans votre cas particulier, remplacer #class_eval par #class_exec est possible et devrait être préféré:

 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
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X