Ruby访问器有没有办法返回除set变量之外的东西?

时间:2008-10-13 14:06:34

标签: ruby class accessor

我想在编写器访问器中进行一些检查。我的第一个想法是返回一个布尔值。

class MyClass
  def var=(var)
    @var = var
    # some checking
    return true
  end
end

m = MyClass.new
retval = (m.var = 'foo')

=> "foo"

我可以在编写器访问器中设置返回值吗?如果是,我怎样才能得到这个值?

4 个答案:

答案 0 :(得分:9)

我会使用set_var(var)而不是你想要做的事情,假设属性编写器正常工作。你要做的是非标准的,并且对于下一个使用你的代码的穷人来说是不明显的。 (它可能就是你自己)如果发送了错误的输入或者发生了异常的事情,我会抛出异常。

您想要这种行为

Correct
>>temp = object.var = 7
=> 7 

Wrong
>>temp = object.var = 7
=> false

=运算符应始终返回传递给它的值。 Ruby使用隐式返回,这在编程语言中并不常见。使用method=()时仔细检查退货。

答案 1 :(得分:4)

class Test
  def var=(var)
    @var = var
    return true
  end
end

t1, t2 = Test.new, Test.new

t1.var = 123 # evaluates to 123

# Why is it impossible to return something else:
t1.var = t2.var = 456

如评论中所述:我认为不可能改变返回值以允许链式分配。无论如何,大多数Ruby程序员都可能会意外地改变返回值。

免责声明:我测试了上面的代码,但是我没有发现任何明确的引用来验证我的陈述。

<强>更新

class Test
  def method_missing(method, *args)
    if method == :var=
      # check something
      @var = args[0]
      return true
    else
      super(method, *args)
    end
  end

  def var
    @var
  end
end

t = Test.new
t.var = 123 # evaluates to 123
t.does_not_exists # NoMethodError

这似乎真的不可能!上面的示例表明返回值根本与var=方法无关。你无法改变这种行为 - 这是Ruby任务工作的基本方式。

更新2:找到解决方案

你可以提出异常!

class Test
  def var=(var)
    raise ArgumentError if var < 100 # or some other condition
    @var = var
  end
  def var
    @var
  end
end

t = Test.new
t.var = 123 # 123
t.var = 1 # ArgumentError raised
t.var # 123

答案 2 :(得分:2)

另外,根据您的示例,要清理,您可以执行以下操作:

class MyClass
  attr_accessor :var
end

m = MyClass.new
m.var = "Test"
puts m.var # => "Test"

关于你的问题,您是否在询问是否可以返回除为对象值设置的值以外的值?

更新

查看此项目:Validatable。它将类似ActiveRecord的验证添加到您的类属性中。

快速方案:

class Person
  include Validatable
  validates_presence_of :name
  attr_accessor :name
end

class PersonPresenter
  include Validatable
  include_validations_for :person
  attr_accessor :person

  def initialize(person)
    @person = person
  end
end

presenter = PersonPresenter.new(Person.new)
presenter.valid? #=> false
presenter.errors.on(:name) #=> "can't be blank"

答案 3 :(得分:1)

我知道这是对派对的迟回应......

很难知道你是怎么做的。您提到要在保存到数据库之前检查它吗?文件?

在属性值不好的情况下,您希望发生什么?

通过使用布尔返回,您可以有效地“隐藏”错误(因为忘记必须检查setter的返回值的奇怪之处)。

虽然你可以做别人的建议

  • 使用验证器插件
  • 提出错误

您还可以考虑使用isValid吗?像许多类最终获得持久化的方法一样。然后保存可以检查对象的状态并抛出错误。

底线:

  • 不要做你发布的内容
  • 抛出错误(通过任何已发布的解决方案)

帮助推动解决方案的一种方法是考虑首先编写您正在寻找的行为(即 BDD )。然后,通过 TDD -ing使用 RSpec 进一步研究课程应该做什么,以获得需要出现以支持所需行为的所需类“合同”。