代码之家  ›  专栏  ›  技术社区  ›  Christian Lescuyer

Ruby访问器是否有方法返回set变量以外的内容?

  •  4
  • Christian Lescuyer  · 技术社区  · 16 年前

    我想签入一个writer访问器。我的第一个想法是返回一个布尔值。

    class MyClass
      def var=(var)
        @var = var
        # some checking
        return true
      end
    end
    
    m = MyClass.new
    retval = (m.var = 'foo')
    
    => "foo"
    

    我可以在writer访问器中设置返回值吗?如果是,如何获取该值?

    4 回复  |  直到 16 年前
        1
  •  9
  •   epochwolf    16 年前

    我将使用set_var(var),而不是您试图做的事情,属性编写器被假定为可以正常工作。你试图做的是不标准的,对下一个使用你的代码的穷人来说是不明显的(它可能只是你自己)我会抛出一个异常,如果错误的输入发送或一些相当异常的事情发生。

    你想要这种行为

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

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

        2
  •  4
  •   Christoph Schiessl Joeyjoejoejr    16 年前
    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
    

    更新

    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
    
        3
  •  2
  •   mwilliams    16 年前

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

    class MyClass
      attr_accessor :var
    end
    
    m = MyClass.new
    m.var = "Test"
    puts m.var # => "Test"
    

    查看此项目: Validatable

    快速场景:

    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"
    
        4
  •  1
  •   Jon Kern    14 年前

    我知道这是对派对的迟到回应。。。

    很难知道你想在课堂上做什么。您提到要在保存之前检查它。。。到数据库?文件

    如果属性值不正确,您希望发生什么情况?

    通过使用布尔返回,可以有效地“隐藏”错误(因为 忘记检查setter的返回值这件奇怪的事情)。

    而你可以按照别人的建议去做

    • 使用验证插件
    • 出错

    你也可以考虑一个IsHealm?方法,就像许多最终得到持久化的类一样。然后save可以检查对象的状态并抛出错误。

    底线:

    • 不要做你贴的事
    • 确实抛出错误(由发布的任何解决方案引发)

    BDD TDD RSpec 获得所需的类“契约”,该类需要出现以支持所需的行为。

    推荐文章