second_level_cache 1.3.2

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/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle
2
+ /nbproject/*
3
+ /Gemfile.lock
4
+ /.rvmrc
5
+ /doc
6
+ /pkg
7
+ /tags
8
+ /spec/log
9
+ *.log
10
+ *.gem
11
+ *.sqlite3
12
+ *.swp
13
+ *.swo
14
+
data/CHANGELOG.md ADDED
@@ -0,0 +1,19 @@
1
+ 1.2.0
2
+ -----
3
+ * [clear cache after update_counters](https://github.com/csdn-dev/second_level_cache/commit/240dde81199124092e0e8ad0500c167ac146e301)
4
+
5
+ 1.2.1
6
+ -----
7
+ * [fix polymorphic association bug]
8
+
9
+ 1.3.0
10
+ -----
11
+ * [clean cache after touch]
12
+
13
+ 1.3.1
14
+ -----
15
+ * [clean cache after update_column/increment!/decrement!]
16
+
17
+ 1.3.2
18
+ -----
19
+ * [fix has one assciation issue]
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'http://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in second_level_cache.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,71 @@
1
+ # SecondLevelCache
2
+
3
+ SecondLevelCache is a write-through and read-through caching library inspired by Cache Money and cache_fu, support only Rails3 and ActiveRecord.
4
+
5
+ Read-Through: Queries by ID, like `current_user.articles.find(params[:id])`, will first look in cache store and then look in the database for the results of that query. If there is a cache miss, it will populate the cache.
6
+
7
+ Write-Through: As objects are created, updated, and deleted, all of the caches are automatically kept up-to-date and coherent.
8
+
9
+ ## Risk
10
+
11
+ SecondLevelCache is not fully test and verify in production enviroment right now. Use it at your own risk.
12
+
13
+ ## Install
14
+
15
+ In your gem file:
16
+
17
+ ```ruby
18
+ gem "second_level_cache", :git => "git://github.com/csdn-dev/second_level_cache.git"
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ For example, cache User objects:
24
+
25
+ ```ruby
26
+ class User < ActiveRecord::Base
27
+ acts_as_cached
28
+ end
29
+ ```
30
+
31
+ Then it will fetch cached object in this situations:
32
+
33
+ ```ruby
34
+ User.find(1)
35
+ User.find_by_id(1)
36
+ User.find_by_id!(1)
37
+ User.find_by_id_and_name(1, "Hooopo")
38
+ User.where(:status => 1).find_by_id(1)
39
+ user.articles.find_by_id(1)
40
+ user.articles.find(1), user.where(:status => 1).find(1)
41
+ article.user
42
+ ```
43
+
44
+ Cache key:
45
+
46
+ ```ruby
47
+ user = User.find 1
48
+ user.second_level_cache_key # We will get the key looks like "slc/user/1"
49
+ ```
50
+
51
+ Notice:
52
+
53
+ * SecondLevelCache cache by model name and id, so only find_one query will work.
54
+ * only equal conditions query WILL get cache; and SQL string query like `User.where("name = 'Hooopo'").find(1)` WILL NOT work.
55
+
56
+ ## configure
57
+
58
+ cache_store: Default is Rails.cache
59
+ logger: Default is Rails.logger
60
+ cache_key_prefix: Avoid cache key conflict with other application, Default is 'slc'
61
+
62
+ You can config like this:
63
+
64
+ ```ruby
65
+ # config/initializers/second_level_cache.rb
66
+ SecondLevelCache.configure do |config|
67
+ config.cache_store = ActiveSupport::Cache::MemoryStore.new
68
+ config.logger = Logger.new($stdout)
69
+ config.cache_key_prefix = 'domain'
70
+ end
71
+ ```
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env rake
2
+ require 'bundler/gem_tasks'
3
+ require 'rake/testtask'
4
+
5
+ task :default => :test
6
+
7
+ Rake::TestTask.new do |t|
8
+ t.libs << "lib" << "test"
9
+ t.test_files = FileList['test/**/*_test.rb']
10
+ end
data/init.rb ADDED
@@ -0,0 +1,2 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require File.expand_path("../lib/second_level_cache", __FILE__)
@@ -0,0 +1,25 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module SecondLevelCache
3
+ module ActiveRecord
4
+ module Base
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ after_destroy :expire_second_level_cache
9
+ after_save :write_second_level_cache
10
+
11
+ class << self
12
+ alias_method_chain :update_counters, :cache
13
+ end
14
+ end
15
+
16
+
17
+ module ClassMethods
18
+ def update_counters_with_cache(id, counters)
19
+ Array(id).each{|i| expire_second_level_cache(i)}
20
+ update_counters_without_cache(id, counters)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,30 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module SecondLevelCache
3
+ module ActiveRecord
4
+ module Associations
5
+ module BelongsToAssociation
6
+ extend ActiveSupport::Concern
7
+ included do
8
+ class_eval do
9
+ alias_method_chain :find_target, :second_level_cache
10
+ end
11
+ end
12
+
13
+ def find_target_with_second_level_cache
14
+ return find_target_without_second_level_cache unless klass.second_level_cache_enabled?
15
+ cache_record = klass.read_second_level_cache(second_level_cache_key)
16
+ return cache_record.tap{|record| set_inverse_instance(record)} if cache_record
17
+ record = find_target_without_second_level_cache
18
+ record.write_second_level_cache
19
+ record
20
+ end
21
+
22
+ private
23
+
24
+ def second_level_cache_key
25
+ owner[reflection.foreign_key]
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,109 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'second_level_cache/arel/wheres'
3
+
4
+ module SecondLevelCache
5
+ module ActiveRecord
6
+ module FinderMethods
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ class_eval do
11
+ alias_method_chain :find_one, :second_level_cache
12
+ alias_method_chain :find_by_attributes, :second_level_cache
13
+ end
14
+ end
15
+
16
+ # TODO fetch multi ids
17
+ #
18
+ # Cacheable:
19
+ #
20
+ # current_user.articles.where(:status => 1).visiable.find(params[:id])
21
+ #
22
+ # Uncacheable:
23
+ #
24
+ # Article.where("user_id = '1'").find(params[:id])
25
+ # Article.where("user_id > 1").find(params[:id])
26
+ # Article.where("articles.user_id = 1").find(prams[:id])
27
+ # Article.where("user_id = 1 AND ...").find(params[:id])
28
+ def find_one_with_second_level_cache(id)
29
+ return find_one_without_second_level_cache(id) unless second_level_cache_enabled?
30
+
31
+ id = id.id if ActiveRecord::Base === id
32
+ if ::ActiveRecord::IdentityMap.enabled? && cachable? && record = from_identity_map(id)
33
+ return record
34
+ end
35
+
36
+ if cachable?
37
+ return record if record = @klass.read_second_level_cache(id)
38
+ end
39
+
40
+ if cachable_without_conditions?
41
+ if record = @klass.read_second_level_cache(id)
42
+ return record if where_match_with_cache?(where_values, record)
43
+ end
44
+ end
45
+
46
+ record = find_one_without_second_level_cache(id)
47
+ record.write_second_level_cache
48
+ record
49
+ end
50
+
51
+ # TODO cache find_or_create_by_id
52
+ def find_by_attributes_with_second_level_cache(match, attributes, *args)
53
+ return find_by_attributes_without_second_level_cache(match, attributes, *args) unless second_level_cache_enabled?
54
+
55
+ conditions = Hash[attributes.map {|a| [a, args[attributes.index(a)]]}]
56
+
57
+ if conditions.has_key?("id")
58
+ result = wrap_bang(match.bang?) do
59
+ if conditions.size == 1
60
+ find_one_with_second_level_cache(conditions["id"])
61
+ else
62
+ where(conditions.except("id")).find_one_with_second_level_cache(conditions["id"])
63
+ end
64
+ end
65
+ yield(result) if block_given? #edge rails do this bug rails3.1.0 not
66
+
67
+ return result
68
+ end
69
+
70
+ find_by_attributes_without_second_level_cache(match, attributes, *args)
71
+ end
72
+
73
+ private
74
+
75
+ def wrap_bang(bang)
76
+ bang ? yield : (yield rescue nil)
77
+ end
78
+
79
+ def cachable?
80
+ where_values.blank? &&
81
+ limit_one? && order_values.blank? &&
82
+ includes_values.blank? && preload_values.blank? &&
83
+ readonly_value.nil? && joins_values.blank? && !@klass.locking_enabled?
84
+ end
85
+
86
+ def cachable_without_conditions?
87
+ limit_one? && order_values.blank? &&
88
+ includes_values.blank? && preload_values.blank? &&
89
+ readonly_value.nil? && joins_values.blank? && !@klass.locking_enabled?
90
+ end
91
+
92
+ def where_match_with_cache?(where_values, cache_record)
93
+ condition = SecondLevelCache::Arel::Wheres.new(where_values)
94
+ return false unless condition.all_equality?
95
+ condition.extract_pairs.all? do |pair|
96
+ cache_record.read_attribute(pair[:left]) == pair[:right]
97
+ end
98
+ end
99
+
100
+ def limit_one?
101
+ limit_value.blank? || limit_value == 1
102
+ end
103
+
104
+ def from_identity_map(id)
105
+ ::ActiveRecord::IdentityMap.get(@klass, id)
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,31 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module SecondLevelCache
3
+ module ActiveRecord
4
+ module Persistence
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ class_eval do
9
+ alias_method_chain :reload, :second_level_cache
10
+ alias_method_chain :touch, :second_level_cache
11
+ alias_method_chain :update_column, :second_level_cache
12
+ end
13
+ end
14
+
15
+ def update_column_with_second_level_cache(name, value)
16
+ expire_second_level_cache
17
+ update_column_without_second_level_cache(name, value)
18
+ end
19
+
20
+ def reload_with_second_level_cache(options = nil)
21
+ expire_second_level_cache
22
+ reload_without_second_level_cache(options)
23
+ end
24
+
25
+ def touch_with_second_level_cache(name = nil)
26
+ expire_second_level_cache
27
+ touch_without_second_level_cache(name)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,11 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'second_level_cache/active_record/base'
3
+ require 'second_level_cache/active_record/finder_methods'
4
+ require 'second_level_cache/active_record/persistence'
5
+ require 'second_level_cache/active_record/belongs_to_association'
6
+
7
+ ActiveRecord::Base.send(:include, SecondLevelCache::Mixin)
8
+ ActiveRecord::Base.send(:include, SecondLevelCache::ActiveRecord::Base)
9
+ ActiveRecord::FinderMethods.send(:include, SecondLevelCache::ActiveRecord::FinderMethods)
10
+ ActiveRecord::Base.send(:include, SecondLevelCache::ActiveRecord::Persistence)
11
+ ActiveRecord::Associations::BelongsToAssociation.send(:include, SecondLevelCache::ActiveRecord::Associations::BelongsToAssociation)
@@ -0,0 +1,35 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module SecondLevelCache
3
+ module Arel
4
+ class Wheres
5
+ attr_reader :where_values
6
+
7
+ def initialize(where_values)
8
+ @where_values = where_values
9
+ end
10
+
11
+ # Determine whether all conditions is equality, for example:
12
+ #
13
+ # Article.where("user_id = 1").where(:status => 1).find(1)
14
+ def all_equality?
15
+ where_values.all?{|where_value| where_value.is_a?(::Arel::Nodes::Equality)}
16
+ end
17
+
18
+ # Extract conditions to pairs, for checking whether cache match the conditions.
19
+ def extract_pairs
20
+ where_values.map do |where_value|
21
+ if where_value.is_a?(String)
22
+ left, right = where_value.split(/\s*=\s*/, 2)
23
+ right = right.to_i
24
+ else
25
+ left, right = where_value.left.name, where_value.right
26
+ end
27
+ {
28
+ :left => left,
29
+ :right => right
30
+ }
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,22 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module SecondLevelCache
3
+ module Config
4
+ extend self
5
+
6
+ attr_accessor :cache_store, :logger, :cache_key_prefix
7
+
8
+ def cache_store
9
+ @cache_store ||= Rails.cache if defined?(Rails)
10
+ @cache_store
11
+ end
12
+
13
+ def logger
14
+ @logger ||= Rails.logger if defined?(Rails)
15
+ @logger ||= Logger.new(STDOUT)
16
+ end
17
+
18
+ def cache_key_prefix
19
+ @cache_key_prefix ||= 'slc'
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,16 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Marshal
3
+ class << self
4
+ def load_with_constantize(value)
5
+ begin
6
+ Marshal.load_without_constantize value
7
+ rescue ArgumentError => e
8
+ _, class_name = *(/undefined class\/module (\w+)/.match(e.message))
9
+ raise if !class_name
10
+ class_name.constantize
11
+ Marshal.load value
12
+ end
13
+ end
14
+ alias_method_chain :load, :constantize
15
+ end
16
+ end
@@ -0,0 +1,4 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module SecondLevelCache
3
+ VERSION = "1.3.2"
4
+ end
@@ -0,0 +1,70 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'active_support/all'
3
+ require 'second_level_cache/config'
4
+ require 'second_level_cache/marshal'
5
+
6
+ module SecondLevelCache
7
+ def self.configure
8
+ block_given? ? yield(Config) : Config
9
+ end
10
+
11
+ class << self
12
+ delegate :logger, :cache_store, :cache_key_prefix, :to => Config
13
+ end
14
+
15
+ module Mixin
16
+ extend ActiveSupport::Concern
17
+
18
+ module ClassMethods
19
+ attr_reader :second_level_cache_options
20
+
21
+ def acts_as_cached(options = {})
22
+ @second_level_cache_enabled = true
23
+ @second_level_cache_options = options
24
+ @second_level_cache_options[:expires_in] ||= 1.day
25
+ end
26
+
27
+ def second_level_cache_enabled?
28
+ !!@second_level_cache_enabled
29
+ end
30
+
31
+ def cache_store
32
+ Config.cache_store
33
+ end
34
+
35
+ def logger
36
+ Config.logger
37
+ end
38
+
39
+ def cache_key_prefix
40
+ Config.cache_key_prefix
41
+ end
42
+
43
+ def second_level_cache_key(id)
44
+ "#{cache_key_prefix}/#{name.downcase}/#{id}"
45
+ end
46
+
47
+ def read_second_level_cache(id)
48
+ SecondLevelCache.cache_store.read(second_level_cache_key(id)) if self.second_level_cache_enabled?
49
+ end
50
+
51
+ def expire_second_level_cache(id)
52
+ SecondLevelCache.cache_store.delete(second_level_cache_key(id)) if self.second_level_cache_enabled?
53
+ end
54
+ end
55
+
56
+ def second_level_cache_key
57
+ self.class.second_level_cache_key(id)
58
+ end
59
+
60
+ def expire_second_level_cache
61
+ SecondLevelCache.cache_store.delete(second_level_cache_key) if self.class.second_level_cache_enabled?
62
+ end
63
+
64
+ def write_second_level_cache
65
+ SecondLevelCache.cache_store.write(second_level_cache_key, self, self.class.second_level_cache_options) if self.class.second_level_cache_enabled?
66
+ end
67
+ end
68
+ end
69
+
70
+ require 'second_level_cache/active_record' if defined?(ActiveRecord)
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/second_level_cache/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["wangxz"]
6
+ gem.email = ["wangxz@csdn.net"]
7
+ gem.description = %q{Write Through and Read Through caching library inspired by CacheMoney and cache_fu, support only Rails3 and ActiveRecord.}
8
+ gem.summary = <<-SUMMARY
9
+ SecondLevelCache is a write-through and read-through caching library inspired by Cache Money and cache_fu, support only Rails3 and ActiveRecord.
10
+
11
+ Read-Through: Queries by ID, like current_user.articles.find(params[:id]), will first look in cache store and then look in the database for the results of that query. If there is a cache miss, it will populate the cache.
12
+
13
+ Write-Through: As objects are created, updated, and deleted, all of the caches are automatically kept up-to-date and coherent.
14
+ SUMMARY
15
+
16
+ gem.homepage = "https://github.com/csdn-dev/second_level_cache"
17
+
18
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ gem.files = `git ls-files`.split("\n")
20
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
21
+ gem.name = "second_level_cache"
22
+ gem.require_paths = ["lib"]
23
+ gem.version = SecondLevelCache::VERSION
24
+
25
+ gem.add_runtime_dependency "activesupport", ["~> 3.2.0"]
26
+
27
+ gem.add_development_dependency "activerecord", ["~> 3.2.0"]
28
+ gem.add_development_dependency "sqlite3"
29
+ gem.add_development_dependency "rake"
30
+ end
@@ -0,0 +1,36 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'active_record/test_helper'
3
+
4
+ class ActiveRecord::BaseTest < Test::Unit::TestCase
5
+ def setup
6
+ @user = User.create :name => 'csdn', :email => 'test@csdn.com'
7
+ end
8
+
9
+ def test_should_have_cache_when_create
10
+ no_connection do
11
+ assert_not_nil User.read_second_level_cache(@user.id)
12
+ assert_equal @user, User.find(@user.id)
13
+ end
14
+ end
15
+
16
+ def test_should_update_cache_when_update
17
+ @user.update_attributes :name => 'change'
18
+
19
+ no_connection do
20
+ assert_equal 'change', User.find(@user.id).name
21
+ end
22
+ end
23
+
24
+ def test_should_expire_cache_when_destroy
25
+ @user.destroy
26
+ assert_nil User.read_second_level_cache(@user.id)
27
+ end
28
+
29
+ def test_should_expire_cache_when_update_counters
30
+ assert_equal @user.books_count, 0
31
+ @user.books.create
32
+ assert_nil User.read_second_level_cache(@user.id)
33
+ user = User.find(@user.id)
34
+ assert_equal user.books_count, @user.books_count + 1
35
+ end
36
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'active_record/test_helper'
3
+
4
+ class ActiveRecord::BelongsToAssociationTest < Test::Unit::TestCase
5
+ def setup
6
+ @user = User.create :name => 'csdn', :email => 'test@csdn.com'
7
+ end
8
+
9
+ def test_should_get_cache_when_use_belongs_to_association
10
+ book = @user.books.create
11
+
12
+ no_connection do
13
+ assert_equal @user, book.user
14
+ end
15
+ end
16
+
17
+ def test_should_write_belongs_to_association_cache
18
+ book = @user.books.create
19
+ @user.expire_second_level_cache
20
+ assert_nil User.read_second_level_cache(@user.id)
21
+ assert_equal @user, book.user
22
+ # assert_not_nil User.read_second_level_cache(@user.id)
23
+ end
24
+ end
@@ -0,0 +1,25 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'active_record/test_helper'
3
+
4
+ class ActiveRecord::FinderMethodsTest < Test::Unit::TestCase
5
+ def setup
6
+ @user = User.create :name => 'csdn', :email => 'test@csdn.com'
7
+ end
8
+
9
+ def test_should_find_without_cache
10
+ SecondLevelCache.cache_store.clear
11
+ assert_equal @user, User.find(@user.id)
12
+ end
13
+
14
+ def test_should_find_with_cache
15
+ no_connection do
16
+ assert_equal @user, User.find(@user.id)
17
+ end
18
+ end
19
+
20
+ def test_should_find_with_condition
21
+ no_connection do
22
+ assert_equal @user, User.where(:name => @user.name).find(@user.id)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,14 @@
1
+ # -*- encoding : utf-8 -*-
2
+ ActiveRecord::Base.connection.create_table(:books, :force => true) do |t|
3
+ t.string :title
4
+ t.string :body
5
+ t.integer :user_id
6
+ t.integer :images_count, :default => 0
7
+ end
8
+
9
+ class Book < ActiveRecord::Base
10
+ acts_as_cached
11
+
12
+ belongs_to :user, :counter_cache => true
13
+ has_many :images, :as => :imagable
14
+ end
@@ -0,0 +1,13 @@
1
+ # -*- encoding : utf-8 -*-
2
+ ActiveRecord::Base.connection.create_table(:images, :force => true) do |t|
3
+ t.string :url
4
+ t.string :imagable_type
5
+ t.integer :imagable_id
6
+ end
7
+
8
+ class Image < ActiveRecord::Base
9
+ acts_as_cached
10
+
11
+ belongs_to :imagable, :polymorphic => true, :counter_cache => true
12
+ end
13
+
@@ -0,0 +1,10 @@
1
+ # -*- encoding : utf-8 -*-
2
+ ActiveRecord::Base.connection.create_table(:posts, :force => true) do |t|
3
+ t.text :body
4
+ t.integer :topic_id
5
+ end
6
+
7
+ class Post < ActiveRecord::Base
8
+ acts_as_cached
9
+ belongs_to :topic, :touch => true
10
+ end
@@ -0,0 +1,13 @@
1
+ # -*- encoding : utf-8 -*-
2
+ ActiveRecord::Base.connection.create_table(:topics, :force => true) do |t|
3
+ t.string :title
4
+ t.text :body
5
+
6
+ t.timestamps
7
+ end
8
+
9
+ class Topic < ActiveRecord::Base
10
+ acts_as_cached
11
+
12
+ has_many :posts
13
+ end
@@ -0,0 +1,14 @@
1
+ # -*- encoding : utf-8 -*-
2
+ ActiveRecord::Base.connection.create_table(:users, :force => true) do |t|
3
+ t.string :name
4
+ t.string :email
5
+ t.integer :books_count, :default => 0
6
+ t.integer :images_count, :default => 0
7
+ end
8
+
9
+ class User < ActiveRecord::Base
10
+ acts_as_cached
11
+
12
+ has_many :books
13
+ has_many :images, :as => :imagable
14
+ end
@@ -0,0 +1,27 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'active_record/test_helper'
3
+
4
+ class ActiveRecord::PersistenceTest < Test::Unit::TestCase
5
+ def setup
6
+ @user = User.create :name => 'csdn', :email => 'test@csdn.com'
7
+ @topic = Topic.create :title => "csdn"
8
+ end
9
+
10
+ def test_should_reload_object
11
+ User.increment_counter :books_count, @user.id
12
+ assert_equal 0, @user.books_count
13
+ assert_equal 1, @user.reload.books_count
14
+ end
15
+
16
+ def test_should_clean_cache_after_touch
17
+ post = @topic.posts.create
18
+ post.body = "body"
19
+ post.save
20
+ new_topic = Topic.find @topic.id
21
+ assert !(new_topic.updated_at == @topic.updated_at)
22
+ end
23
+
24
+ def test_should_return_true_if_touch_ok
25
+ assert @topic.touch == true
26
+ end
27
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'active_record/test_helper'
3
+
4
+ class ActiveRecord::PolymorphicAssociationTest < Test::Unit::TestCase
5
+ def setup
6
+ @user = User.create :name => 'csdn', :email => 'test@csdn.com'
7
+ end
8
+
9
+ def test_should_get_cache_when_use_polymorphic_association
10
+ image = @user.images.create
11
+
12
+ no_connection do
13
+ assert_equal @user, image.imagable
14
+ end
15
+ end
16
+
17
+ def test_should_write_polymorphic_association_cache
18
+ image = @user.images.create
19
+ @user.expire_second_level_cache
20
+ assert_nil User.read_second_level_cache(@user.id)
21
+ assert_equal @user, image.imagable
22
+ end
23
+ end
24
+
@@ -0,0 +1,20 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'active_record/test_helper'
3
+
4
+ class ActiveRecord::SecondLevelCacheTest < Test::Unit::TestCase
5
+ def setup
6
+ @user = User.create :name => 'csdn', :email => 'test@csdn.com'
7
+ end
8
+
9
+ def test_should_get_cache_key
10
+ assert_equal "slc/user/#{@user.id}", @user.second_level_cache_key
11
+ end
12
+
13
+ def test_should_write_and_read_cache
14
+ assert_not_nil User.read_second_level_cache(@user.id)
15
+ @user.expire_second_level_cache
16
+ assert_nil User.read_second_level_cache(@user.id)
17
+ @user.write_second_level_cache
18
+ assert_not_nil User.read_second_level_cache(@user.id)
19
+ end
20
+ end
@@ -0,0 +1,35 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'test_helper'
3
+ require 'active_record'
4
+ require 'second_level_cache/active_record'
5
+
6
+ def open_test_db_connect
7
+ ActiveRecord::Base.establish_connection(
8
+ :adapter => 'sqlite3',
9
+ :database => 'test/test.sqlite3'
10
+ )
11
+ end
12
+ open_test_db_connect
13
+
14
+ def close_test_db_connect
15
+ ActiveRecord::Base.connection.disconnect!
16
+ end
17
+
18
+ class Test::Unit::TestCase
19
+ def no_connection
20
+ close_test_db_connect
21
+ assert_nothing_raised { yield }
22
+ ensure
23
+ open_test_db_connect
24
+ end
25
+
26
+ def teardown
27
+ User.delete_all
28
+ end
29
+ end
30
+
31
+ require 'active_record/model/user'
32
+ require 'active_record/model/book'
33
+ require 'active_record/model/image'
34
+ require 'active_record/model/topic'
35
+ require 'active_record/model/post'
@@ -0,0 +1,11 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'rubygems'
3
+ require 'bundler/setup'
4
+ require 'second_level_cache'
5
+ require 'test/unit'
6
+
7
+ SecondLevelCache.configure do |config|
8
+ config.cache_store = ActiveSupport::Cache::MemoryStore.new
9
+ end
10
+
11
+ SecondLevelCache.logger.level = Logger::INFO
metadata ADDED
@@ -0,0 +1,145 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: second_level_cache
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.3.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - wangxz
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-19 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activesupport
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 3.2.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 3.2.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: activerecord
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 3.2.0
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 3.2.0
46
+ - !ruby/object:Gem::Dependency
47
+ name: sqlite3
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rake
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ description: Write Through and Read Through caching library inspired by CacheMoney
79
+ and cache_fu, support only Rails3 and ActiveRecord.
80
+ email:
81
+ - wangxz@csdn.net
82
+ executables: []
83
+ extensions: []
84
+ extra_rdoc_files: []
85
+ files:
86
+ - .gitignore
87
+ - CHANGELOG.md
88
+ - Gemfile
89
+ - README.md
90
+ - Rakefile
91
+ - init.rb
92
+ - lib/second_level_cache.rb
93
+ - lib/second_level_cache/active_record.rb
94
+ - lib/second_level_cache/active_record/base.rb
95
+ - lib/second_level_cache/active_record/belongs_to_association.rb
96
+ - lib/second_level_cache/active_record/finder_methods.rb
97
+ - lib/second_level_cache/active_record/persistence.rb
98
+ - lib/second_level_cache/arel/wheres.rb
99
+ - lib/second_level_cache/config.rb
100
+ - lib/second_level_cache/marshal.rb
101
+ - lib/second_level_cache/version.rb
102
+ - second_level_cache.gemspec
103
+ - test/active_record/base_test.rb
104
+ - test/active_record/belongs_to_association_test.rb
105
+ - test/active_record/finder_methods_test.rb
106
+ - test/active_record/model/book.rb
107
+ - test/active_record/model/image.rb
108
+ - test/active_record/model/post.rb
109
+ - test/active_record/model/topic.rb
110
+ - test/active_record/model/user.rb
111
+ - test/active_record/persistence_test.rb
112
+ - test/active_record/polymorphic_association_test.rb
113
+ - test/active_record/second_level_cache_test.rb
114
+ - test/active_record/test_helper.rb
115
+ - test/test_helper.rb
116
+ homepage: https://github.com/csdn-dev/second_level_cache
117
+ licenses: []
118
+ post_install_message:
119
+ rdoc_options: []
120
+ require_paths:
121
+ - lib
122
+ required_ruby_version: !ruby/object:Gem::Requirement
123
+ none: false
124
+ requirements:
125
+ - - ! '>='
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ required_rubygems_version: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ requirements: []
135
+ rubyforge_project:
136
+ rubygems_version: 1.8.24
137
+ signing_key:
138
+ specification_version: 3
139
+ summary: ! 'SecondLevelCache is a write-through and read-through caching library inspired
140
+ by Cache Money and cache_fu, support only Rails3 and ActiveRecord. Read-Through:
141
+ Queries by ID, like current_user.articles.find(params[:id]), will first look in
142
+ cache store and then look in the database for the results of that query. If there
143
+ is a cache miss, it will populate the cache. Write-Through: As objects are created,
144
+ updated, and deleted, all of the caches are automatically kept up-to-date and coherent.'
145
+ test_files: []