Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Memoize errors #20

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 40 additions & 16 deletions lib/memoist.rb
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,22 @@ def flush_cache(*method_names)
end
end

class Result
attr_reader :error, :value

def initialize
begin
@value = yield
rescue => e
@error = e
end
end

def fetch
error ? raise(error) : value
end
end

def memoize(*method_names)
if method_names.last.is_a?(Hash)
identifier = method_names.pop[:identifier]
Expand All @@ -109,16 +125,18 @@ def memoize(*method_names)
# set_cache = skip_cache && !frozen?
#
# if skip_cache
# value = _unmemoized_mime_type
# result = ::Memoist::Result.new do
# _unmemoized_mime_type
# end
# else
# value = @_memoized_mime_type
# result = @_memoized_mime_type
# end
#
# if set_cache
# @_memoized_mime_type = value
# @_memoized_mime_type = result
# end
#
# value
# result.fetch
# end

module_eval <<-EOS, __FILE__, __LINE__ + 1
Expand All @@ -127,16 +145,18 @@ def #{method_name}(reload = false)
set_cache = skip_cache && !frozen?

if skip_cache
value = #{unmemoized_method}
result = ::Memoist::Result.new do
#{unmemoized_method}
end
else
value = #{memoized_ivar}
result = #{memoized_ivar}
end

if set_cache
#{memoized_ivar} = value
#{memoized_ivar} = result
end

value
result.fetch
end
EOS
else
Expand All @@ -150,17 +170,19 @@ def #{method_name}(reload = false)
# set_cache = skip_cache && !frozen
#
# if skip_cache
# value = _unmemoized_mime_type(*args)
# result = ::Memoist::Result.new do
# _unmemoized_mime_type(*args)
# end
# else
# value = @_memoized_mime_type[args]
# result = @_memoized_mime_type[args]
# end
#
# if set_cache
# @_memoized_mime_type ||= {}
# @_memoized_mime_type[args] = value
# @_memoized_mime_type[args] = result
# end
#
# value
# result.fetch
# end

module_eval <<-EOS, __FILE__, __LINE__ + 1
Expand All @@ -171,17 +193,19 @@ def #{method_name}(*args)
set_cache = skip_cache && !frozen?

if skip_cache
value = #{unmemoized_method}(*args)
result = ::Memoist::Result.new do
#{unmemoized_method}(*args)
end
else
value = #{memoized_ivar}[args]
result = #{memoized_ivar}[args]
end

if set_cache
#{memoized_ivar} ||= {}
#{memoized_ivar}[args] = value
#{memoized_ivar}[args] = result
end

value
result.fetch
end
EOS
end
Expand Down
43 changes: 42 additions & 1 deletion test/memoist_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,10 @@ class Calculator
extend Memoist
include Rates

attr_reader :fib_calls
attr_reader :fib_calls, :divide_by_zero_calls
def initialize
@fib_calls = 0
@divide_by_zero_calls = 0
end

def fib(n)
Expand Down Expand Up @@ -172,6 +173,12 @@ def counter
@count += 1
end
memoize :counter

def divide_by_zero(x)
@divide_by_zero_calls += 1
x / 0
end
memoize :divide_by_zero
end

def setup
Expand Down Expand Up @@ -380,4 +387,38 @@ def test_private_method_memoization
assert_equal 1, person.is_developer_calls
end

def test_memoization_with_an_error
assert_equal 0, @calculator.divide_by_zero_calls

error123 = assert_raises(ZeroDivisionError) do
@calculator.divide_by_zero 123
end
assert_equal 1, @calculator.divide_by_zero_calls

e = assert_raises(ZeroDivisionError) do
@calculator.divide_by_zero 123
end
assert_same error123, e
assert_equal 1, @calculator.divide_by_zero_calls

error456 = assert_raises(ZeroDivisionError) do
@calculator.divide_by_zero 456
end
assert_equal 2, @calculator.divide_by_zero_calls

e = assert_raises(ZeroDivisionError) do
@calculator.divide_by_zero 456
end
assert_same error456, e
assert_equal 2, @calculator.divide_by_zero_calls

refute_same error123, error456

e = assert_raises(ZeroDivisionError) do
@calculator.divide_by_zero 456, :reload
end
refute_same error456, e
assert_equal 3, @calculator.divide_by_zero_calls
end

end