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.

+3


source to share


3 answers


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?

+2


source


This is because local variables, unlike instance variables, have lexical scope. This Wikipedia article might help.



+3


source


I cannot reproduce the problem. Here's a simple test case I created:

          class MyReader

            def initialize
              @line_hash = {}
            end

            def read
              [1,2].each do |x|
                @line_hash[x] = '0'
              end
            end

          end  

          p MyReader.new.read

      

0


source







All Articles