Reputation: 599
In the following code, why does the data
variable work properly as a class variable but not an instance variable? (Note: I tried to simplify/reproduce only the necessary bits of the script to have the question make sense. If more is needed I can post the full script.)
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
If @@data
is instead @data
the script returns undefined method 'each' for nil:NilClass (NoMethodError)
Why is that? Shouldn't an instance variable be equally accessible to the included module? (also why is it ok that the @filename variable is an instance method?)
Upvotes: 0
Views: 487
Reputation: 434755
From the fine manual:
When using the implicit block form, Prawn will evaluate the block within an instance of
Prawn::Document
, simplifying your syntax. However, please note that you will not be able to reference variables from the enclosing scope within this block.Prawn::Document.generate "example.pdf" do # ...
If you need to access your local and instance variables, use the explicit block form shown below. In this case, Prawn yields an instance of
PDF::Document
and the block is an ordinary closure:Prawn::Document.generate "example.pdf" do |pdf| #...
Your block in to_pdf
is being evaluated in the content of a Prawn::Document
instance, not within the context of your object and that means that there is no @data
instance variable so @data
is created with a value of nil
when you try to access it. You probably want to use a block with a single argument:
Document.generate("#{@filename}.pdf") do |pdf|
# do things to 'pdf' in here
Upvotes: 4