Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I use class_eval?

I don't understand class_eval.

class Module
  def attr_ (*syms)
    syms.each do |sym|
      class_eval %{def #{sym}= (val)
        @#{sym} = val
      end}
    end
  end
end

What does the % mean?

What does class_eval do?

And where is (val) coming from?

like image 893
never_had_a_name Avatar asked Jun 09 '10 05:06

never_had_a_name


1 Answers

The short answer is: you probably want to avoid using class_eval like this.

Here's an explanation of your code:

The %{hello} is just another way to write a string literal in Ruby, without having to worry about escaping double or single quotes within the string:

%{hello "world"} == "hello \"world\""  # => true

The val in your code is an argument of the method being defined.

The class_eval is used to define some methods by computing the text one would write to do the definition and then evaluating it. It is not necessary here, BTW. An equivalent code would be:

class Module
  def attr_ (*syms)
    syms.each do |sym|
      define_method "#{sym}=" do |val|
        instance_variable_set "@#{sym}", val
      end
    end
  end
end

This is just equivalent to the builtin attr_writer.

Update: There can actually be a significant difference between the two...

The class_eval version is vulnerable if you can't trust the argument syms. For example:

class Foo
  attr_ "x; end; puts 'I can execute anything here!'; val=42; begin; val"
end

The class_eval version will print "I can execute anything here" twice, proving it can execute anything. The define_method version won't print anything.

This type of code was pivotal to create major vulnerability for all installed Rails apps.

like image 151
Marc-André Lafortune Avatar answered Nov 14 '22 18:11

Marc-André Lafortune