如何做真正的只读属性(accessors => attributs)

时间:2013-10-18 09:20:58

标签: ruby readonly accessor

考虑这个简单的代码:

class Yeah
  attr_reader :foo
  attr_reader :fool
  attr_reader :feel
  def initialize(foo: "test", fool: {}, feel: [])
    @foo = foo
    @fool = fool
  end
end

test = Yeah::new
pp test
test.fool[:one] = 10
pp test

输出:

#<Yeah:0x000008019a84a0 @foo="test", @fool={}>
#<Yeah:0x000008019a84a0 @foo="test", @fool={:one=>10}>

我的问题是,有一种“简单”,“干净”的方式,对真正的只读数组,Hash attributs进行读取加速,或者我需要继承具有很多难以编写的锁定的数组或哈希,(undef,别名)或使用代理,委托或其他类似的模式?

3 个答案:

答案 0 :(得分:2)

您可以想到以下内容:

class Yeah
  def self.reader_meth
    %i(foo fool feel).each do |m|
      define_method(m){instance_variable_get("@#{m}").dup.freeze}
    end
  end
  def initialize(foo: "test", fool: {}, feel: [])
    @foo = foo
    @fool = fool
    @feel =feel
  end
  reader_meth
end

test = Yeah.new
test # => #<Yeah:0x8975498 @foo="test", @fool={}, @feel=[]>
test.fool[:one] = 10 # can't modify frozen Hash (RuntimeError)
test # => #<Yeah:0x8975498 @foo="test", @fool={}, @feel=[]>

答案 1 :(得分:1)

因为我想概括这个解决方案并防止“邪恶”的逃避:

我终于从Arup解决方案到达了这个:

class Module
  def attr_readonly *syms
    syms.each do |method|
      define_method(method){
        return self.instance_variable_get("@#{method.to_s}").dup.freeze 
      }
    end
  end
end

class Yeah

  attr_reader :foo
  attr_readonly :fool
  attr_reader :feel
  def initialize(foo: "test", fool: {}, feel: [])
    @foo = foo
    @fool = fool
    @feel = feel
  end

end

答案 2 :(得分:0)

Object#freeze

怎么样?
class Yeah
  def fool
    @fool.freeze
  end 
  def initialize(fool={})
    @fool = fool
  end
end
相关问题