How can I access an instance variable inside a Ruby block?
I have the following code:
class MyXmlReader
attr_accessor :filename, :lines
def initialize(filename)
@filename = filename
@line_hash = {}
end
def read
reader = Nokogiri::XML::Reader(open(@filename))
Xml::Parser.new(reader) do
... do stuff
@line_hash[var] = line # ERROR!
end
end
end
It looks like the unit is working in a new area. Because I am getting:
NoMethodError: undefined method `[]' for nil:NilClass
This can be easily worked around by creating local variables and then assigning those variables to instance variables at the end of the method read
. But I'm wondering why the local variable is available inside the block, but not the instance variable.
source to share
The interesting question is not only why a local variable is available inside a block (of course, it is locks, closing blocks, having access to local variables from the surrounding scope - that's the point), but rather why there is no instance variable. Because in fact, it should be available.
However, if the block is instance_eval
ed or instance_exec
ed, then the value self
will be changed to the message receiver instance_eval
or instance_exec
, and the instance variables will always look in self
, since it is self
now a different object, it probably won't have an instance variable @line_hash
. You have to look at the implementation Xml::Parser::new
to find out.
See also How instance_eval
does DHH work and why does DHH hate it?
source to share
This is because local variables, unlike instance variables, have lexical scope. This Wikipedia article might help.
source to share