Reputation: 868
I'm brand-new to Ruby coming from a Java background. I don't understand the relationship between instance methods and variables yet, apparently. I just had some code like this:
class Problem022
FILENAME = "resources/p022_names.txt"
@name_array = [] # <--- class line 3
def do_problem
read_input()
sort_input()
# do more stuff
end
def read_input
# <--- read_input line 2
File.open(FILENAME, "r") do |file|
file.each_line do |line|
scanner = StringScanner.new(line)
while scanner.exist?(/,/) do
name = scanner.scan_until(/,/)
@name_array.push(name) # <--- marked line
end
# more logic
end
def sort_input()
@name_array.sort!
end
# other methods
end
puts problem = Problem022.new.do_problem()
I confirmed this worked correctly up until "marked line" (see comment above), but on that line, I got the error
in `block (2 levels) in read_input': undefined method `push' for nil:NilClass (NoMethodError)
I was able to solve it by (kinda blindly) adding the line
@name_array = []
at "read_input line 2", but I don't understand why this worked. Why doesn't the method recognize the declaration of instance variable @name_array
in the class body? It seems to be able to use the constant FILENAME
just fine, and that's defined in basically the same place. The method and the variable are both instance, not class, so I wouldn't expect any problems there. I just realized that the program still runs fine even if the declaration on "class line 3" is commented out, which only confuses me more.
I've read multiple definitions of scope in Ruby but none of them cleared this up for me. What am I misunderstanding?
Upvotes: 0
Views: 173
Reputation: 230521
Here's some code that should illuminate what's going "wrong".
class Problem
@name = 'foo' # this belongs to the class, because that's what current `self` is.
# instance method
# inside of this method, `self` will be an instance of the class
def action
@name
end
# class method (or class instance method)
# inside of this method, `self` will refer to the class
def self.action
@name
end
end
p1 = Problem.new # an instance of the class
p2 = Problem # the class itself
p1.action # => nil, you never initialize @name in the context of class instance
p2.action # => "foo"
Key points:
Upvotes: 2