public
Description: Ruby on Rails
Homepage: http://rubyonrails.org
Clone URL: git://github.com/rails/rails.git
Allow memoized methods to be reloaded and allow multiple symbols
josh (author)
Fri Jul 18 09:18:16 -0700 2008
commit  e1f23da53cef20a60e4bf458d959fe2bfe7d52ea
tree    97753d4e40ef08da5c0827b51e03a4e7f5c8c276
parent  7430c4168fad07b480dbf80c8ac75ba7db8c634f
...
5
6
7
8
9
10
11
 
 
 
 
 
12
13
14
15
16
17
18
19
 
 
 
 
 
 
 
 
20
21
22
 
 
23
24
25
26
27
28
29
 
 
30
31
32
...
5
6
7
 
 
 
 
8
9
10
11
12
13
 
 
 
 
 
 
 
14
15
16
17
18
19
20
21
22
 
 
23
24
25
26
27
28
29
 
 
30
31
32
33
34
0
@@ -5,28 +5,30 @@ module ActiveSupport
0
     end
0
 
0
     module ClassMethods
0
-      def memoize(symbol)
0
-        original_method = "_unmemoized_#{symbol}"
0
-        memoized_ivar = "@_memoized_#{symbol}"
0
-        raise "Already memoized #{symbol}" if instance_methods.map(&:to_s).include?(original_method)
0
+      def memoize(*symbols)
0
+        symbols.each do |symbol|
0
+          original_method = "unmemoized_#{symbol}"
0
+          memoized_ivar = "@#{symbol}"
0
+          raise "Already memoized #{symbol}" if instance_methods.map(&:to_s).include?(original_method)
0
 
0
-        alias_method original_method, symbol
0
-        class_eval <<-EOS, __FILE__, __LINE__
0
-          def #{symbol}
0
-            if defined? #{memoized_ivar}
0
-              #{memoized_ivar}
0
-            else
0
-              #{memoized_ivar} = #{original_method}
0
+          alias_method original_method, symbol
0
+          class_eval <<-EOS, __FILE__, __LINE__
0
+            def #{symbol}(reload = false)
0
+              if !reload && defined? #{memoized_ivar}
0
+                #{memoized_ivar}
0
+              else
0
+                #{memoized_ivar} = #{original_method}.freeze
0
+              end
0
             end
0
-          end
0
-        EOS
0
+          EOS
0
+        end
0
       end
0
     end
0
 
0
     def freeze
0
       methods.each do |method|
0
-        if m = method.to_s.match(/\A_unmemoized_(.*)/)
0
-          send(m[1]).freeze
0
+        if m = method.to_s.match(/\Aunmemoized_(.*)/)
0
+          send(m[1])
0
         end
0
       end
0
       super
...
8
9
10
11
12
13
14
15
16
 
 
 
 
 
 
17
18
19
...
21
22
23
 
 
 
 
24
25
26
 
 
 
 
 
27
28
29
 
 
 
 
30
31
32
33
34
35
36
 
 
 
 
 
37
38
39
40
41
42
 
 
43
44
45
...
8
9
10
 
11
12
13
14
 
15
16
17
18
19
20
21
22
23
...
25
26
27
28
29
30
31
32
 
 
33
34
35
36
37
38
 
 
39
40
41
42
43
44
45
 
 
 
 
46
47
48
49
50
51
52
53
 
 
 
54
55
56
57
58
0
@@ -8,12 +8,16 @@ uses_mocha 'Memoizable' do
0
       def name
0
         fetch_name_from_floppy
0
       end
0
-      memoize :name
0
 
0
       def age
0
         nil
0
       end
0
-      memoize :age
0
+
0
+      def random
0
+        rand(0)
0
+      end
0
+
0
+      memoize :name, :age, :random
0
 
0
       private
0
         def fetch_name_from_floppy
0
@@ -21,25 +25,34 @@ uses_mocha 'Memoizable' do
0
         end
0
     end
0
 
0
+    def setup
0
+      @person = Person.new
0
+    end
0
+
0
     def test_memoization
0
-      person = Person.new
0
-      assert_equal "Josh", person.name
0
+      assert_equal "Josh", @person.name
0
+
0
+      @person.expects(:fetch_name_from_floppy).never
0
+      2.times { assert_equal "Josh", @person.name }
0
+    end
0
 
0
-      person.expects(:fetch_name_from_floppy).never
0
-      2.times { assert_equal "Josh", person.name }
0
+    def test_reloadable
0
+      random = @person.random
0
+      assert_equal random, @person.random
1
+      assert_not_equal random, @person.random(:reload)
0
     end
0
 
0
     def test_memoized_methods_are_frozen
0
-      person = Person.new
0
-      person.freeze
0
-      assert_equal "Josh", person.name
0
-      assert_equal true, person.name.frozen?
0
+      assert_equal true, @person.name.frozen?
0
+
0
+      @person.freeze
0
+      assert_equal "Josh", @person.name
0
+      assert_equal true, @person.name.frozen?
0
     end
0
 
0
     def test_memoization_frozen_with_nil_value
0
-      person = Person.new
0
-      person.freeze
0
-      assert_equal nil, person.age
0
+      @person.freeze
0
+      assert_equal nil, @person.age
0
     end
0
 
0
     def test_double_memoization

Comments

DefV Fri Jul 18 09:24:14 -0700 2008 at activesupport/test/memoizable_test.rb L48

This test will not always pass :-)

NZKoz Fri Jul 18 11:51:59 -0700 2008

Unless it’s run on debian

nbibler Fri Jul 18 12:01:10 -0700 2008

It would probably be better to replace the random calls with an incrementing instance variable. For instance:

class Person
  def current_count
    @count ||= 0
    @count += 1
  end
  memoize :current_count

You can then reliably test expected values against the memoization.