Почему переменная класса работает, но переменная экземпляра возвращает nil при включении модуля в класс [Ruby]? - PullRequest
0 голосов
/ 06 декабря 2011

В следующем коде почему переменная data правильно работает как переменная класса, но не как переменная экземпляра?(Примечание: я попытался упростить / воспроизвести только необходимые фрагменты сценария, чтобы вопрос имел смысл. Если потребуется больше, я могу опубликовать полный сценарий.)

require 'prawn'

class Test
  include Prawn

  def initialize (data, filename) #data is an array of arrays
    @@data = data #this is the variable in question, when @data the script fails
    @filename = filename
  end

  def to_pdf
    Document.generate("#{@filename}.pdf") do #included from Prawn
      @@data.each do |item|
        do some stuff to the data
      end
      make_table with the data that's been worked on
    end
  end
end

test_run = Test.new([[1, 2, 1], [1, 2, 2]], "testfile.pdf")
test.to_pdf

Если вместо него @@data@data скрипт возвращает undefined method 'each' for nil:NilClass (NoMethodError) Почему это так?Разве переменная экземпляра не должна быть одинаково доступна для включенного модуля?(также почему нормально, что переменная @filename является методом экземпляра?)

1 Ответ

4 голосов
/ 06 декабря 2011

Из тонкой инструкции :

При использовании формы неявного блока Prawn оценит блок в экземпляре Prawn::Document, упрощая ваш синтаксис. Тем не менее, обратите внимание, что вы не сможете ссылаться на переменные из охватывающей области в этом блоке.

Prawn::Document.generate "example.pdf" do
    # ...

Если вам нужен доступ к локальным переменным и переменным экземпляра, используйте явную блочную форму, показанную ниже. В этом случае Prawn дает экземпляр PDF::Document, а блок является обычным закрытием:

Prawn::Document.generate "example.pdf" do |pdf|
    #...

Ваш блок в to_pdf оценивается в содержимом экземпляра Prawn::Document, а не в контексте вашего объекта, и это означает, что нет переменной экземпляра @data, поэтому @data создается со значением nil при попытке доступа к нему. Вы, вероятно, хотите использовать блок с одним аргументом:

Document.generate("#{@filename}.pdf") do |pdf|
  # do things to 'pdf' in here
...