<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -5,4 +5,9 @@ class Object
       self
     end
   end
+
+  # If class_eval is called on an object, add those methods to its metaclass
+  def class_eval(*args, &amp;block)
+    metaclass.class_eval(*args, &amp;block)
+  end
 end</diff>
      <filename>activesupport/lib/active_support/core_ext/object/metaclass.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,32 +1,43 @@
 module ActiveSupport
-  module Memoizable #:nodoc:
+  module Memoizable
+    module Freezable
+      def self.included(base)
+        base.class_eval do
+          unless base.method_defined?(:freeze_without_memoizable)
+            alias_method_chain :freeze, :memoizable
+          end
+        end
+      end
+
+      def freeze_with_memoizable
+        methods.each do |method|
+          if m = method.to_s.match(/^_unmemoized_(.*)/)
+            send(m[1])
+          end
+        end
+        freeze_without_memoizable
+      end
+    end
+
     def memoize(*symbols)
       symbols.each do |symbol|
-        original_method = &quot;unmemoized_#{symbol}&quot;
-        memoized_ivar = &quot;@#{symbol}&quot;
+        original_method = &quot;_unmemoized_#{symbol}&quot;
+        memoized_ivar = &quot;@_memoized_#{symbol}&quot;
 
-        klass = respond_to?(:class_eval) ? self : self.metaclass
-        raise &quot;Already memoized #{symbol}&quot; if klass.instance_methods.map(&amp;:to_s).include?(original_method)
+        class_eval &lt;&lt;-EOS, __FILE__, __LINE__
+          include Freezable
 
-        klass.class_eval &lt;&lt;-EOS, __FILE__, __LINE__
-          unless instance_methods.map(&amp;:to_s).include?(&quot;freeze_without_memoizable&quot;)
-            alias_method :freeze_without_memoizable, :freeze
-            def freeze
-              methods.each do |method|
-                if m = method.to_s.match(/^unmemoized_(.*)/)
-                  send(m[1])
-                end
-              end
-              freeze_without_memoizable
-            end
-          end
+          raise &quot;Already memoized #{symbol}&quot; if method_defined?(:#{original_method})
+          alias #{original_method} #{symbol}
+
+          def #{symbol}(*args)
+            #{memoized_ivar} ||= {}
+            reload = args.pop if args.last == true || args.last == :reload
 
-          alias_method :#{original_method}, :#{symbol}
-          def #{symbol}(reload = false)
-            if !reload &amp;&amp; defined? #{memoized_ivar}
-              #{memoized_ivar}
+            if !reload &amp;&amp; #{memoized_ivar} &amp;&amp; #{memoized_ivar}.has_key?(args)
+              #{memoized_ivar}[args]
             else
-              #{memoized_ivar} = #{original_method}.freeze
+              #{memoized_ivar}[args] = #{original_method}(*args).freeze
             end
           end
         EOS</diff>
      <filename>activesupport/lib/active_support/memoizable.rb</filename>
    </modified>
    <modified>
      <diff>@@ -5,86 +5,174 @@ uses_mocha 'Memoizable' do
     class Person
       extend ActiveSupport::Memoizable
 
-      def name
-        fetch_name_from_floppy
+      attr_reader :name_calls, :age_calls
+      def initialize
+        @name_calls = 0
+        @age_calls = 0
       end
 
-      memoize :name
+      def name
+        @name_calls += 1
+        &quot;Josh&quot;
+      end
 
       def age
+        @age_calls += 1
         nil
       end
 
-      def counter
-        @counter ||= 0
-        @counter += 1
+      memoize :name, :age
+    end
+
+    class Company
+      attr_reader :name_calls
+      def initialize
+        @name_calls = 0
       end
 
-      memoize :age, :counter
+      def name
+        @name_calls += 1
+        &quot;37signals&quot;
+      end
+    end
+
+    module Rates
+      extend ActiveSupport::Memoizable
 
-      private
-        def fetch_name_from_floppy
-          &quot;Josh&quot;
+      attr_reader :sales_tax_calls
+      def sales_tax(price)
+        @sales_tax_calls ||= 0
+        @sales_tax_calls += 1
+        price * 0.1025
+      end
+      memoize :sales_tax
+    end
+
+    class Calculator
+      extend ActiveSupport::Memoizable
+      include Rates
+
+      attr_reader :fib_calls
+      def initialize
+        @fib_calls = 0
+      end
+
+      def fib(n)
+        @fib_calls += 1
+
+        if n == 0 || n == 1
+          n
+        else
+          fib(n - 1) + fib(n - 2)
         end
+      end
+      memoize :fib
+
+      def counter
+        @count ||= 0
+        @count += 1
+      end
+      memoize :counter
     end
 
     def setup
       @person = Person.new
+      @calculator = Calculator.new
     end
 
     def test_memoization
       assert_equal &quot;Josh&quot;, @person.name
+      assert_equal 1, @person.name_calls
 
-      @person.expects(:fetch_name_from_floppy).never
-      2.times { assert_equal &quot;Josh&quot;, @person.name }
+      3.times { assert_equal &quot;Josh&quot;, @person.name }
+      assert_equal 1, @person.name_calls
+    end
+
+    def test_memoization_with_nil_value
+      assert_equal nil, @person.age
+      assert_equal 1, @person.age_calls
+
+      3.times { assert_equal nil, @person.age }
+      assert_equal 1, @person.age_calls
     end
 
     def test_reloadable
-      counter = @person.counter
-      assert_equal 1, @person.counter
-      assert_equal 2, @person.counter(:reload)
+      counter = @calculator.counter
+      assert_equal 1, @calculator.counter
+      assert_equal 2, @calculator.counter(:reload)
+      assert_equal 2, @calculator.counter
+      assert_equal 3, @calculator.counter(true)
+      assert_equal 3, @calculator.counter
     end
 
-    def test_memoized_methods_are_frozen
-      assert_equal true, @person.name.frozen?
+    def test_memoization_cache_is_different_for_each_instance
+      assert_equal 1, @calculator.counter
+      assert_equal 2, @calculator.counter(:reload)
+      assert_equal 1, Calculator.new.counter
+    end
 
+    def test_memoized_is_not_affected_by_freeze
       @person.freeze
       assert_equal &quot;Josh&quot;, @person.name
-      assert_equal true, @person.name.frozen?
     end
 
-    def test_memoization_frozen_with_nil_value
-      @person.freeze
-      assert_equal nil, @person.age
+    def test_memoization_with_args
+      assert_equal 55, @calculator.fib(10)
+      assert_equal 11, @calculator.fib_calls
     end
 
-    def test_double_memoization
-      assert_raise(RuntimeError) { Person.memoize :name }
+    def test_reloadable_with_args
+      assert_equal 55, @calculator.fib(10)
+      assert_equal 11, @calculator.fib_calls
+      assert_equal 55, @calculator.fib(10, :reload)
+      assert_equal 12, @calculator.fib_calls
+      assert_equal 55, @calculator.fib(10, true)
+      assert_equal 13, @calculator.fib_calls
     end
 
-    class Company
-      def name
-        lookup_name
+    def test_object_memoization
+      [Company.new, Company.new, Company.new].each do |company|
+        company.extend ActiveSupport::Memoizable
+        company.memoize :name
+
+        assert_equal &quot;37signals&quot;, company.name
+        assert_equal 1, company.name_calls
+        assert_equal &quot;37signals&quot;, company.name
+        assert_equal 1, company.name_calls
       end
+    end
 
-      def lookup_name
-        &quot;37signals&quot;
-      end
+    def test_memoized_module_methods
+      assert_equal 1.025, @calculator.sales_tax(10)
+      assert_equal 1, @calculator.sales_tax_calls
+      assert_equal 1.025, @calculator.sales_tax(10)
+      assert_equal 1, @calculator.sales_tax_calls
+      assert_equal 2.5625, @calculator.sales_tax(25)
+      assert_equal 2, @calculator.sales_tax_calls
     end
 
-    def test_object_memoization
+    def test_object_memoized_module_methods
       company = Company.new
-      company.extend ActiveSupport::Memoizable
-      company.memoize :name
+      company.extend(Rates)
+
+      assert_equal 1.025, company.sales_tax(10)
+      assert_equal 1, company.sales_tax_calls
+      assert_equal 1.025, company.sales_tax(10)
+      assert_equal 1, company.sales_tax_calls
+      assert_equal 2.5625, company.sales_tax(25)
+      assert_equal 2, company.sales_tax_calls
+    end
 
-      assert_equal &quot;37signals&quot;, company.name
-      # Mocha doesn't play well with frozen objects
-      company.metaclass.instance_eval { define_method(:lookup_name) { b00m } }
-      assert_equal &quot;37signals&quot;, company.name
+    def test_double_memoization
+      assert_raise(RuntimeError) { Person.memoize :name }
+      person = Person.new
+      person.extend ActiveSupport::Memoizable
+      assert_raise(RuntimeError) { person.memoize :name }
 
-      assert_equal true, company.name.frozen?
-      company.freeze
-      assert_equal true, company.name.frozen?
+      company = Company.new
+      company.extend ActiveSupport::Memoizable
+      company.memoize :name
+      assert_raise(RuntimeError) { company.memoize :name }
     end
   end
 end</diff>
      <filename>activesupport/test/memoizable_test.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>8b858782fa693e89a47fc3dd5ae38d842ede6d04</id>
    </parent>
  </parents>
  <author>
    <name>Joshua Peek</name>
    <email>josh@joshpeek.com</email>
  </author>
  <url>http://github.com/rails/rails/commit/8a87d8a6c2c6dfb423bcaf61c750010d80993b16</url>
  <id>8a87d8a6c2c6dfb423bcaf61c750010d80993b16</id>
  <committed-date>2008-07-22T08:26:44-07:00</committed-date>
  <authored-date>2008-07-22T08:26:44-07:00</authored-date>
  <message>Improved Memoizable test coverage and added support for multiple arguments</message>
  <tree>16c43dd83a34f451bc0dbddbd7167ce78ffed351</tree>
  <committer>
    <name>Joshua Peek</name>
    <email>josh@joshpeek.com</email>
  </committer>
</commit>
