covercache 0.0.1 → 0.1.0
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.
- 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
|