Reputation: 1248
Back when I used Ruby regularly, I had a bad habit of leaving everything public and ignoring privacy. Unfortunately, that ignorance is coming back to haunt me. Here's a simpler version of my problem:
class Something
private
attr_accessor :sneaky
public
def initialize
@sneaky = 0
end
def test
while sneaky < 10
puts "#{sneaky}"
sneaky = (sneaky + 1)
end
end
end
test = Something.new
test.test
This prints the correct value of sneaky (0
), then errors out at sneaky = (sneaky + 1)
, saying that sneaky
is nil
:
0
test.rb:13:in `test': undefined method `+' for nil:NilClass (NoMethodError)
from test.rb:19:in `<main>'
What's up with that? @sneaky
's been set to 0 in the constructor. And if it really were nil, shouldn't that puts
print a blank line and not a 0
?
EDIT: Yep, replacing sneaky = (sneaky + 1)
with self.sneaky = sneaky + 1
solves the problem, even though self.sneaky=
looks like a privacy violation, since it has an explicit receiver. Apparently an exception is made for setters. But the weird interaction with privacy means you can't say self.sneaky += 1
(you end up getting test.rb:14:in 'test': private method 'sneaky' called for #<Something:0x000001019004c8 @sneaky=0> (NoMethodError)
). Fortunately I'm not the only one who thinks that's weird.
Upvotes: 4
Views: 2975
Reputation: 369458
A form of foo = bar
assigns to a local variable called foo
. If you want to call an attr_writer
, you need to use an explicit receiver: self.sneaky += 1
.
This has nothing to do with private
, it's just basic Ruby syntax for local variable assignments.
Upvotes: 6