File: active_support/cache.rb

Overview
Module Structure
Class Hierarchy
Code

Overview

Module Structure

  module: <Toplevel Module>
  module: ActiveSupport#3
  module: Cache#5
has properties
module method: lookup_store / 1 #42
module method: expand_cache_key / 2 #57
  module: Strategy#13
  class: Store#91
inherits from
  Object ( Builtin-Module )
has properties
attribute: silence [R] #94
attribute: logger_off [R] #94
method: silence! #96
alias: silence? silence #101
alias: logger_off? logger_off #102
method: mute #104
method: fetch / 2 #151
method: read / 2 #181
method: write / 3 #200
method: delete / 2 #204
method: delete_matched / 2 #208
method: exist? / 2 #212
method: increment / 2 #216
method: decrement / 2 #225
method: expires_in / 1 #235
method: log / 3 #243

Class Hierarchy

Code

   1  require 'benchmark'
   2 
   3  module ActiveSupport
   4    # See ActiveSupport::Cache::Store for documentation.
   5    module Cache
   6      autoload :FileStore, 'active_support/cache/file_store'
   7      autoload :MemoryStore, 'active_support/cache/memory_store'
   8      autoload :SynchronizedMemoryStore, 'active_support/cache/synchronized_memory_store'
   9      autoload :DRbStore, 'active_support/cache/drb_store'
  10      autoload :MemCacheStore, 'active_support/cache/mem_cache_store'
  11      autoload :CompressedMemCacheStore, 'active_support/cache/compressed_mem_cache_store'
  12 
  13      module Strategy
  14        autoload :LocalCache, 'active_support/cache/strategy/local_cache'
  15      end
  16 
  17      # Creates a new CacheStore object according to the given options.
  18      #
  19      # If no arguments are passed to this method, then a new
  20      # ActiveSupport::Cache::MemoryStore object will be returned.
  21      #
  22      # If you pass a Symbol as the first argument, then a corresponding cache
  23      # store class under the ActiveSupport::Cache namespace will be created.
  24      # For example:
  25      #
  26      #   ActiveSupport::Cache.lookup_store(:memory_store)
  27      #   # => returns a new ActiveSupport::Cache::MemoryStore object
  28      #   
  29      #   ActiveSupport::Cache.lookup_store(:drb_store)
  30      #   # => returns a new ActiveSupport::Cache::DRbStore object
  31      #
  32      # Any additional arguments will be passed to the corresponding cache store
  33      # class's constructor:
  34      #
  35      #   ActiveSupport::Cache.lookup_store(:file_store, "/tmp/cache")
  36      #   # => same as: ActiveSupport::Cache::FileStore.new("/tmp/cache")
  37      #
  38      # If the first argument is not a Symbol, then it will simply be returned:
  39      #
  40      #   ActiveSupport::Cache.lookup_store(MyOwnCacheStore.new)
  41      #   # => returns MyOwnCacheStore.new
  42      def self.lookup_store(*store_option)
  43        store, *parameters = *([ store_option ].flatten)
  44 
  45        case store
  46        when Symbol
  47          store_class_name = (store == :drb_store ? "DRbStore" : store.to_s.camelize)
  48          store_class = ActiveSupport::Cache.const_get(store_class_name)
  49          store_class.new(*parameters)
  50        when nil
  51          ActiveSupport::Cache::MemoryStore.new
  52        else
  53          store
  54        end
  55      end
  56 
  57      def self.expand_cache_key(key, namespace = nil)
  58        expanded_cache_key = namespace ? "#{namespace}/" : ""
  59 
  60        if ENV["RAILS_CACHE_ID"] || ENV["RAILS_APP_VERSION"]
  61          expanded_cache_key << "#{ENV["RAILS_CACHE_ID"] || ENV["RAILS_APP_VERSION"]}/"
  62        end
  63 
  64        expanded_cache_key << case
  65          when key.respond_to?(:cache_key)
  66            key.cache_key
  67          when key.is_a?(Array)
  68            key.collect { |element| expand_cache_key(element) }.to_param
  69          when key
  70            key.to_param
  71          end.to_s
  72 
  73        expanded_cache_key
  74      end
  75 
  76      # An abstract cache store class. There are multiple cache store
  77      # implementations, each having its own additional features. See the classes
  78      # under the ActiveSupport::Cache module, e.g.
  79      # ActiveSupport::Cache::MemCacheStore. MemCacheStore is currently the most
  80      # popular cache store for large production websites.
  81      #
  82      # ActiveSupport::Cache::Store is meant for caching strings. Some cache
  83      # store implementations, like MemoryStore, are able to cache arbitrary
  84      # Ruby objects, but don't count on every cache store to be able to do that.
  85      #
  86      #   cache = ActiveSupport::Cache::MemoryStore.new
  87      #   
  88      #   cache.read("city")   # => nil
  89      #   cache.write("city", "Duckburgh")
  90      #   cache.read("city")   # => "Duckburgh"
  91      class Store
  92        cattr_accessor :logger
  93 
  94        attr_reader :silence, :logger_off
  95 
  96        def silence!
  97          @silence = true
  98          self
  99        end
 100 
 101        alias silence? silence
 102        alias logger_off? logger_off
 103 
 104        def mute
 105          previous_silence, @silence = defined?(@silence) && @silence, true
 106          yield
 107        ensure
 108          @silence = previous_silence
 109        end
 110 
 111        # Fetches data from the cache, using the given key. If there is data in
 112        # the cache with the given key, then that data is returned.
 113        #
 114        # If there is no such data in the cache (a cache miss occurred), then
 115        # then nil will be returned. However, if a block has been passed, then
 116        # that block will be run in the event of a cache miss. The return value
 117        # of the block will be written to the cache under the given cache key,
 118        # and that return value will be returned.
 119        #
 120        #   cache.write("today", "Monday")
 121        #   cache.fetch("today")  # => "Monday"
 122        #   
 123        #   cache.fetch("city")   # => nil
 124        #   cache.fetch("city") do
 125        #     "Duckburgh"
 126        #   end
 127        #   cache.fetch("city")   # => "Duckburgh"
 128        #
 129        # You may also specify additional options via the +options+ argument.
 130        # Setting <tt>:force => true</tt> will force a cache miss:
 131        #
 132        #   cache.write("today", "Monday")
 133        #   cache.fetch("today", :force => true)  # => nil
 134        #
 135        # Other options will be handled by the specific cache store implementation.
 136        # Internally, #fetch calls #read, and calls #write on a cache miss.
 137        # +options+ will be passed to the #read and #write calls.
 138        #
 139        # For example, MemCacheStore's #write method supports the +:expires_in+
 140        # option, which tells the memcached server to automatically expire the
 141        # cache item after a certain period. We can use this option with #fetch
 142        # too:
 143        #
 144        #   cache = ActiveSupport::Cache::MemCacheStore.new
 145        #   cache.fetch("foo", :force => true, :expires_in => 5.seconds) do
 146        #     "bar"
 147        #   end
 148        #   cache.fetch("foo")  # => "bar"
 149        #   sleep(6)
 150        #   cache.fetch("foo")  # => nil
 151        def fetch(key, options = {})
 152          @logger_off = true
 153          if !options[:force] && value = read(key, options)
 154            @logger_off = false
 155            log("hit", key, options)
 156            value
 157          elsif block_given?
 158            @logger_off = false
 159            log("miss", key, options)
 160 
 161            value = nil
 162            ms = Benchmark.ms { value = yield }
 163 
 164            @logger_off = true
 165            write(key, value, options)
 166            @logger_off = false
 167 
 168            log('write (will save %.2fms)' % ms, key, nil)
 169 
 170            value
 171          end
 172        end
 173 
 174        # Fetches data from the cache, using the given key. If there is data in
 175        # the cache with the given key, then that data is returned. Otherwise,
 176        # nil is returned.
 177        #
 178        # You may also specify additional options via the +options+ argument.
 179        # The specific cache store implementation will decide what to do with
 180        # +options+.
 181        def read(key, options = nil)
 182          log("read", key, options)
 183        end
 184 
 185        # Writes the given value to the cache, with the given key.
 186        #
 187        # You may also specify additional options via the +options+ argument.
 188        # The specific cache store implementation will decide what to do with
 189        # +options+.
 190        # 
 191        # For example, MemCacheStore supports the +:expires_in+ option, which
 192        # tells the memcached server to automatically expire the cache item after
 193        # a certain period:
 194        #
 195        #   cache = ActiveSupport::Cache::MemCacheStore.new
 196        #   cache.write("foo", "bar", :expires_in => 5.seconds)
 197        #   cache.read("foo")  # => "bar"
 198        #   sleep(6)
 199        #   cache.read("foo")  # => nil
 200        def write(key, value, options = nil)
 201          log("write", key, options)
 202        end
 203 
 204        def delete(key, options = nil)
 205          log("delete", key, options)
 206        end
 207 
 208        def delete_matched(matcher, options = nil)
 209          log("delete matched", matcher.inspect, options)
 210        end
 211 
 212        def exist?(key, options = nil)
 213          log("exist?", key, options)
 214        end
 215 
 216        def increment(key, amount = 1)
 217          log("incrementing", key, amount)
 218          if num = read(key)
 219            write(key, num + amount)
 220          else
 221            nil
 222          end
 223        end
 224 
 225        def decrement(key, amount = 1)
 226          log("decrementing", key, amount)
 227          if num = read(key)
 228            write(key, num - amount)
 229          else
 230            nil
 231          end
 232        end
 233 
 234        private
 235          def expires_in(options)
 236            expires_in = options && options[:expires_in]
 237 
 238            raise ":expires_in must be a number" if expires_in && !expires_in.is_a?(Numeric)
 239 
 240            expires_in || 0
 241          end
 242 
 243          def log(operation, key, options)
 244            logger.debug("Cache #{operation}: #{key}#{options ? " (#{options.inspect})" : ""}") if logger && !silence? && !logger_off?
 245          end
 246      end
 247    end
 248  end