From ef6f6625c91ea789a033799f649e4388e4a71045 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Fri, 18 Jul 2008 15:32:28 -0500 Subject: Changed ActiveSupport::Memoizable API to extend since it mainly adds the memoize class method --- activesupport/lib/active_support/memoizable.rb | 55 +++++++++++++------------- activesupport/test/memoizable_test.rb | 42 ++++++++++++++++---- 2 files changed, 63 insertions(+), 34 deletions(-) (limited to 'activesupport') diff --git a/activesupport/lib/active_support/memoizable.rb b/activesupport/lib/active_support/memoizable.rb index c41feef4c7..59fecbecb1 100644 --- a/activesupport/lib/active_support/memoizable.rb +++ b/activesupport/lib/active_support/memoizable.rb @@ -1,37 +1,38 @@ module ActiveSupport - module Memoizable - def self.included(base) #:nodoc: - base.extend(ClassMethods) - end - - module ClassMethods - def memoize(*symbols) - symbols.each do |symbol| - original_method = "unmemoized_#{symbol}" - memoized_ivar = "@#{symbol}" - raise "Already memoized #{symbol}" if instance_methods.map(&:to_s).include?(original_method) - - alias_method original_method, symbol - class_eval <<-EOS, __FILE__, __LINE__ - def #{symbol}(reload = false) - if !reload && defined? #{memoized_ivar} - #{memoized_ivar} - else - #{memoized_ivar} = #{original_method}.freeze - end + module Memoizable #:nodoc: + def self.extended(obj) + klass = obj.respond_to?(:class_eval) ? obj : obj.metaclass + klass.class_eval do + def freeze + methods.each do |method| + if m = method.to_s.match(/^unmemoized_(.*)/) + send(m[1]) end - EOS + end + super end end end - def freeze - methods.each do |method| - if m = method.to_s.match(/\Aunmemoized_(.*)/) - send(m[1]) - end + def memoize(*symbols) + symbols.each do |symbol| + original_method = "unmemoized_#{symbol}" + memoized_ivar = "@#{symbol}" + + klass = respond_to?(:class_eval) ? self : self.metaclass + raise "Already memoized #{symbol}" if klass.instance_methods.map(&:to_s).include?(original_method) + + klass.class_eval <<-EOS, __FILE__, __LINE__ + alias_method :#{original_method}, :#{symbol} + def #{symbol}(reload = false) + if !reload && defined? #{memoized_ivar} + #{memoized_ivar} + else + #{memoized_ivar} = #{original_method}.freeze + end + end + EOS end - super end end end diff --git a/activesupport/test/memoizable_test.rb b/activesupport/test/memoizable_test.rb index b649b31455..79769631ad 100644 --- a/activesupport/test/memoizable_test.rb +++ b/activesupport/test/memoizable_test.rb @@ -3,21 +3,24 @@ require 'abstract_unit' uses_mocha 'Memoizable' do class MemoizableTest < Test::Unit::TestCase class Person - include ActiveSupport::Memoizable + extend ActiveSupport::Memoizable def name fetch_name_from_floppy end + memoize :name + def age nil end - def random - rand(0) + def counter + @counter ||= 0 + @counter += 1 end - memoize :name, :age, :random + memoize :age, :counter private def fetch_name_from_floppy @@ -37,9 +40,9 @@ uses_mocha 'Memoizable' do end def test_reloadable - random = @person.random - assert_equal random, @person.random - assert_not_equal random, @person.random(:reload) + counter = @person.counter + assert_equal 1, @person.counter + assert_equal 2, @person.counter(:reload) end def test_memoized_methods_are_frozen @@ -58,5 +61,30 @@ uses_mocha 'Memoizable' do def test_double_memoization assert_raise(RuntimeError) { Person.memoize :name } end + + class Company + def name + lookup_name + end + + def lookup_name + "37signals" + end + end + + def test_object_memoization + company = Company.new + company.extend ActiveSupport::Memoizable + company.memoize :name + + assert_equal "37signals", company.name + # Mocha doesn't play well with frozen objects + company.metaclass.instance_eval { define_method(:lookup_name) { b00m } } + assert_equal "37signals", company.name + + assert_equal true, company.name.frozen? + company.freeze + assert_equal true, company.name.frozen? + end end end -- cgit v1.2.3