Module: MoreCoreExtensions::CacheWithTimeout
- Defined in:
- lib/more_core_extensions/core_ext/module/cache_with_timeout.rb
Defined Under Namespace
Modules: ClassMethods
Instance Method Summary collapse
-
#cache_with_timeout(method, timeout = nil, &block) ⇒ Object
cache_with_timeout creates singleton methods that cache the results of the given block, but only for a short amount of time.
Instance Method Details
#cache_with_timeout(method, timeout = nil, &block) ⇒ Object
cache_with_timeout creates singleton methods that cache the
results of the given block, but only for a short amount of time.
If the method is called again after time has passed, then the
cache is cleared and the block is reevaluated. Note that the
cache is only cleared on the next invocation after the time has
passed, so if the block retains references to large objects,
they will never be garbage collected if the method is never
called again.
The methods created are
- `method`
- `#{method}_clear_cache` - Will clear the cached value on demand
- `#{method}_cached?` - Says whether or not there is a value cached
Example:
class Foo
cache_with_timeout(:expensive_operation) do
sleep 100
rand(100)
end
end
Foo.expensive_operation # => 42
Foo.expensive_operation # => 42
# ... wait 5+ minutes ...
Foo.expensive_operation # => 18
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/more_core_extensions/core_ext/module/cache_with_timeout.rb', line 39 def cache_with_timeout(method, timeout = nil, &block) raise "no block given" if block.nil? raise ArgumentError, "method must be a Symbol" unless method.respond_to?(:to_sym) key = "#{name}.#{method}".to_sym $cache_with_timeout_lock.synchronize(:EX) do $cache_with_timeout[key] = {} end define_singleton_method(method) do |*args| force_reload = args.first return $cache_with_timeout_lock.synchronize(:EX) do cache = $cache_with_timeout[key] old_timeout = cache[:timeout] cache.clear if force_reload || (old_timeout && Time.now.utc > old_timeout) break cache[:value] if cache.key?(:value) new_timeout = timeout || 300 # 5 minutes new_timeout = new_timeout.call if new_timeout.kind_of?(Proc) new_timeout = Time.now.utc + new_timeout new_value = block.call cache[:timeout] = new_timeout cache[:value] = new_value end end define_singleton_method("#{method}_clear_cache") do |*_args| $cache_with_timeout_lock.synchronize(:EX) do $cache_with_timeout[key].clear end end define_singleton_method("#{method}_cached?") do |*_args| $cache_with_timeout_lock.synchronize(:EX) do !$cache_with_timeout[key].empty? end end method.to_sym end |