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.