Динамические методы с использованием define_method и eval

Я собрал два примера классов, реализованных несколькими разными способами, которые очень хорошо отражают то, что я хочу сделать в моей модели Rails. Меня беспокоит то, что я не знаю, что, если таковые имеются, связаны с использованием любого метода. И я нашел только сообщения, которые объясняют, как их реализовать, или общее предупреждение, чтобы избежать / быть осторожным при их использовании. Чего я не нашел, так это четкого объяснения того, как сделать это безопасно, и чего я должен опасаться или почему я должен избегать этого шаблона.

class X
  attr_accessor :yn_sc, :um_sc
  def initialize
    @yn_sc = 0
    @um_sc = 0
  end
  types = %w(yn um)
  types.each do |t|
    define_method("#{t}_add") do |val|
      val = ActiveRecord::Base.send(:sanitize_sql_array, ["%s", val])
      eval("@#{t}_sc += #{val}")
    end
  end
end

class X
  attr_accessor :yn_sc, :um_sc
  def initialize
    @yn_sc = 0
    @um_sc = 0
  end
  types = %w(yn um)
  types.each do |t|
    # eval <<-EVAL also works
    self.class_eval <<-EVAL 
      def #{t}_add(val)
        @#{t}_sc += val
      end
    EVAL
  end
end


x = X.new
x.yn_add(1) #=> x.yn_sc == 1 for both

person MCB    schedule 19.11.2013    source источник


Ответы (1)


Что ж, ваш код выглядит действительно безопасным. Но представьте себе код, основанный на пользовательском вводе. Это может выглядеть примерно так

puts 'Give me an order, sir!'
order = gets.chomp
eval(order)

Что произойдет, если наш капитан взбесится и прикажет нам 'rm -rf ~/'? Грустные вещи конечно!

Так что возьмите небольшой урок. eval небезопасен, потому что он оценивает каждую полученную строку. Но есть еще одна причина не использовать eval. Иногда он оценивается медленнее, чем альтернативы. Посмотрите здесь, если интересно.

person user2422869    schedule 19.11.2013
comment
Что ж, val будет пользовательским вводом из формы, хотя я знаю, что злоумышленники могут его подделать, поэтому sanitize. - person MCB; 19.11.2013