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 CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- MzNkNTE2ZGNhMWY5NGZmYWMyZDY1NTE5NzhmYWQwZjlmZjEyMWVkOA==
4
+ YzU2NzM4MzljZGIzOTkyMzU2ZGYwMDBkN2Q2YzNjODQ4YmQxNDE4NQ==
5
5
  data.tar.gz: !binary |-
6
- ZWFlOWM5M2ZiZGFmZjE0NzAxNDVlYjVkMzU2YWM0ZGE2ODQ5ZDY4Mw==
6
+ NDNhOTk2NmVhMjExZjcxNDhhNDJhOGY1MDA1YWE1Nzg0YmQ5N2YwNA==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- NDJhMjcxZGQzZWYwMTAxNWMxNTQxMDdhNTM3ZGMxNmU4MDgzYmYwYzJjN2Vm
10
- YWJkNjE5N2JjNGRkMmYxODczYmI0MDZmODlhNzJiZTQ4ZDg4YjU1M2NhMjUz
11
- ZDk5ODdmODk5MjVkNTUyODE5YTc1ZDhlYmI3OWZlMDhiZjI0MjY=
9
+ YThkMDcwYzE1Y2YzZWY2MWM4MTU4M2ZmMWY5NTFmNmZjMWEwYzVlNjJjNGEy
10
+ ZjYzZjU0ZmM1Zjk5ZTlmMWUzOGEwMWNlOThlNWFkZjAyMzVhMGFiYzQ2NTlk
11
+ M2EwNWViMDRjNTNhZjQ2OWJiODA5YWM5YmIyNDJiM2QwNzZmYzQ=
12
12
  data.tar.gz: !binary |-
13
- NmQ4MmJiNjIyNzM5ZjgwMGUwNWJiNzkyOTljMDEzYWVhMmE3MzMxNzI3ZmIz
14
- NzdkYjFlNzNlYWRjNGI1MGJhZTY1YzJjN2Q1OWE4MmZjZWMwMjk2ZDkyM2Iw
15
- ZjI1NGM4NmQ1NDcxNGMyNjQ3ODhlMzYwNTBlNWYyYjg3MzcwYmM=
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
- Covercache is a simple helper for Rails.cache<br />
6
- When included in your class it makes caching trivial.
6
+ ## Motivation
7
7
 
8
- Add following line to your model which you want to cache
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 wrap methods with Covercash (like PackRat). For example:
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
- ## Installation
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
- Or install it yourself as:
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
- $ gem install covercache
44
-
45
- ## Usage
46
-
47
- TODO: Write usage instructions here
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
 
@@ -1,3 +1,3 @@
1
1
  module Covercache
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
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
- module CoversWithCache
9
- def covers_with_cache
10
- class_eval do
11
- %w(keys model_source model_digest).each do |key, value|
12
- class_attribute :"covercache_#{key}"
13
- self.send(:"covercache_#{key}=", value) if value.present?
14
- end
15
-
16
- self.covercache_keys ||= []
17
- self.covercache_model_source = Where.is_class self, of: 'app/models'
18
-
19
- include Covercache::Model
20
-
21
- generate_model_digest!
22
-
23
- after_commit :covercache_flush_cache
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
- # TODO: coming soon...
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
- define_method :"cached_#{method_name}" do |*method_args|
32
- puts self.inspect
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, opts) { self.send(method_name, *method_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::CoversWithCache
195
+ ActiveRecord::Base.extend Covercache #::CoversWithCache
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.1
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-19 00:00:00.000000000 Z
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
@@ -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