aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoshua Peek <josh@joshpeek.com>2008-07-14 19:50:32 -0500
committerJoshua Peek <josh@joshpeek.com>2008-07-14 19:50:32 -0500
commit8a9934a9d9fc98b56c4566ae2e3fd4d83e505d3e (patch)
treefe7ed2626140178c722f5245d37b23c311da5ce4
parentd27dd860c7f4f9b9e5aebe7d0c6e9b6108d8717c (diff)
downloadrails-8a9934a9d9fc98b56c4566ae2e3fd4d83e505d3e.tar.gz
rails-8a9934a9d9fc98b56c4566ae2e3fd4d83e505d3e.tar.bz2
rails-8a9934a9d9fc98b56c4566ae2e3fd4d83e505d3e.zip
Added Memoizable mixin for caching simple lazy loaded attributes
-rw-r--r--activesupport/CHANGELOG2
-rw-r--r--activesupport/lib/active_support.rb1
-rw-r--r--activesupport/lib/active_support/memoizable.rb32
-rw-r--r--activesupport/test/memoizable_test.rb45
4 files changed, 80 insertions, 0 deletions
diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG
index 983e7d0dac..0c308a1cfe 100644
--- a/activesupport/CHANGELOG
+++ b/activesupport/CHANGELOG
@@ -1,5 +1,7 @@
*Edge*
+* Added Memoizable mixin for caching simple lazy loaded attributes [Josh Peek]
+
* Move the test related core_ext stuff out of core_ext so it's only loaded by the test helpers. [Michael Koziarski]
* Add Inflection rules for String#humanize. #535 [dcmanges]
diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb
index 1a8603e892..0526057b15 100644
--- a/activesupport/lib/active_support.rb
+++ b/activesupport/lib/active_support.rb
@@ -43,6 +43,7 @@ require 'active_support/ordered_hash'
require 'active_support/ordered_options'
require 'active_support/option_merger'
+require 'active_support/memoizable'
require 'active_support/string_inquirer'
require 'active_support/values/time_zone'
diff --git a/activesupport/lib/active_support/memoizable.rb b/activesupport/lib/active_support/memoizable.rb
new file mode 100644
index 0000000000..c78fb0a793
--- /dev/null
+++ b/activesupport/lib/active_support/memoizable.rb
@@ -0,0 +1,32 @@
+module ActiveSupport
+ module Memoizable
+ def self.included(base) #:nodoc:
+ base.extend(ClassMethods)
+ end
+
+ module ClassMethods
+ def memorize(symbol)
+ original_method = "_unmemorized_#{symbol}"
+ alias_method original_method, symbol
+ class_eval <<-EOS, __FILE__, __LINE__
+ def #{symbol}
+ if instance_variable_defined?(:@#{symbol})
+ @#{symbol}
+ else
+ @#{symbol} = #{original_method}
+ end
+ end
+ EOS
+ end
+ end
+
+ def freeze
+ methods.each do |method|
+ if m = method.to_s.match(/^_unmemorized_(.*)/)
+ send(m[1]).freeze
+ end
+ end
+ super
+ end
+ end
+end
diff --git a/activesupport/test/memoizable_test.rb b/activesupport/test/memoizable_test.rb
new file mode 100644
index 0000000000..40a02cf253
--- /dev/null
+++ b/activesupport/test/memoizable_test.rb
@@ -0,0 +1,45 @@
+require 'abstract_unit'
+
+uses_mocha 'Memoizable' do
+ class MemoizableTest < Test::Unit::TestCase
+ class Person
+ include ActiveSupport::Memoizable
+
+ def name
+ fetch_name_from_floppy
+ end
+ memorize :name
+
+ def age
+ nil
+ end
+ memorize :age
+
+ private
+ def fetch_name_from_floppy
+ "Josh"
+ end
+ end
+
+ def test_memoization
+ person = Person.new
+ assert_equal "Josh", person.name
+
+ person.expects(:fetch_name_from_floppy).never
+ 2.times { assert_equal "Josh", person.name }
+ end
+
+ def test_memoized_methods_are_frozen
+ person = Person.new
+ 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
+ end
+ end
+end