sreeix-cache-money 0.2.24.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +201 -0
- data/README +210 -0
- data/README.markdown +210 -0
- data/TODO +17 -0
- data/UNSUPPORTED_FEATURES +13 -0
- data/config/environment.rb +16 -0
- data/config/memcached.yml +6 -0
- data/db/schema.rb +18 -0
- data/init.rb +1 -0
- data/lib/cache_money.rb +91 -0
- data/lib/cash/accessor.rb +83 -0
- data/lib/cash/buffered.rb +129 -0
- data/lib/cash/config.rb +75 -0
- data/lib/cash/fake.rb +83 -0
- data/lib/cash/finders.rb +38 -0
- data/lib/cash/index.rb +214 -0
- data/lib/cash/local.rb +76 -0
- data/lib/cash/lock.rb +63 -0
- data/lib/cash/mock.rb +154 -0
- data/lib/cash/query/abstract.rb +210 -0
- data/lib/cash/query/calculation.rb +45 -0
- data/lib/cash/query/primary_key.rb +50 -0
- data/lib/cash/query/select.rb +16 -0
- data/lib/cash/request.rb +3 -0
- data/lib/cash/transactional.rb +43 -0
- data/lib/cash/util/array.rb +9 -0
- data/lib/cash/util/marshal.rb +19 -0
- data/lib/cash/write_through.rb +69 -0
- data/lib/mem_cached_session_store.rb +49 -0
- data/lib/mem_cached_support_store.rb +135 -0
- data/lib/memcached_wrapper.rb +263 -0
- data/rails/init.rb +38 -0
- data/spec/cash/accessor_spec.rb +159 -0
- data/spec/cash/active_record_spec.rb +224 -0
- data/spec/cash/buffered_spec.rb +9 -0
- data/spec/cash/calculations_spec.rb +78 -0
- data/spec/cash/finders_spec.rb +430 -0
- data/spec/cash/local_buffer_spec.rb +9 -0
- data/spec/cash/local_spec.rb +9 -0
- data/spec/cash/lock_spec.rb +108 -0
- data/spec/cash/marshal_spec.rb +60 -0
- data/spec/cash/order_spec.rb +138 -0
- data/spec/cash/shared.rb +62 -0
- data/spec/cash/transactional_spec.rb +578 -0
- data/spec/cash/window_spec.rb +195 -0
- data/spec/cash/write_through_spec.rb +245 -0
- data/spec/memcached_wrapper_test.rb +209 -0
- data/spec/spec_helper.rb +60 -0
- metadata +151 -0
    
        data/db/schema.rb
    ADDED
    
    | @@ -0,0 +1,18 @@ | |
| 1 | 
            +
            ActiveRecord::Schema.define(:version => 2) do
         | 
| 2 | 
            +
              create_table "stories", :force => true do |t|
         | 
| 3 | 
            +
                t.string "title", "subtitle"
         | 
| 4 | 
            +
                t.string  "type"
         | 
| 5 | 
            +
                t.boolean "published"
         | 
| 6 | 
            +
              end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              create_table "characters", :force => true do |t|
         | 
| 9 | 
            +
                t.integer "story_id"
         | 
| 10 | 
            +
                t.string "name"
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
              
         | 
| 13 | 
            +
              create_table :sessions, :force => true do |t|
         | 
| 14 | 
            +
                t.string :session_id
         | 
| 15 | 
            +
                t.text   :data
         | 
| 16 | 
            +
                t.timestamps
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
            end
         | 
    
        data/init.rb
    ADDED
    
    | @@ -0,0 +1 @@ | |
| 1 | 
            +
            require File.join(File.basedir(__FILE__),'rails','init')
         | 
    
        data/lib/cache_money.rb
    ADDED
    
    | @@ -0,0 +1,91 @@ | |
| 1 | 
            +
            require 'active_support'
         | 
| 2 | 
            +
            require 'active_record'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            require 'cash/lock'
         | 
| 5 | 
            +
            require 'cash/transactional'
         | 
| 6 | 
            +
            require 'cash/write_through'
         | 
| 7 | 
            +
            require 'cash/finders'
         | 
| 8 | 
            +
            require 'cash/buffered'
         | 
| 9 | 
            +
            require 'cash/index'
         | 
| 10 | 
            +
            require 'cash/config'
         | 
| 11 | 
            +
            require 'cash/accessor'
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            require 'cash/request'
         | 
| 14 | 
            +
            require 'cash/fake'
         | 
| 15 | 
            +
            require 'cash/local'
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            require 'cash/query/abstract'
         | 
| 18 | 
            +
            require 'cash/query/select'
         | 
| 19 | 
            +
            require 'cash/query/primary_key'
         | 
| 20 | 
            +
            require 'cash/query/calculation'
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            require 'cash/util/array'
         | 
| 23 | 
            +
            require 'cash/util/marshal'
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            class ActiveRecord::Base
         | 
| 26 | 
            +
              def self.is_cached(options = {})
         | 
| 27 | 
            +
                if options == false
         | 
| 28 | 
            +
                  include NoCash
         | 
| 29 | 
            +
                else
         | 
| 30 | 
            +
                  options.assert_valid_keys(:ttl, :repository, :version)
         | 
| 31 | 
            +
                  include Cash unless ancestors.include?(Cash)
         | 
| 32 | 
            +
                  Cash::Config.create(self, options)
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
              def <=>(other)
         | 
| 37 | 
            +
                if self.id == other.id then 
         | 
| 38 | 
            +
                  0
         | 
| 39 | 
            +
                else
         | 
| 40 | 
            +
                  self.id < other.id ? -1 : 1
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
              end
         | 
| 43 | 
            +
            end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
            module Cash
         | 
| 46 | 
            +
              def self.included(active_record_class)
         | 
| 47 | 
            +
                active_record_class.class_eval do
         | 
| 48 | 
            +
                  include Config, Accessor, WriteThrough, Finders
         | 
| 49 | 
            +
                  extend ClassMethods
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
              end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
              module ClassMethods
         | 
| 54 | 
            +
                def self.extended(active_record_class)
         | 
| 55 | 
            +
                  class << active_record_class
         | 
| 56 | 
            +
                    alias_method_chain :transaction, :cache_transaction
         | 
| 57 | 
            +
                  end
         | 
| 58 | 
            +
                end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                def transaction_with_cache_transaction(*args)
         | 
| 61 | 
            +
                  if cache_config
         | 
| 62 | 
            +
                    # Wrap both the db and cache transaction in another cache transaction so that the cache 
         | 
| 63 | 
            +
                    # gets written only after the database commit but can still flush the inner cache
         | 
| 64 | 
            +
                    # transaction if an AR::Rollback is issued.
         | 
| 65 | 
            +
                    repository.transaction do
         | 
| 66 | 
            +
                      transaction_without_cache_transaction(*args) do
         | 
| 67 | 
            +
                        repository.transaction { yield }
         | 
| 68 | 
            +
                      end
         | 
| 69 | 
            +
                    end
         | 
| 70 | 
            +
                  else
         | 
| 71 | 
            +
                    transaction_without_cache_transaction(*args)
         | 
| 72 | 
            +
                  end
         | 
| 73 | 
            +
                end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                def cacheable?(*args)
         | 
| 76 | 
            +
                  true
         | 
| 77 | 
            +
                end
         | 
| 78 | 
            +
              end
         | 
| 79 | 
            +
            end
         | 
| 80 | 
            +
            module NoCash
         | 
| 81 | 
            +
              def self.included(active_record_class)
         | 
| 82 | 
            +
                active_record_class.class_eval do
         | 
| 83 | 
            +
                  extend ClassMethods
         | 
| 84 | 
            +
                end
         | 
| 85 | 
            +
              end
         | 
| 86 | 
            +
              module ClassMethods
         | 
| 87 | 
            +
                def cacheable?(*args)
         | 
| 88 | 
            +
                  false
         | 
| 89 | 
            +
                end
         | 
| 90 | 
            +
              end
         | 
| 91 | 
            +
            end
         | 
| @@ -0,0 +1,83 @@ | |
| 1 | 
            +
            module Cash
         | 
| 2 | 
            +
              module Accessor
         | 
| 3 | 
            +
                def self.included(a_module)
         | 
| 4 | 
            +
                  a_module.module_eval do
         | 
| 5 | 
            +
                    extend ClassMethods
         | 
| 6 | 
            +
                    include InstanceMethods
         | 
| 7 | 
            +
                  end
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                module ClassMethods
         | 
| 11 | 
            +
                  def fetch(keys, options = {}, &block)
         | 
| 12 | 
            +
                    case keys
         | 
| 13 | 
            +
                    when Array
         | 
| 14 | 
            +
                      return {} if keys.empty?
         | 
| 15 | 
            +
                      
         | 
| 16 | 
            +
                      keys = keys.collect { |key| cache_key(key) }
         | 
| 17 | 
            +
                      hits = repository.get_multi(*keys)
         | 
| 18 | 
            +
                      if (missed_keys = keys - hits.keys).any?
         | 
| 19 | 
            +
                        missed_values = block.call(missed_keys)
         | 
| 20 | 
            +
                        hits.merge!(missed_keys.zip(Array(missed_values)).to_hash_without_nils)
         | 
| 21 | 
            +
                      end
         | 
| 22 | 
            +
                      hits
         | 
| 23 | 
            +
                    else
         | 
| 24 | 
            +
                      repository.get(cache_key(keys), options[:raw]) || (block ? block.call : nil)
         | 
| 25 | 
            +
                    end
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  def get(keys, options = {}, &block)
         | 
| 29 | 
            +
                    case keys
         | 
| 30 | 
            +
                    when Array
         | 
| 31 | 
            +
                      fetch(keys, options, &block)
         | 
| 32 | 
            +
                    else
         | 
| 33 | 
            +
                      fetch(keys, options) do
         | 
| 34 | 
            +
                        if block_given?
         | 
| 35 | 
            +
                          add(keys, result = yield(keys), options)
         | 
| 36 | 
            +
                          result
         | 
| 37 | 
            +
                        end
         | 
| 38 | 
            +
                      end
         | 
| 39 | 
            +
                    end
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                  def add(key, value, options = {})
         | 
| 43 | 
            +
                    if repository.add(cache_key(key), value, options[:ttl] || cache_config.ttl, options[:raw]) == "NOT_STORED\r\n"
         | 
| 44 | 
            +
                      yield if block_given?
         | 
| 45 | 
            +
                    end
         | 
| 46 | 
            +
                  end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                  def set(key, value, options = {})
         | 
| 49 | 
            +
                    repository.set(cache_key(key), value, options[:ttl] || cache_config.ttl, options[:raw])
         | 
| 50 | 
            +
                  end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                  def incr(key, delta = 1, ttl = nil)
         | 
| 53 | 
            +
                    ttl ||= cache_config.ttl
         | 
| 54 | 
            +
                    repository.incr(cache_key = cache_key(key), delta) || begin
         | 
| 55 | 
            +
                      repository.add(cache_key, (result = yield).to_s, ttl, true) { repository.incr(cache_key) }
         | 
| 56 | 
            +
                      result
         | 
| 57 | 
            +
                    end
         | 
| 58 | 
            +
                  end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                  def decr(key, delta = 1, ttl = nil)
         | 
| 61 | 
            +
                    ttl ||= cache_config.ttl
         | 
| 62 | 
            +
                    repository.decr(cache_key = cache_key(key), delta) || begin
         | 
| 63 | 
            +
                      repository.add(cache_key, (result = yield).to_s, ttl, true) { repository.decr(cache_key) }
         | 
| 64 | 
            +
                      result
         | 
| 65 | 
            +
                    end
         | 
| 66 | 
            +
                  end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                  def expire(key)
         | 
| 69 | 
            +
                    repository.delete(cache_key(key))
         | 
| 70 | 
            +
                  end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                  def cache_key(key)
         | 
| 73 | 
            +
                    "#{name}:#{cache_config.version}/#{key.to_s.gsub(' ', '+')}"
         | 
| 74 | 
            +
                  end
         | 
| 75 | 
            +
                end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                module InstanceMethods
         | 
| 78 | 
            +
                  def expire
         | 
| 79 | 
            +
                    self.class.expire(id)
         | 
| 80 | 
            +
                  end
         | 
| 81 | 
            +
                end
         | 
| 82 | 
            +
              end
         | 
| 83 | 
            +
            end
         | 
| @@ -0,0 +1,129 @@ | |
| 1 | 
            +
            module Cash
         | 
| 2 | 
            +
              class Buffered
         | 
| 3 | 
            +
                def self.push(cache, lock)
         | 
| 4 | 
            +
                  if cache.is_a?(Buffered)
         | 
| 5 | 
            +
                    cache.push
         | 
| 6 | 
            +
                  else
         | 
| 7 | 
            +
                    Buffered.new(cache, lock)
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def initialize(memcache, lock)
         | 
| 12 | 
            +
                  @buffer = {}
         | 
| 13 | 
            +
                  @commands = []
         | 
| 14 | 
            +
                  @cache = memcache
         | 
| 15 | 
            +
                  @lock = lock
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                def pop
         | 
| 19 | 
            +
                  @cache
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                def push
         | 
| 23 | 
            +
                  NestedBuffered.new(self, @lock)
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                def get(key, *options)
         | 
| 27 | 
            +
                  if @buffer.has_key?(key)
         | 
| 28 | 
            +
                    @buffer[key]
         | 
| 29 | 
            +
                  else
         | 
| 30 | 
            +
                    @buffer[key] = @cache.get(key, *options)
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                def set(key, value, *options)
         | 
| 35 | 
            +
                  @buffer[key] = value
         | 
| 36 | 
            +
                  buffer_command Command.new(:set, key, value, *options)
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                def incr(key, amount = 1)
         | 
| 40 | 
            +
                  return unless value = get(key, true)
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                  @buffer[key] = value.to_i + amount
         | 
| 43 | 
            +
                  buffer_command Command.new(:incr, key, amount)
         | 
| 44 | 
            +
                  @buffer[key]
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                def decr(key, amount = 1)
         | 
| 48 | 
            +
                  return unless value = get(key, true)
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  @buffer[key] = [value.to_i - amount, 0].max
         | 
| 51 | 
            +
                  buffer_command Command.new(:decr, key, amount)
         | 
| 52 | 
            +
                  @buffer[key]
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                def add(key, value, *options)
         | 
| 56 | 
            +
                  @buffer[key] = value
         | 
| 57 | 
            +
                  buffer_command Command.new(:add, key, value, *options)
         | 
| 58 | 
            +
                end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                def delete(key, *options)
         | 
| 61 | 
            +
                  @buffer[key] = nil
         | 
| 62 | 
            +
                  buffer_command Command.new(:delete, key, *options)
         | 
| 63 | 
            +
                end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                def get_multi(*keys)
         | 
| 66 | 
            +
                  values = keys.collect { |key| get(key) }
         | 
| 67 | 
            +
                  keys.zip(values).to_hash_without_nils
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                def flush
         | 
| 71 | 
            +
                  sorted_keys = @commands.select(&:requires_lock?).collect(&:key).uniq.sort
         | 
| 72 | 
            +
                  sorted_keys.each do |key|
         | 
| 73 | 
            +
                    @lock.acquire_lock(key)
         | 
| 74 | 
            +
                  end
         | 
| 75 | 
            +
                  perform_commands
         | 
| 76 | 
            +
                ensure
         | 
| 77 | 
            +
                  @buffer = {}
         | 
| 78 | 
            +
                  sorted_keys.each do |key|
         | 
| 79 | 
            +
                    @lock.release_lock(key)
         | 
| 80 | 
            +
                  end
         | 
| 81 | 
            +
                end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                def respond_to?(method)
         | 
| 84 | 
            +
                  @cache.respond_to?(method)
         | 
| 85 | 
            +
                end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                protected
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                def perform_commands
         | 
| 90 | 
            +
                  @commands.each do |command|
         | 
| 91 | 
            +
                    command.call(@cache)
         | 
| 92 | 
            +
                  end
         | 
| 93 | 
            +
                end
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                def buffer_command(command)
         | 
| 96 | 
            +
                  @commands << command
         | 
| 97 | 
            +
                end
         | 
| 98 | 
            +
                
         | 
| 99 | 
            +
                private
         | 
| 100 | 
            +
                
         | 
| 101 | 
            +
                def method_missing(method, *args, &block)
         | 
| 102 | 
            +
                  @cache.send(method, *args, &block)
         | 
| 103 | 
            +
                end
         | 
| 104 | 
            +
              end
         | 
| 105 | 
            +
             | 
| 106 | 
            +
              class NestedBuffered < Buffered
         | 
| 107 | 
            +
                def flush
         | 
| 108 | 
            +
                  perform_commands
         | 
| 109 | 
            +
                end
         | 
| 110 | 
            +
              end
         | 
| 111 | 
            +
             | 
| 112 | 
            +
              class Command
         | 
| 113 | 
            +
                attr_accessor :key
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                def initialize(name, key, *args)
         | 
| 116 | 
            +
                  @name = name
         | 
| 117 | 
            +
                  @key = key
         | 
| 118 | 
            +
                  @args = args
         | 
| 119 | 
            +
                end
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                def requires_lock?
         | 
| 122 | 
            +
                  @name == :set
         | 
| 123 | 
            +
                end
         | 
| 124 | 
            +
             | 
| 125 | 
            +
                def call(cache)
         | 
| 126 | 
            +
                  cache.send @name, @key, *@args
         | 
| 127 | 
            +
                end
         | 
| 128 | 
            +
              end
         | 
| 129 | 
            +
            end
         | 
    
        data/lib/cash/config.rb
    ADDED
    
    | @@ -0,0 +1,75 @@ | |
| 1 | 
            +
            module Cash
         | 
| 2 | 
            +
              module Config
         | 
| 3 | 
            +
                def self.create(active_record, options, indices = [])
         | 
| 4 | 
            +
                  active_record.cache_config = Cash::Config::Config.new(active_record, options)
         | 
| 5 | 
            +
                  indices.each { |i| active_record.index i.attributes, i.options }
         | 
| 6 | 
            +
                end
         | 
| 7 | 
            +
                
         | 
| 8 | 
            +
                def self.included(a_module)
         | 
| 9 | 
            +
                  a_module.module_eval do
         | 
| 10 | 
            +
                    extend ClassMethods
         | 
| 11 | 
            +
                    delegate :repository, :to => "self.class"
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                module ClassMethods
         | 
| 16 | 
            +
                  def self.extended(a_class)
         | 
| 17 | 
            +
                    class << a_class
         | 
| 18 | 
            +
                      def cache_config
         | 
| 19 | 
            +
                        @cache_config ? @cache_config : superclass.cache_config
         | 
| 20 | 
            +
                      end
         | 
| 21 | 
            +
                      
         | 
| 22 | 
            +
                      delegate :repository, :indices, :to => :cache_config
         | 
| 23 | 
            +
                      alias_method_chain :inherited, :cache_config
         | 
| 24 | 
            +
                    end
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  def inherited_with_cache_config(subclass)
         | 
| 28 | 
            +
                    inherited_without_cache_config(subclass)
         | 
| 29 | 
            +
                    @cache_config.inherit(subclass)
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  def index(attributes, options = {})
         | 
| 33 | 
            +
                    options.assert_valid_keys(:ttl, :order, :limit, :buffer, :order_column)
         | 
| 34 | 
            +
                    (@cache_config.indices.unshift(Index.new(@cache_config, self, attributes, options))).uniq!
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  def version(number)
         | 
| 38 | 
            +
                    @cache_config.options[:version] = number
         | 
| 39 | 
            +
                  end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                  def cache_config=(config)
         | 
| 42 | 
            +
                    @cache_config = config
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                class Config
         | 
| 47 | 
            +
                  attr_reader :active_record, :options
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  def initialize(active_record, options = {})
         | 
| 50 | 
            +
                    @active_record, @options = active_record, options
         | 
| 51 | 
            +
                  end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                  def repository
         | 
| 54 | 
            +
                    @options[:repository]
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  def ttl
         | 
| 58 | 
            +
                    repository_ttl = repository.respond_to?(:default_ttl) ? repository.default_ttl : nil
         | 
| 59 | 
            +
                    @ttl ||= @options[:ttl] || repository_ttl || 1.day
         | 
| 60 | 
            +
                  end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                  def version
         | 
| 63 | 
            +
                    @options[:version] || 1
         | 
| 64 | 
            +
                  end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                  def indices
         | 
| 67 | 
            +
                    @indices ||= active_record == ActiveRecord::Base ? [] : [Index.new(self, active_record, active_record.primary_key)]
         | 
| 68 | 
            +
                  end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                  def inherit(active_record)
         | 
| 71 | 
            +
                    Cash::Config.create(active_record, @options, indices)
         | 
| 72 | 
            +
                  end
         | 
| 73 | 
            +
                end
         | 
| 74 | 
            +
              end
         | 
| 75 | 
            +
            end
         | 
    
        data/lib/cash/fake.rb
    ADDED
    
    | @@ -0,0 +1,83 @@ | |
| 1 | 
            +
            module Cash
         | 
| 2 | 
            +
              class Fake < HashWithIndifferentAccess
         | 
| 3 | 
            +
                attr_accessor :servers
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                def get_multi(*keys)
         | 
| 6 | 
            +
                  slice(*keys).collect { |k,v| [k, Marshal.load(v)] }.to_hash
         | 
| 7 | 
            +
                end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                def set(key, value, ttl = 0, raw = false)
         | 
| 10 | 
            +
                  self[key] = marshal(value, raw)
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def get(key, raw = false)
         | 
| 14 | 
            +
                  if raw
         | 
| 15 | 
            +
                    self[key]
         | 
| 16 | 
            +
                  else
         | 
| 17 | 
            +
                    if self.has_key?(key)
         | 
| 18 | 
            +
                      Marshal.load(self[key])
         | 
| 19 | 
            +
                    else
         | 
| 20 | 
            +
                      nil
         | 
| 21 | 
            +
                    end
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                def incr(key, amount = 1)
         | 
| 26 | 
            +
                  if self.has_key?(key)
         | 
| 27 | 
            +
                    self[key] = (self[key].to_i + amount).to_s
         | 
| 28 | 
            +
                    self[key].to_i
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                def decr(key, amount = 1)
         | 
| 33 | 
            +
                  if self.has_key?(key)
         | 
| 34 | 
            +
                    self[key] = (self[key].to_i - amount).to_s
         | 
| 35 | 
            +
                    self[key].to_i
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                def add(key, value, ttl = 0, raw = false)
         | 
| 40 | 
            +
                  return false if self.has_key?(key)
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                  self[key] = marshal(value, raw)
         | 
| 43 | 
            +
                  true
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                def append(key, value)
         | 
| 47 | 
            +
                  set(key, get(key, true).to_s + value.to_s, nil, true)
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                def namespace
         | 
| 51 | 
            +
                  nil
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                def flush_all
         | 
| 55 | 
            +
                  clear
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                def stats
         | 
| 59 | 
            +
                  {}
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                def reset_runtime
         | 
| 63 | 
            +
                  [0, Hash.new(0)]
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                private
         | 
| 67 | 
            +
                def marshal(value, raw)
         | 
| 68 | 
            +
                  if raw
         | 
| 69 | 
            +
                    value.to_s
         | 
| 70 | 
            +
                  else
         | 
| 71 | 
            +
                    Marshal.dump(value)
         | 
| 72 | 
            +
                  end
         | 
| 73 | 
            +
                end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                def unmarshal(marshaled_obj)
         | 
| 76 | 
            +
                  Marshal.load(marshaled_obj)
         | 
| 77 | 
            +
                end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                def deep_clone(obj)
         | 
| 80 | 
            +
                  unmarshal(marshal(obj))
         | 
| 81 | 
            +
                end
         | 
| 82 | 
            +
              end
         | 
| 83 | 
            +
            end
         | 
    
        data/lib/cash/finders.rb
    ADDED
    
    | @@ -0,0 +1,38 @@ | |
| 1 | 
            +
            module Cash
         | 
| 2 | 
            +
              module Finders
         | 
| 3 | 
            +
                def self.included(active_record_class)
         | 
| 4 | 
            +
                  active_record_class.class_eval do
         | 
| 5 | 
            +
                    extend ClassMethods
         | 
| 6 | 
            +
                  end
         | 
| 7 | 
            +
                end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                module ClassMethods
         | 
| 10 | 
            +
                  def self.extended(active_record_class)
         | 
| 11 | 
            +
                    class << active_record_class
         | 
| 12 | 
            +
                      alias_method_chain :find_every, :cache
         | 
| 13 | 
            +
                      alias_method_chain :find_from_ids, :cache
         | 
| 14 | 
            +
                      alias_method_chain :calculate, :cache
         | 
| 15 | 
            +
                    end
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  def without_cache(&block)
         | 
| 19 | 
            +
                    with_scope(:find => {:readonly => true}, &block)
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  # User.find(:first, ...), User.find_by_foo(...), User.find(:all, ...), User.find_all_by_foo(...)
         | 
| 23 | 
            +
                  def find_every_with_cache(options)
         | 
| 24 | 
            +
                    Query::Select.perform(self, options, scope(:find))
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  # User.find(1), User.find(1, 2, 3), User.find([1, 2, 3]), User.find([])
         | 
| 28 | 
            +
                  def find_from_ids_with_cache(ids, options)
         | 
| 29 | 
            +
                    Query::PrimaryKey.perform(self, ids, options, scope(:find))
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  # User.count(:all), User.count, User.sum(...)
         | 
| 33 | 
            +
                  def calculate_with_cache(operation, column_name, options = {})
         | 
| 34 | 
            +
                    Query::Calculation.perform(self, operation, column_name, options, scope(:find))
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
            end
         |