def foo(bar)
'return value'
end
foo 'bar' # => "return value"
def foo=(bar)
'return value'
end
foo = 'bar' # => "bar"
send :foo=, 'bar' # => "return value"
我希望foo = 'bar'
返回"return value"
但不要为此目的使用send
。我怎么能这样做?
我的宝石需要一个理想的行为。这是一个例子:
car = Car.new
car.gear # => :first
car.next_gear # => :second
car.gear # => :second
car.gear = :fourth # => false
car.gear # => :second
car.gear = :third # => :third
car.gear # => :third
答案 0 :(得分:5)
作业始终会返回作业的右侧。
详细了解ruby documentation:
以等号结尾的方法表示赋值方法。 对于赋值方法,返回值被忽略,参数是 而是返回。
话虽如此,foo = bar
也分配给局部变量foo
,而不是使用foo=
方法。同样,这在the ruby docs:
使用方法分配时,您必须始终拥有接收器。如果你 没有接收器Ruby假定您正在分配给本地 变量
您可以通过运行
进行测试local_variables #=> []
def foo=(bar);end
foo = 42
local_variables #=> [:foo]
您看到已创建局部变量foo
。更好地使用self.foo = 'bar'
。
解决您的宝石特定问题:遵循Neil的建议并使用change_gear
之类的额外方法来完成您的工作。他在评论中给了你很好的理事会。
答案 1 :(得分:2)
这是一个Ruby问题:访问者方法的返回值被忽略。
此代码将更清楚地说明实际发生的事情:
#!/usr/bin/env ruby
def foo(bar)
p "called :foo w/ #{bar.inspect}"
end
def foo=(bar)
p "called :foo= with #{bar.inspect}"
end
ret = (foo :bar1) # calls foo(bar)
p "ret: #{ret}" # "ret: called :foo w/ :bar1"
ret = (foo = :bar2) # assigns a local variable foo = 'bar2'
p "ret: #{ret}" # "ret: bar2"
ret = (send :foo=, :bar3) # calls foo=(bar), returns what p returns
p "ret: #{ret}" # "ret: called :foo= with :bar3"
ret = (self.foo = :bar4) # calls foo=(bar), returns ???
p "ret: #{ret}" # "ret: bar4"
基本上,Ruby解析器(至少在2.1中)的行为就好像self.foo=
正在调用一个访问器方法(即使它实际上没有分配任何东西),将始终返回传递给的值它与你发送的内容无关,而不是访问者的返回值。
演示:
#!/usr/bin/env ruby
class << self
attr_accessor :foo
def foo=(bar)
p "called :foo= with #{bar.inspect}"
@foo = :baz
end
end
ret = (self.foo = :bar)
p "ret: #{ret} vs @foo: #{@foo.inspect}"
输出:
"called :foo= with :bar"
"ret: bar vs @foo: :baz"
编辑:reference的@tessi:
以等号结尾的方法表示赋值方法。对于赋值方法,将忽略返回值,而是返回参数。
答案 2 :(得分:1)
我认为它失败的原因是局部变量名称在定义时优先于方法名称。
因此,您需要使用send
,以便self
知道它正在寻找方法而不是变量。
答案 3 :(得分:0)
你需要这样做:
self.foo = 'bar'