module ActiveCacher

Module for caching results of method invocations. It’s used as follows:

class A

prepend ActiveCacher.instance
instance_cache :foo_a, :foo_b
rails_cache :foo_c

 def foo_a
   # some code
 end
 def foo_b
   # some code
 end
 def foo_c
   # some code
 end

end

Here return values of method calls ‘foo_a’ and ‘foo_b’ will be cached into instance variables ‘@_foo_a’ and ‘@__foo_b’ while result of method call ‘foo_c’ will be both cached into instance variable ‘@_foo_c’ and written to Rails cache.

Calling ‘instance_cache :foo_a’ is roughly equivalent to the following code:

def foo_a

@__foo_a ||= begin
  # some code
end

end

And calling ‘rails_cache :foo_c’ is roughly equivalent to the following code:

def foo_c

@__foo_c ||= Rails.cache.fetch [self, :foo_c] do
  # some code
end

end

Constants

VERSION

Public Class Methods

instance() click to toggle source

It’s important to prepend module’s clone (obtained with ‘instance’ class method) instead of module itself since decorated methods are defined in ActiveCacher module and prepending ActiveCacher in multiple classes might result into method name clashes with unpredictable consequences.

# File lib/active_cacher.rb, line 47
def self.instance
  cloned = clone
  cloned.instance_variable_set "@cloned", true
  cloned
end
prepended(target) click to toggle source
Calls superclass method
# File lib/active_cacher.rb, line 53
def self.prepended target
  raise "do not prepend ActiveCacher - prepend ActiveCacher.instance instead" unless @cloned
  cacher = self

  target.send :define_singleton_method, :instance_cache do |*methods|
    methods.each do |method|
      escaped_method = method.to_s.include?('?') ? "is_#{method[0..-2]}" : method

      cacher.send :define_method, method do |*args|
        instance_variable_get("@__#{escaped_method}") ||
          instance_variable_set("@__#{escaped_method}", prepare_for_cache(super(*args)))
      end
    end
  end

  if defined?(Rails)
    target.send :define_singleton_method, :rails_cache do |*methods|
      methods.each do |method|
        escaped_method = method.to_s.include?('?') ? "is_#{method[0..-2]}" : method

        cacher.send :define_method, method do |*args|
          instance_variable_get("@__#{escaped_method}") ||
            instance_variable_set("@__#{escaped_method}", Rails.cache.fetch([cache_key_object, method], expires_in: 2.weeks) { prepare_for_cache(super(*args)) })
        end
      end
    end
  end
end

Private Instance Methods

cache_key_object() click to toggle source
# File lib/active_cacher.rb, line 83
def cache_key_object
  defined?(Draper::Decorator) && object.kind_of?(Draper::Decorator) ? object : self
end
prepare_for_cache(object) click to toggle source
# File lib/active_cacher.rb, line 87
def prepare_for_cache object
  defined?(ActiveRecord::Relation) && object.kind_of?(ActiveRecord::Relation) ? object.to_a : object
end