require 'memcached' require 'trigga/param_fu' module Itrigga module Cache @default_cache_type = :filecache def self.included(base) base.extend(ClassMethods) base.send(:include, InstanceMethods) base.send(:include, Trigga::ParamFu) base.send(:include, ControllerMethods) if defined?(ActionController::Base) && base.ancestors.include?(ActionController::Base) end def self.setup!(opts ={}) @default_cache_type = opts[:backend] if opts[:backend] if opts[:backend] == :memcached Itrigga::Cache::Memcache.setup!(opts) else Itrigga::Cache::Filecache.setup!(opts) end end def self.instance(opts = {}) case ( opts[:backend] ||= @default_cache_type ) when :memcached Itrigga::Cache::Memcache.instance when :filecache Itrigga::Cache::Filecache.instance else nil end end module InstanceMethods def with_cache(opts = {}, &block) self.class.with_cache(opts, &block) end def caching_enabled?(opts = {}) self.class.caching_enabled?(opts) end def get_from_cache(key, opts = {}) self.class.get_from_cache(key, opts) end def set_to_cache(key, value, opts = {}) self.class.set_to_cache(key, value, opts) end def delete_from_cache(key, opts = {}) self.class.delete_from_cache(key, opts) end def cache_log(text, opts = {}) self.class.cache_log(text, opts) end end module ClassMethods def with_cache(opts = {}, &block) require_param(opts, :key) # if no cache then just return whatever the block gives us unless caching_enabled?(opts) cache_log "Cache not enabled!", opts return block.call end # see if the key is already in cache value = get_from_cache(opts[:key], opts) # if no match then call the block and save result in cache unless value cache_log "Key '#{opts[:key]}' missing! Calling block and setting in cache", opts value = block.call set_to_cache(opts.delete(:key), value, opts) rescue value # incase memcache crashes or whateversolr1-internal-itrigga.dyndns-ip.com solr1-internal-itrigga.dyndns-ip.com else cache_log "Key '#{opts[:key]}' found in cache!", opts end value end def caching_enabled?(opts = {}) Itrigga::Cache.instance(opts).enabled == true end def get_from_cache(key, opts = {}) return nil unless caching_enabled?(opts) cache_log "get_from_cache key: #{key}, opts: #{opts.inspect}" if opts[:debug] begin Itrigga::Cache.instance(opts).get key rescue Memcached::NotFound => not_found # we dont care nil rescue Exception => e cache_log "Exception in get_from_cache: #{e.message}" nil end end def set_to_cache(key, value, opts = {}) raise "Cache not Enabled" unless caching_enabled?(opts) cache_log "set_to_cache key: #{key}, value: #{value}, opts: #{opts.inspect}" if opts[:debug] begin Itrigga::Cache.instance(opts).set key, value, opts rescue Exception => e cache_log "Exception in set_to_cache: #{e.message}" end value end def delete_from_cache(key, opts = {}) return nil unless caching_enabled?(opts) begin cache_log "Deleting key #{key}", opts Itrigga::Cache.instance(opts).delete key rescue Exception => e nil end end def cache_log(text, opts = {}) message = "[CACHE] [#{opts[:backend] }] #{text}" defined?(Rails.logger) && Rails.logger ? Rails.logger.info(message) : puts(message) end end module ControllerMethods def with_controller_cache( opts = {}, &block ) if caching_enabled?(opts) opts[:key] = opts[:cache_key] || opts[:key] || (respond_to?(:cache_key) ? cache_key.to_s : nil) # backwards compat using :cache_key raise ArgumentError("No cache key found") unless opts[:key] begin if params && params.kind_of?(Hash) && params["freshen"] delete_from_cache opts[:key], opts end @content = with_cache(opts, &block) @content ||= render_to_string unless performed? rescue Exception => ex cache_log "Error when rendering cache block: #{ex.message}", opts @content ||= block.call @content ||= render_to_string unless performed? end # flashes need to be rendered and replaced every request if we're in a html request render_flashes if request.format.html? && respond_to?(:render_flashes) else # cache is not enabled so just render the block cache_log "Cache not enabled!", opts @content ||= block.call @content ||= render_to_string unless performed? end render(:text=>@content, :content_type=>( @content_type || "text/html"), :status=>@status) unless performed? @content end end end end