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 like this:
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
What does __FILE__
and __LINE__
do in that context? I know __FILE__
references the current file, but what does that whole thing do exactly? Don't really know how to search for that :).
__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.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With