In Ruby, inside a class\'s instance method, we use a getter by
foo
and we use a setter by
self.foo = something
Since local scope takes precedence, when you say foo = something
, a local variable foo
will be created and assigned the contents of something
.
The reason you can write foo
in order to use the getter is because Ruby will move up in scope when it can't find a variable with that name and it will eventually find the method.
If there is a local variable with the same name as the getter method, Ruby will use its value instead:
class Foo
attr_accessor :foo
def initialize
@foo = :one
end
def f
foo = :two
foo
end
end
Foo.new.f
# => :two
In order to make it clear that you want to access the setter, you must write self.foo = something
. That will tell Ruby you want to execute the foo=
method on the self
object with something
as parameter.
As far as I know, there isn't a way around this in Ruby. I'm pretty confident this is simply how Ruby evaluates expressions.
When given a value, Ruby will first check if there is a local variable within the context which matches the one being called. If there is (perhaps 'foo' in your case), that will be the value used. If there is no such value, then Ruby will try to look up the value as a method call (falling through to "self" as the caller). If no such method exists in the look up path, an error will be raised.
The need to use "self" in the setter is to avoid Ruby setting the value as a local variable, while the lack of the use of "self" only works in the getter instance when there is no local variable of the same name being used in that context. It is probably better and clearer, albeit slightly more verbose, to be explicit with your use of self as to avoid confusion about where values are coming from.
If you are willing to break the conventions, you can write your setters using jQuery style, using the same method for getter and setter, depending of whether it has arguments or not:
def foo *args
return @foo if args.empty?
@foo = args.first
end
# => nil
foo
# => nil
foo(:bar) # foo = :bar
# => :bar
foo
# => :bar