有没有办法检测Ruby中的属性更改?

时间:2017-08-24 04:45:09

标签: ruby

我有这段代码:

class Test
    attr_accessor :test_attr
    def initialize
        @test_attr = ""
    end

    def test_attr_changed
        p 'test_attr is changed: ' + @test_attr 
    end
end

当我更改属性:test_attr时:

test = Test.new
test.test_attr = "New value"

我希望它触发test_attr_changed功能并输出:

test_attr is changed: New value

有没有办法在Ruby中像QML onChanged信号那样做?

2 个答案:

答案 0 :(得分:3)

这是一个如何模块化这个功能的相当简单的实现

module Overlord
  module ClassMethods
    def attr_watcher(*attrs)
      attrs.each do |attr|
        define_method(attr) {instance_variable_get("@#{attr}")}
        define_method("#{attr}=") do |val|
          changes[attr] << {new: val, old: send(attr), when: Time.now}
          instance_variable_set("@#{attr}",val)
        end
      end
    end
  end
  def self.included(base)
    base.extend(ClassMethods)
  end
  def changes
    @changes ||= Hash.new {|h,k| h[k] = []}
  end
end 

class Test
  include Overlord
  attr_watcher :name
end

然后简单地

t = Test.new
t.changes
#=> {}
t.name = "Mnky"
t.changes
#=> => {:name=>[{:new=>"Mnky", :old=>nil, :when=>2017-08-24 11:17:27 -0400}]}
t.name = "Other"
t.changes[:name] 
#=> [
     {:new=>"Mnky", :old=>nil, :when=>2017-08-24 11:17:27 -0400},
     {:new=>"Other", :old=>"Mnky", :when=>2017-08-24 11:17:58 -0400}]
t.name
#=> "Other"

答案 1 :(得分:2)

删除attr_accessor :test_attr

class Test
  attr_reader :test_attr

  def test_attr=(value)
    @test_attr = value
    test_attr_changed
    value
  end
end