Sometimes, you don't want to calculate the value of an attribute every time--like the sum of an array. However, you don't want it cached on the outside of the object since that makes for messy code. But you seem to cache things over and over again inside objects. Here's a module AttributeCache that does a little meta programming to make attribute caching a little bit easier. more details at
http://webjazz.blogspot.com/2007/05/ruby-snippet-caching-object-attributes.html 1
2 module AttributeCache
3
4 def metaclass; class << self; self; end; end
5
6 def cache(attr_name, options)
7 instance_variable_set "@#{attr_name}", options[:initial]
8 instance_variable_set "@#{:sum}_outdated", true
9
10 metaclass.instance_eval do
11 define_method("outdate_#{attr_name}") do
12 puts "in outdated"
13 instance_variable_set "@#{attr_name}_outdated", true
14 end
15 end
16
17 metaclass.class_eval %Q{
18 def cached_#{attr_name}(&block)
19 if @#{attr_name}_outdated
20 puts "in cached to update!"
21 @#{attr_name}_outdated = false
22 @#{attr_name} = block.call
23 else
24 puts "in cached to give cache!"
25 end
26 return @#{attr_name}
27 end
28 }
29
30 end
31
32 end
33
34 class Collection
35 include AttributeCache
36
37 def initialize
38 @array = []
39 cache :sum, :initial => 0
40 end
41
42 def add(x)
43 outdate_sum
44 @array << x
45 end
46
47 def sum
48 cached_sum { @array.inject {|t, e| t += e} }
49 end
50
51 end
52
53 c = Collection.new
54 puts c.public_methods(false).inspect
55 c.add(2)
56 c.add(3)
57 puts c.sum
58 puts c.sum
59 c.add(4)
60 puts c.sum
61 puts c.sum