Опасности и предостережения от Kernel :: eval в Ruby? - PullRequest
5 голосов
/ 15 сентября 2011

Я использую Ruby 1.9.2 p180.

Я пишу инструмент непрерывной оценки для Rubyvis (будет частью SciRuby ). По сути, вы устанавливаете Rubyvis::Panel во входном файле (например, test.rb), и этот класс SciRuby (Плоттер) следит за test.rb на предмет изменений. Когда есть изменение, SciRuby запускает скрипт через eval.

Сценарий работает, если я запускаю его из командной строки, но при выполнении через eval график неверен - прямая линия, как будто все данные пропали, вместо , что вы видите здесь . Примечание: Раньше здесь говорилось, что SVG отличается, но оказывается, что это был результат загрузки REXML вместо нокогири.

Вот сценарии тестирования и eval-код. Большинство выводят прямую линию (с исключениями, описанными в разделе edit ниже).

Я не знаю, как это происходит.

У меня есть несколько идей относительно , почему это может происходить, но не имею понятия о механизме.

Гипотеза:

  1. eval не позволяет делать глубокие копии. Объекты, взятые из eval, в определенных контекстах являются недостающими частями, особенно когда лямбда используется для обработки данных в правильном формате для графика.
  2. По какой-то причине eval не соблюдает связанный список депозита при вызове require - может быть, в моей привязке используется неправильная версия nokogiri?
  3. Некоторая другая необходимая библиотека (возможно, RSVG?) Перегружена некоторым методом, который использует Rubyvis.

Кто-нибудь видел что-нибудь подобное раньше? Я как бы чувствую себя в темноте - совершенно не зная, с чего начать устранение неполадок.

Редактировать 15.09.11: новая информация

Похоже, что вызов OpenStruct.new вызывает проблему.

Если я определю данные как список списков, data = pv.range(0,10,0.1).map { |d| [d,Math.sin(d)+2+rand()] }, это будет хорошо.

Но когда данные определены как список OpenStructs, следующий код дает неправильный вывод:

data = pv.range(0, 10, 0.1).map {|x|
  o = OpenStruct.new({:x=> x, :y=> Math.sin(x) + 2+rand()})
  STDERR.puts o.inspect # Output is correct.
  o
}
STDERR.puts "size of data: #{data.size}"
STDERR.puts "first x = #{data.first.x}" # Output is first x = 0.0
STDERR.puts "first y = #{data.first.y}" # Output is first y =     (WRONG)

Я даже могу вызвать ошибку, если при назначении данных буду использовать метод сбора, например,

vis.add(pv.Line).data(data.collect { |d| [d.x,d.y] }

plotter.rb:88:in `block in <main>': undefined method `x' for [0.0, nil]:Array (NoMethodError)

против ошибки без vis.add(pv.Line).data(data). Ошибка возникает из-за вызова eval("vis.render()", bind) в источнике моего приложения (не в сценарии печати).

Оказывается, что если я просто использую хеш, например, {:x => x, :y => Math.sin(x)}, это работает нормально. Но когда я явно говорю Hash.new({:x => x, :y => Math.sin(x)}), это дает ошибку независимо от того, как я вызываю vis.data:

rubyvis/lib/rubyvis/internals.rb:184:in `each': comparison of Hash with Hash failed (ArgumentError)

Так что разница в том, как мои данные назначены. Вопрос: почему?

Копии входов доступны в оригинальном списке . Спасибо за вашу помощь.

Ответы [ 2 ]

1 голос
/ 16 сентября 2011

Оказывается, что если я просто использую хеш, например, {: x => x,: y => Math.sin (x)}, это прекрасно работает. Но когда я прямо говорю Hash.new ({: x => x,: y => Math.sin (x)}), что выдает ошибку независимо от того, как я позвоните vis.data:

Прежде всего, ваш звонок в Hash.new неверен. Hash.new принимает параметр, который является значением по умолчанию хэша.

0 голосов
/ 30 сентября 2011

Я хотел опубликовать это как комментарий, а не как ответ;

Вы пробовали load вместо eval?

...