John, this is a _fantastic_ point. It's certainly true that there
would be no way to use the "setter" half of a private attr_accessor in
a regular Ruby object:
self.bar = 'baz' # violates private
bar = 'baz' # sets a local variable
Well, no, that would be silly. Private methods in Ruby are fairly
gimpy*, but mercifully not that gimpy. Ruby has a special case to
allow the self.bar = 'baz' syntax with a private accessor for bar.
Try it. However, this does cause problems with compound operators;
for instance, this won't work:
self.bar ||= "bar" # calls self.bar under the covers;
bar || = "bar" # sets a local variable.
In any case, I've always been a fan of judicious use of access
control, so I agree with Gaius that ActiveRecord attributes and
association proxies should act in a consistent manner in this regard.
I've submitted a patch for the issue brought up by acechase earlier in
this thread (http://rails.lighthouseapp.com/projects/8994-ruby-on-
should-act-consistently-with-ruby-method-dispatch). I hope to submit
a second patch for the initial issue soon.
Interestingly, fixing the initial tests I wrote causes one unexpected
test failure, which is the reason for the line change in
has_one_association.rb. The method was calling #quote_value on the
instance (which is private) rather than #quote_value on the class
(which is public). All other calls to #quote_value in the nearby code
used the class method, which makes me think this was perhaps an
extremely minor bug; but, a bug exposed by proper access control.
*Incidentally, the fact that anyone can circumvent access control in
Ruby via the #send method isn't what makes me think it gimped. The
fact is, this still forces any consumers of my interface to make an
explicit decision to ignore my suggested usage. At this point they
know they've voided the warranty and proceed at their own peril. My
concerns with private methods in Ruby center more on how difficult
they are to use within the class that does have access to them;
disallowing an explicit sender, even when that sender is self, can
handicap readability in some cases, and leads to inconsistent usage
patterns, like the example I gave above with the ||= operator.