Skip to content

Commit

Permalink
Changed ActiveSupport::Memoizable API to extend since it mainly adds …
Browse files Browse the repository at this point in the history
…the memoize class method
  • Loading branch information
josh committed Jul 18, 2008
1 parent e1f23da commit ef6f662
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 38 deletions.
4 changes: 2 additions & 2 deletions actionpack/lib/action_view/renderable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ module Renderable
# NOTE: The template that this mixin is beening include into is frozen
# So you can not set or modify any instance variables

extend ActiveSupport::Memoizable

def self.included(base)
@@mutex = Mutex.new
end

include ActiveSupport::Memoizable

def filename
'compiled-template'
end
Expand Down
2 changes: 1 addition & 1 deletion actionpack/lib/action_view/renderable_partial.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module RenderablePartial
# NOTE: The template that this mixin is beening include into is frozen
# So you can not set or modify any instance variables

include ActiveSupport::Memoizable
extend ActiveSupport::Memoizable

def variable_name
name.sub(/\A_/, '').to_sym
Expand Down
2 changes: 1 addition & 1 deletion actionpack/lib/action_view/template.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module ActionView #:nodoc:
class Template
extend TemplateHandlers
include ActiveSupport::Memoizable
extend ActiveSupport::Memoizable
include Renderable

attr_accessor :filename, :load_path, :base_path, :name, :format, :extension
Expand Down
55 changes: 28 additions & 27 deletions activesupport/lib/active_support/memoizable.rb
Original file line number Diff line number Diff line change
@@ -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
42 changes: 35 additions & 7 deletions activesupport/test/memoizable_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,24 @@
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
Expand All @@ -37,9 +40,9 @@ def test_memoization
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
Expand All @@ -58,5 +61,30 @@ def test_memoization_frozen_with_nil_value
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

4 comments on commit ef6f662

@matthewrudy
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh wow.
this includes my :comment saying “it should have a force_reload param”

@matthewrudy
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh wow.
this includes my :comment saying “it should have a force_reload param”

@josh
Copy link
Contributor Author

@josh josh commented on ef6f662 Jul 19, 2008

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really want to accept args too, but it doesn’t mix well with reload. Too bad 1.8 does not support “method(*args, reload = false)”

@josh
Copy link
Contributor Author

@josh josh commented on ef6f662 Jul 19, 2008

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really want to accept args too, but it doesn’t mix well with reload. Too bad 1.8 does not support “method(*args, reload = false)”

Please sign in to comment.