covercache 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/README.md +66 -22
- data/lib/covercache/version.rb +1 -1
- data/lib/covercache.rb +177 -26
- data/spec/covercache.sqlite3 +0 -0
- data/spec/libs/covercache_spec.rb +8 -0
- data/spec/spec_helper.rb +4 -0
- metadata +2 -4
- data/lib/covercache/model/cacher.rb +0 -43
- data/lib/covercache/model.rb +0 -40
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
YzU2NzM4MzljZGIzOTkyMzU2ZGYwMDBkN2Q2YzNjODQ4YmQxNDE4NQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
NDNhOTk2NmVhMjExZjcxNDhhNDJhOGY1MDA1YWE1Nzg0YmQ5N2YwNA==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
YThkMDcwYzE1Y2YzZWY2MWM4MTU4M2ZmMWY5NTFmNmZjMWEwYzVlNjJjNGEy
|
10
|
+
ZjYzZjU0ZmM1Zjk5ZTlmMWUzOGEwMWNlOThlNWFkZjAyMzVhMGFiYzQ2NTlk
|
11
|
+
M2EwNWViMDRjNTNhZjQ2OWJiODA5YWM5YmIyNDJiM2QwNzZmYzQ=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ODE1MTRlYzMzZjc4MTdkZjE1MzhmZDc4MGJmYmRkODdiZTZkYTBlMTUzZmVk
|
14
|
+
ZjFhZjkyNmUyNjFjNjgyMGFlY2JlZWI0MzU0MDVlNGE1ODZiZWRmODQ1ZGMz
|
15
|
+
ZGIwNzIxMWU0YzgwOWE3MmYzZDQ2MGZjNGMzMTFjOGE5MDE1Yzk=
|
data/README.md
CHANGED
@@ -1,16 +1,41 @@
|
|
1
1
|
# Covercache
|
2
2
|
|
3
|
-
Covercache based on PackRat
|
3
|
+
Covercache is a helper for Rails.cache, based on [PackRat](https://github.com/cpuguy83/pack_rat) gem, and, as it says: <br />
|
4
|
+
> When included in your class it makes caching trivial.
|
4
5
|
|
5
|
-
|
6
|
-
When included in your class it makes caching trivial.
|
6
|
+
## Motivation
|
7
7
|
|
8
|
-
|
8
|
+
* Quickly use <tt>Rails.cache</tt> for some tasks without rubbish code in models.
|
9
|
+
* Don't worrying about generation and storing cache keys, but sometimes will be able to adjust it.
|
10
|
+
* Cache any queries and scopes, not only `find_by` and simple associations, as many caching gems provide.
|
11
|
+
|
12
|
+
|
13
|
+
## Installation
|
14
|
+
|
15
|
+
Add this line to your application's Gemfile:
|
16
|
+
|
17
|
+
gem 'covercache'
|
18
|
+
|
19
|
+
And then execute:
|
20
|
+
|
21
|
+
$ bundle
|
22
|
+
|
23
|
+
Or install it yourself as:
|
24
|
+
|
25
|
+
$ gem install covercache
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
Add following line to your model which you want to cache:
|
9
30
|
|
10
31
|
class Post < ActiveRecord::Base
|
11
32
|
covers_with_cache
|
12
|
-
|
13
|
-
Now you can
|
33
|
+
|
34
|
+
Now you can use `define_cached`, `class_define_cached` or `covercache` helpers.
|
35
|
+
|
36
|
+
### Method covering with `covercache`
|
37
|
+
|
38
|
+
Use the `covercache` helper inside instance and class methods. Syntax is similar to PackRat `cache` helper with a few additions (see source).
|
14
39
|
|
15
40
|
has_many :comments
|
16
41
|
scope :published, where(published: true)
|
@@ -22,29 +47,48 @@ Now you can wrap methods with Covercash (like PackRat). For example:
|
|
22
47
|
end
|
23
48
|
|
24
49
|
def self.cached_published
|
25
|
-
covercache do
|
50
|
+
covercache debug:true do
|
26
51
|
published.all
|
27
52
|
end
|
28
53
|
end
|
29
54
|
|
30
55
|
|
31
|
-
|
32
|
-
|
33
|
-
Add this line to your application's Gemfile:
|
34
|
-
|
35
|
-
gem 'covercache'
|
36
|
-
|
37
|
-
And then execute:
|
38
|
-
|
39
|
-
$ bundle
|
56
|
+
### Wrapping with <tt>define_cached</tt> and `class_define_cached`
|
40
57
|
|
41
|
-
|
58
|
+
You can easily wrap methods with the <tt>define_cached</tt> helper.<br />
|
59
|
+
Note, that Relation objects couldn't be cached, so wrapped method or block
|
60
|
+
should return an array or single instance of your model.
|
42
61
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
62
|
+
To wrap instance methods you should use a name of already defined method:
|
63
|
+
|
64
|
+
class Post < ActiveRecord::Base
|
65
|
+
def all_comments
|
66
|
+
comments.all
|
67
|
+
end
|
68
|
+
|
69
|
+
# Wrap instance method Post#all_comments to Post#cached_all_comments:
|
70
|
+
define_cached :all_comments
|
71
|
+
|
72
|
+
# You can add arguments like for covercache:
|
73
|
+
# [keys], debug: true, expires_in: 10.minutes
|
74
|
+
define_cached :all_comments, expires_in: 1.minute
|
75
|
+
|
76
|
+
# ...
|
77
|
+
end
|
78
|
+
|
79
|
+
post = Post.find(1)
|
80
|
+
post.cached_all_comments
|
81
|
+
|
82
|
+
To wrap class methods you can also use blocks:
|
83
|
+
|
84
|
+
class_define_cached :for_post_ids,
|
85
|
+
debug: true,
|
86
|
+
expires_in: 10.minutes do |post_ids|
|
87
|
+
where(post_id: post_ids).all
|
88
|
+
end
|
89
|
+
|
90
|
+
post_ids = (1..10).to_a
|
91
|
+
Comments.cached_for_post_ids post_ids, cache_key: post_ids.hash
|
48
92
|
|
49
93
|
## Contributing
|
50
94
|
|
data/lib/covercache/version.rb
CHANGED
data/lib/covercache.rb
CHANGED
@@ -1,44 +1,195 @@
|
|
1
|
-
require "where"
|
2
|
-
require 'active_record'
|
3
|
-
require 'active_support/core_ext'
|
4
1
|
require "covercache/version"
|
5
|
-
require "covercache/model"
|
6
2
|
|
3
|
+
require 'active_support/core_ext'
|
4
|
+
require 'active_support/concern'
|
5
|
+
require 'active_record'
|
6
|
+
|
7
|
+
require "where"
|
8
|
+
|
9
|
+
# == Motivation
|
10
|
+
#
|
11
|
+
# * Quickly use <tt>Rails.cache</tt> for some tasks without rubbish code in models.
|
12
|
+
# * Don't worrying about generation and storing cache keys, but sometimes will be able to adjust it.
|
13
|
+
# * Don't be limited with indexes, queries or scopes.
|
14
|
+
#
|
15
|
+
# == Usage
|
16
|
+
#
|
17
|
+
# Add <tt>covers_with_cache</tt> in your model class and use <tt>define_cached</tt> or <tt>covercache</tt> helpers.
|
18
|
+
#
|
19
|
+
# == Wrapping with <tt>define_cached</tt>
|
20
|
+
#
|
21
|
+
# You can easily wrap methods with the <tt>define_cached</tt> helper.<br />
|
22
|
+
# Note, that Relation objects couldn't be cached, so wrapped method or block
|
23
|
+
# should return an array or single instance of your model.
|
24
|
+
#
|
25
|
+
# To wrap instance methods you should use a name of already defined method:
|
26
|
+
#
|
27
|
+
# class Post < ActiveRecord::Base
|
28
|
+
# def all_comments
|
29
|
+
# comments.all
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# # Wrap instance method Post#all_comments to Post#cached_all_comments:
|
33
|
+
# define_cached :all_comments
|
34
|
+
#
|
35
|
+
# # You can add arguments like for covercache: [keys], debug: true, expires_in: 10.minutes
|
36
|
+
# define_cached :all_comments, expires_in: 1.minute
|
37
|
+
#
|
38
|
+
# # ...
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# post = Post.find(1)
|
42
|
+
# post.cached_all_comments
|
43
|
+
#
|
44
|
+
# To wrap class methods you can also use use a block:
|
45
|
+
#
|
46
|
+
# class_define_cached :for_post_ids, debug: true, expires_in: 10.minutes do |post_ids|
|
47
|
+
# where(post_id: post_ids).all
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# post_ids = (1..10).to_a
|
51
|
+
# Comments.cached_for_post_ids post_ids, cache_key: post_ids.hash
|
52
|
+
#
|
7
53
|
module Covercache
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
54
|
+
# General helper method (ex <tt>cache</tt> helper in PackRat)
|
55
|
+
module Base
|
56
|
+
private # ?
|
57
|
+
def covercache(*args, &block)
|
58
|
+
options = args.extract_options!
|
59
|
+
key = []
|
60
|
+
should_debug = options[:debug].present? and options[:debug]
|
61
|
+
|
62
|
+
klass = covercaching_class_method? ? self : self.class
|
63
|
+
|
64
|
+
# Remove helper related options so we can pass to Rails.cache
|
65
|
+
filtered_options = options.except(:debug, :overwrite_key)
|
66
|
+
|
67
|
+
# if overwrite_key was set, we skip creating our own key
|
68
|
+
unless options[:overwrite_key]
|
69
|
+
model_digest = covercaching_get_model_digest
|
70
|
+
# Hack to get the method that called cache
|
71
|
+
calling_method = caller[0][/`([^']*)'/, 1]
|
72
|
+
|
73
|
+
key << klass.name
|
74
|
+
key << [model_digest, calling_method].compact.join('/')
|
75
|
+
key << cache_key if self.respond_to?(:cache_key)
|
76
|
+
key += args
|
77
|
+
end
|
78
|
+
# Output the generated cache key to the console if debug is set
|
79
|
+
puts key.inspect if should_debug
|
80
|
+
# Make the actual Rails.cache call
|
81
|
+
Rails.cache.fetch key, filtered_options do
|
82
|
+
klass.covercache_keys << key unless key.in?(klass.covercache_keys)
|
83
|
+
block.call
|
24
84
|
end
|
25
85
|
end
|
86
|
+
|
87
|
+
def covercaching_get_model_digest
|
88
|
+
self.covercache_model_digest.presence
|
89
|
+
end
|
26
90
|
|
27
|
-
|
91
|
+
def covercaching_class_method?
|
92
|
+
self.is_a? Class
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# == Defining Helper
|
97
|
+
#
|
98
|
+
# TODO: share logic
|
99
|
+
#
|
100
|
+
module DefiningHelper
|
101
|
+
# Define and wrap methods or blocks
|
28
102
|
def define_cached(*args)
|
29
103
|
method_name = args.shift
|
30
104
|
opts = args.extract_options!
|
31
|
-
|
32
|
-
|
105
|
+
# method definition
|
106
|
+
define_method :"cached_#{method_name}" do |*method_args|
|
33
107
|
if method_args.last.is_a?(Hash) and method_args.last.has_key?(:cache_key)
|
34
108
|
add_to_args = method_args.last.delete(:cache_key)
|
35
109
|
args += [add_to_args].flatten if add_to_args.present?
|
36
110
|
end
|
37
|
-
covercache(*args,
|
38
|
-
end
|
111
|
+
covercache(*args,opts){ self.send method_name, *method_args }
|
112
|
+
end
|
39
113
|
end
|
40
114
|
|
115
|
+
# TODO: not good
|
116
|
+
def class_define_cached(*args)
|
117
|
+
(class << self; self; end).instance_eval do
|
118
|
+
method_name = args.shift
|
119
|
+
opts = args.extract_options!
|
120
|
+
# method definition
|
121
|
+
define_method :"cached_#{method_name}" do |*method_args|
|
122
|
+
if method_args.last.is_a?(Hash) and method_args.last.has_key?(:cache_key)
|
123
|
+
add_to_args = method_args.last.delete :cache_key
|
124
|
+
args += [add_to_args].flatten if add_to_args.present?
|
125
|
+
end
|
126
|
+
covercache(*args, opts) do
|
127
|
+
block_given? ? yield(*method_args) : self.send(method_name, *method_args)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# Extend and Include to model Base helper so cache method is available in all contexts.
|
135
|
+
# <em>(yes, it is form PackRat too)</em>
|
136
|
+
module ModelConcern
|
137
|
+
extend ActiveSupport::Concern
|
138
|
+
|
139
|
+
included do
|
140
|
+
%w(keys model_source model_digest).each do |key, value|
|
141
|
+
class_attribute :"covercache_#{key}"
|
142
|
+
self.send(:"covercache_#{key}=", value) if value.present?
|
143
|
+
end
|
144
|
+
|
145
|
+
self.covercache_keys ||= []
|
146
|
+
self.covercache_model_source = Where.is_class self, of: 'app/models'
|
147
|
+
|
148
|
+
generate_model_digest!
|
149
|
+
|
150
|
+
after_commit :covercache_flush_cache
|
151
|
+
|
152
|
+
extend Base
|
153
|
+
include Base
|
154
|
+
end
|
155
|
+
|
156
|
+
# Support class methods
|
157
|
+
module ClassMethods
|
158
|
+
def generate_model_digest
|
159
|
+
return unless covercache_model_source?
|
160
|
+
file = File.read self.covercache_model_source
|
161
|
+
Digest::MD5.hexdigest(file)
|
162
|
+
rescue
|
163
|
+
nil
|
164
|
+
end
|
165
|
+
|
166
|
+
# Generates and sets file_digest attribute
|
167
|
+
def generate_model_digest!
|
168
|
+
self.covercache_model_digest = self.generate_model_digest
|
169
|
+
end
|
170
|
+
|
171
|
+
def covercache_flush!
|
172
|
+
self.covercache_keys.each do |key|
|
173
|
+
Rails.cache.delete(key) # if Rails.cache.exist?(key)
|
174
|
+
end.clear
|
175
|
+
self.covercache_keys.empty?
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
# flush cache on after_commit callback
|
180
|
+
def covercache_flush_cache!
|
181
|
+
self.class.send :covercache_flush!
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
# module CoversWithCache
|
186
|
+
# add Covercache supporting to model
|
187
|
+
def covers_with_cache
|
188
|
+
class_eval do
|
189
|
+
include Covercache::ModelConcern
|
190
|
+
extend Covercache::DefiningHelper
|
191
|
+
end
|
41
192
|
end
|
42
193
|
end
|
43
194
|
|
44
|
-
ActiveRecord::Base.extend Covercache
|
195
|
+
ActiveRecord::Base.extend Covercache #::CoversWithCache
|
data/spec/covercache.sqlite3
CHANGED
Binary file
|
@@ -17,6 +17,14 @@ describe "covercache" do
|
|
17
17
|
pp Post.covercache_model_digest
|
18
18
|
Post.covercache_model_digest.should be_an(String)
|
19
19
|
end
|
20
|
+
it "should respounds to instance method defined by define_cached" do
|
21
|
+
comment = Comment.last
|
22
|
+
comment.cached_post.should == comment.post
|
23
|
+
end
|
24
|
+
it "should respounds to class method defined by define_cached" do
|
25
|
+
comments = Comment.cached_for_post(1)
|
26
|
+
Post.find(1).comments.should == comments
|
27
|
+
end
|
20
28
|
it 'should return the same digest for class and instance' do
|
21
29
|
post1 = Post.find(1)
|
22
30
|
pp post1.covercache_model_digest
|
data/spec/spec_helper.rb
CHANGED
@@ -72,6 +72,10 @@ end
|
|
72
72
|
class Comment < ActiveRecord::Base
|
73
73
|
belongs_to :post
|
74
74
|
covers_with_cache
|
75
|
+
define_cached :post, debug: true
|
76
|
+
class_define_cached :for_post, debug: true do |post_id|
|
77
|
+
where(post_id: post_id).all
|
78
|
+
end
|
75
79
|
end
|
76
80
|
|
77
81
|
post1 = Post.create(:text => "First post!")
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: covercache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tõnis Simo
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-05-
|
12
|
+
date: 2013-05-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -138,8 +138,6 @@ files:
|
|
138
138
|
- Rakefile
|
139
139
|
- covercache.gemspec
|
140
140
|
- lib/covercache.rb
|
141
|
-
- lib/covercache/model.rb
|
142
|
-
- lib/covercache/model/cacher.rb
|
143
141
|
- lib/covercache/version.rb
|
144
142
|
- lib/where.rb
|
145
143
|
- spec/covercache.sqlite3
|
@@ -1,43 +0,0 @@
|
|
1
|
-
module Covercache
|
2
|
-
module Model
|
3
|
-
module Cacher
|
4
|
-
private
|
5
|
-
def covercache(*args, &block)
|
6
|
-
options = args.extract_options!
|
7
|
-
key = []
|
8
|
-
should_debug = options[:debug].present? and options[:debug]
|
9
|
-
|
10
|
-
klass = covercaching_class_method? ? self : self.class
|
11
|
-
|
12
|
-
filtered_options = options.except(:debug, :overwrite_key) # Remove PackRat related options so we can pass to Rails.cache
|
13
|
-
|
14
|
-
unless options[:overwrite_key] # if overwrite_key was set, we skip creating our own key
|
15
|
-
model_digest = covercaching_get_model_digest
|
16
|
-
calling_method = caller[0][/`([^']*)'/, 1] # Hack to get the method that called cache
|
17
|
-
|
18
|
-
key << klass.name
|
19
|
-
key << [model_digest, calling_method].compact.join('/')
|
20
|
-
key << cache_key if self.respond_to?(:cache_key)
|
21
|
-
key += args
|
22
|
-
end
|
23
|
-
|
24
|
-
puts key.inspect if should_debug # Output the generated cache key to the console if debug is set
|
25
|
-
|
26
|
-
# Make the actual Rails.cache call
|
27
|
-
Rails.cache.fetch key, filtered_options do
|
28
|
-
klass.covercache_keys << key unless key.in?(klass.covercache_keys)
|
29
|
-
block.call
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
private
|
34
|
-
def covercaching_get_model_digest
|
35
|
-
self.covercache_model_digest.presence
|
36
|
-
end
|
37
|
-
|
38
|
-
def covercaching_class_method?
|
39
|
-
self.is_a? Class
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
data/lib/covercache/model.rb
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
require 'active_support/concern'
|
2
|
-
require 'covercache/model/cacher'
|
3
|
-
|
4
|
-
module Covercache
|
5
|
-
module Model
|
6
|
-
extend ActiveSupport::Concern
|
7
|
-
|
8
|
-
included do
|
9
|
-
extend Cacher # Include and Extend so cache method is available in all contexts
|
10
|
-
include Cacher
|
11
|
-
end
|
12
|
-
|
13
|
-
module ClassMethods
|
14
|
-
def generate_model_digest
|
15
|
-
return unless covercache_model_source?
|
16
|
-
file = File.read self.covercache_model_source
|
17
|
-
Digest::MD5.hexdigest(file)
|
18
|
-
rescue
|
19
|
-
nil
|
20
|
-
end
|
21
|
-
|
22
|
-
# Generates and sets file_digest attribute
|
23
|
-
def generate_model_digest!
|
24
|
-
self.covercache_model_digest = self.generate_model_digest
|
25
|
-
end
|
26
|
-
|
27
|
-
def covercache_flush!
|
28
|
-
self.covercache_keys.each do |key|
|
29
|
-
Rails.cache.delete(key) # if Rails.cache.exist?(key)
|
30
|
-
end.clear
|
31
|
-
self.covercache_keys.empty?
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
# flush cache on after_commit callback
|
36
|
-
def covercache_flush_cache!
|
37
|
-
self.class.send :covercache_flush!
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|