Как я использую class_eval?

Я не понимаю 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) прибытие из?

20
задан the Tin Man 3 January 2012 в 21:33
поделиться

1 ответ

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

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

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

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

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

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

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.

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

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

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

Версия class_eval дважды выведет "I can execute anything here", доказывая, что может выполнить что угодно. Версия define_method ничего не выведет.

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

26
ответ дан 30 November 2019 в 00:51
поделиться