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 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