遅延初期化する attr_reader を追加するモジュール
module LazyInitializationAttribute def LazyInitializationAttribute.append_features(mod) super mod.const_set("LAZY_INITIALIZE_BLOCK_TABLE", {}) def mod.lazy_attr_accesser name, hook=nil, &block lazy_attr_reader name, hook, &block attr_writer name end def mod.lazy_attr_reader name, hook=nil, &block name = name.to_sym hook = hook.to_sym unless hook.nil? self::LAZY_INITIALIZE_BLOCK_TABLE[name] = block hook_snippet = hook.nil? ? "" : %Q{ result = self.__send__(:#{hook}) if self.respond_to? :#{hook} }.lstrip class_eval %Q{ def #{name} if @#{name}.nil? lazy_init_proc = self.class::LAZY_INITIALIZE_BLOCK_TABLE[:#{name}] result = nil result = instance_eval &lazy_init_proc if lazy_init_proc #{hook_snippet} @#{name} = result if @#{name}.nil? and not result.nil? end @#{name} end } end end end
使い方
適当すぎるけど。。
class A include LazyInitializationAttribute def initialize(init=0) @init = init end def update! @init += 1 @a = @init end def hoge 3 end lazy_attr_reader :a, :update! lazy_attr_reader(:aa) {|a| 2 } lazy_attr_reader(:aai) {|a| @init } lazy_attr_reader(:bb, :hoge) lazy_attr_accesser(:aas) {|a| 2 } lazy_attr_accesser(:bbs, :hoge) end a =A.new(0) a.a # => 1 a.aa # => 2 a.aai # => 1 a.bb # => 3 b =A.new(0) b.aai # => 0 b.a # => 1 b.aai # => 0