Как я могу использовать class_eval? - PullRequest
20 голосов
/ 09 июня 2010

Я не понимаю class_eval.

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

Что означает %?

Что означает class_eval?

И где(val) исходит от?

1 Ответ

26 голосов
/ 09 июня 2010

Краткий ответ: вы, вероятно, хотите избегать , используя class_eval, как это.

Вот объяснение вашего кода:

%{hello} - это просто еще один способ написать строковый литерал в Ruby, не беспокоясь о экранировании двойных или одинарных кавычек в строке:

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

val в вашем коде является аргументом определяемого метода.

class_eval используется для определения некоторых методов путем вычисления текста, который можно написать для определения, а затем его оценки. Это не обязательно здесь, кстати. Эквивалентный код будет:

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

Это просто эквивалентно встроенному attr_writer.

Обновление : На самом деле между этими двумя понятиями может быть существенная разница ...

Версия class_eval уязвима, если вы не можете доверять аргументу syms. Например:

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

Версия class_eval напечатает «Я могу выполнить все что угодно» дважды, доказывая, что она может выполнить что угодно. Версия define_method ничего не печатает.

Этот тип кода был ключевым для создания серьезной уязвимости для всех установленных приложений Rails.

...