What does class_eval <<-“end_eval”, __FILE__, __LINE__ mean in Ruby?

前端 未结 3 1436
执笔经年
执笔经年 2020-11-30 20:21

I\'m learning how to use class_eval in modules (I\'m somewhat familiar with class_eval) and came across this helpful class in resource_controller. In there they have things

相关标签:
3条回答
  • 2020-11-30 20:44

    The << is the start of a heredoc. That line is the start of a multiline string. The string is evaled to create the function. The class_eval function uses the __FILE__ and __LINE__ to add debug information.

    0 讨论(0)
  • 2020-11-30 20:46

    __FILE__ and __LINE__ are sort of dynamic constants that hold the file and line that are currently executing. Passing them in here allow errors to properly report their location.

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

    When you run this

    $ 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
    

    Note it says the file and line #5 even though that was just text in an eval. Without those the file/line trick the output would look like this:

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

    The stack trace simply shows (eval) which isn't as helpful.

    0 讨论(0)
  • 2020-11-30 20:46

    Let's also note, that eval-ling strings should be avoided where possible. In your particular case, replacing #class_eval with #class_exec is possible, and should be preferred:

    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
    
    0 讨论(0)
提交回复
热议问题