Skip to content
Browse files

Allow memoized methods to be reloaded and allow multiple symbols

  • Loading branch information...
1 parent 7430c41 commit e1f23da53cef20a60e4bf458d959fe2bfe7d52ea @josh josh committed
Showing with 43 additions and 28 deletions.
  1. +17 −15 activesupport/lib/active_support/memoizable.rb
  2. +26 −13 activesupport/test/memoizable_test.rb
View
32 activesupport/lib/active_support/memoizable.rb
@@ -5,28 +5,30 @@ def self.included(base) #:nodoc:
end
module ClassMethods
- def memoize(symbol)
- original_method = "_unmemoized_#{symbol}"
- memoized_ivar = "@_memoized_#{symbol}"
- raise "Already memoized #{symbol}" if instance_methods.map(&:to_s).include?(original_method)
+ 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}
- if defined? #{memoized_ivar}
- #{memoized_ivar}
- else
- #{memoized_ivar} = #{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
end
- end
- EOS
+ EOS
+ end
end
end
def freeze
methods.each do |method|
- if m = method.to_s.match(/\A_unmemoized_(.*)/)
- send(m[1]).freeze
+ if m = method.to_s.match(/\Aunmemoized_(.*)/)
+ send(m[1])
end
end
super
View
39 activesupport/test/memoizable_test.rb
@@ -8,12 +8,16 @@ class Person
def name
fetch_name_from_floppy
end
- memoize :name
def age
nil
end
- memoize :age
+
+ def random
+ rand(0)
+ end
+
+ memoize :name, :age, :random
private
def fetch_name_from_floppy
@@ -21,25 +25,34 @@ def fetch_name_from_floppy
end
end
+ def setup
+ @person = Person.new
+ end
+
def test_memoization
- person = Person.new
- assert_equal "Josh", person.name
+ assert_equal "Josh", @person.name
+
+ @person.expects(:fetch_name_from_floppy).never
+ 2.times { assert_equal "Josh", @person.name }
+ end
- person.expects(:fetch_name_from_floppy).never
- 2.times { assert_equal "Josh", person.name }
+ def test_reloadable
+ random = @person.random
+ assert_equal random, @person.random
+ assert_not_equal random, @person.random(:reload)
@DefV
DefV added a note

This test will not always pass :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
end
def test_memoized_methods_are_frozen
- person = Person.new
- person.freeze
- assert_equal "Josh", person.name
- assert_equal true, person.name.frozen?
+ assert_equal true, @person.name.frozen?
+
+ @person.freeze
+ assert_equal "Josh", @person.name
+ assert_equal true, @person.name.frozen?
end
def test_memoization_frozen_with_nil_value
- person = Person.new
- person.freeze
- assert_equal nil, person.age
+ @person.freeze
+ assert_equal nil, @person.age
end
def test_double_memoization

2 comments on commit e1f23da

@NZKoz
Ruby on Rails member

Unless it’s run on debian

@nbibler

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.

Please sign in to comment.
Something went wrong with that request. Please try again.