covercache 0.1.0 → 0.2

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
- YzU2NzM4MzljZGIzOTkyMzU2ZGYwMDBkN2Q2YzNjODQ4YmQxNDE4NQ==
4
+ YjlhOGViNGViNzYwZDEyNjg3ZjQ1N2ZhNjFiYWY3OGJmMTY5ODVmNw==
5
5
  data.tar.gz: !binary |-
6
- NDNhOTk2NmVhMjExZjcxNDhhNDJhOGY1MDA1YWE1Nzg0YmQ5N2YwNA==
6
+ MmE3MDFlNmU0ZDQ4NDVjNjEwN2EwOWQxMjI5NDVmY2FiODA3ZjVmYQ==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- YThkMDcwYzE1Y2YzZWY2MWM4MTU4M2ZmMWY5NTFmNmZjMWEwYzVlNjJjNGEy
10
- ZjYzZjU0ZmM1Zjk5ZTlmMWUzOGEwMWNlOThlNWFkZjAyMzVhMGFiYzQ2NTlk
11
- M2EwNWViMDRjNTNhZjQ2OWJiODA5YWM5YmIyNDJiM2QwNzZmYzQ=
9
+ NjM3YmJmN2NjMzI2NzBlYjU5MDQ5ZmI5YjBhY2E4MDllY2I1MTM4YzdhMWE0
10
+ YjQ4M2EzYTk3ZjJjODZkMGYwYTYwMDIxY2Y0Yzk3OGI0ZTczOWI5NWE3N2Vj
11
+ ZTJjZDEyZThjMDNmOTY1MGMyYzE2YTY3ZGJkMjllMDlmZmEwZWY=
12
12
  data.tar.gz: !binary |-
13
- ODE1MTRlYzMzZjc4MTdkZjE1MzhmZDc4MGJmYmRkODdiZTZkYTBlMTUzZmVk
14
- ZjFhZjkyNmUyNjFjNjgyMGFlY2JlZWI0MzU0MDVlNGE1ODZiZWRmODQ1ZGMz
15
- ZGIwNzIxMWU0YzgwOWE3MmYzZDQ2MGZjNGMzMTFjOGE5MDE1Yzk=
13
+ MmQ5OTllYzMwZmUyMmZlYzk2MmUyNzMyOGEyMmI1ZWY2OTg3ZDkxNjBiYzBk
14
+ NmNjMTE4ZDA1ZGMxMjU1MGFhZGE0ZDIwZjZiZDY1ZGQ3Zjc4OTEzM2EzMzlk
15
+ N2YxOTRkYjY2ZjE3ZTFkMjhiMjEyYjE3MjcyYjRhMmM2OWNiOTY=
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Covercache
2
2
 
3
+ [![Code Climate](https://codeclimate.com/github/estum/covercache.png)](https://codeclimate.com/github/estum/covercache)
4
+
3
5
  Covercache is a helper for Rails.cache, based on [PackRat](https://github.com/cpuguy83/pack_rat) gem, and, as it says: <br />
4
6
  > When included in your class it makes caching trivial.
5
7
 
@@ -59,7 +61,7 @@ You can easily wrap methods with the <tt>define_cached</tt> helper.<br />
59
61
  Note, that Relation objects couldn't be cached, so wrapped method or block
60
62
  should return an array or single instance of your model.
61
63
 
62
- To wrap instance methods you should use a name of already defined method:
64
+ To wrap instance methods you should use a name of already defined method or set block with the first argument as record:
63
65
 
64
66
  class Post < ActiveRecord::Base
65
67
  def all_comments
@@ -72,7 +74,10 @@ To wrap instance methods you should use a name of already defined method:
72
74
  # You can add arguments like for covercache:
73
75
  # [keys], debug: true, expires_in: 10.minutes
74
76
  define_cached :all_comments, expires_in: 1.minute
75
-
77
+
78
+ define_cached :all_comments_authors, debug: true, do |record|
79
+ record.author
80
+ end
76
81
  # ...
77
82
  end
78
83
 
data/covercache.gemspec CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.email = ["anton.estum@gmail.com"]
11
11
  spec.description = %q{Helper method to simplify Rails caching, based on PackRat}
12
12
  spec.summary = %q{Rails cache helper based on PackRat gem}
13
- spec.homepage = "http://github.com/tonissimo/covercache"
13
+ spec.homepage = "http://github.com/estum/covercache"
14
14
  spec.license = "MIT"
15
15
 
16
16
  spec.files = `git ls-files`.split($/)
@@ -1,3 +1,3 @@
1
1
  module Covercache
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2"
3
3
  end
data/lib/covercache.rb CHANGED
@@ -4,8 +4,6 @@ require 'active_support/core_ext'
4
4
  require 'active_support/concern'
5
5
  require 'active_record'
6
6
 
7
- require "where"
8
-
9
7
  # == Motivation
10
8
  #
11
9
  # * Quickly use <tt>Rails.cache</tt> for some tasks without rubbish code in models.
@@ -22,7 +20,7 @@ require "where"
22
20
  # Note, that Relation objects couldn't be cached, so wrapped method or block
23
21
  # should return an array or single instance of your model.
24
22
  #
25
- # To wrap instance methods you should use a name of already defined method:
23
+ # To wrap instance methods you should use a name of already defined method or set block with the first argument as record:
26
24
  #
27
25
  # class Post < ActiveRecord::Base
28
26
  # def all_comments
@@ -35,13 +33,16 @@ require "where"
35
33
  # # You can add arguments like for covercache: [keys], debug: true, expires_in: 10.minutes
36
34
  # define_cached :all_comments, expires_in: 1.minute
37
35
  #
36
+ # define_cached :all_comments_authors, expires_in: 1.minute do |record|
37
+ # record.author
38
+ # end
38
39
  # # ...
39
40
  # end
40
41
  #
41
42
  # post = Post.find(1)
42
43
  # post.cached_all_comments
43
44
  #
44
- # To wrap class methods you can also use use a block:
45
+ # To wrap class methods:
45
46
  #
46
47
  # class_define_cached :for_post_ids, debug: true, expires_in: 10.minutes do |post_ids|
47
48
  # where(post_id: post_ids).all
@@ -52,85 +53,119 @@ require "where"
52
53
  #
53
54
  module Covercache
54
55
  # 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)
56
+ module Base
57
+ # Arguments:
58
+ #
59
+ # [1..] any count of custom *keys
60
+ # :debug #=>
61
+ # :without_auto_key #=> don't generate cache_key
62
+ # any option for Rails.cache.fetch
63
+ #
64
+ # Example:
65
+ #
66
+ # scope :published, -> { where published: true }
67
+ # has_many :comments
68
+ #
69
+ # def cached_comments
70
+ # covercache do
71
+ # comments.all
72
+ # end
73
+ # end
74
+ #
75
+ # def self.cached_published
76
+ # covercache debug:true do
77
+ # published.all
78
+ # end
79
+ # end
80
+ #
81
+ private
82
+ def covercache(*keys, &block)
83
+ klass = class_or_instance_class
84
+ options = keys.extract_options!
85
+ cover_opts = options.extract! :debug, :without_auto_key
66
86
 
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)
87
+ # if :no_auto_cache_keys was set, we skip creating our own key
88
+ keys.prepend get_auto_cache_key(klass.name, caller) unless cover_opts[:without_auto_key]
89
+ keys.flatten!
90
+ puts keys.inspect if !!cover_opts[:debug]
91
+ # puts caller.inspect if !!cover_opts[:debug],
92
+
93
+ Rails.cache.fetch keys, options do
94
+ klass.covercache_keys |= [ keys ]
83
95
  block.call
84
96
  end
85
97
  end
86
-
87
- def covercaching_get_model_digest
88
- self.covercache_model_digest.presence
98
+
99
+ def get_auto_cache_key(class_name, _caller)
100
+ caller_method = _caller.map {|c| c[/`([^']*)'/, 1] }.detect {|m| !m.start_with?('block') }
101
+ puts caller_method.inspect
102
+ [ class_name, covercache_model_digest, caller_method, (cache_key if self.respond_to?(:cache_key?)) ].compact
103
+ end
104
+
105
+ def class_or_instance_class
106
+ self.is_a?(Class) ? self : self.class
89
107
  end
90
108
 
91
- def covercaching_class_method?
92
- self.is_a? Class
109
+ def extract_cache_key_from(*args)
110
+ Array.wrap((args.last.delete(:cache_key) if args.last.is_a?(Hash)))
93
111
  end
94
112
  end
95
113
 
96
114
  # == Defining Helper
97
115
  #
98
- # TODO: share logic
99
- #
100
116
  module DefiningHelper
101
117
  # Define and wrap methods or blocks
102
- def define_cached(*args)
103
- method_name = args.shift
104
- opts = args.extract_options!
105
- # method definition
106
- define_method :"cached_#{method_name}" do |*method_args|
107
- if method_args.last.is_a?(Hash) and method_args.last.has_key?(:cache_key)
108
- add_to_args = method_args.last.delete(:cache_key)
109
- args += [add_to_args].flatten if add_to_args.present?
110
- end
111
- covercache(*args,opts){ self.send method_name, *method_args }
112
- end
118
+ def define_cached(method, *args, &block)
119
+ options = args.extract_options!
120
+ is_class_method = !!options.delete(:is_class_method)
121
+
122
+ file, line = caller[is_class_method ? 1 : 0].split ':', 2
123
+ line = line.to_i
124
+
125
+ covercache_method_arguments method, args, options, &block
126
+ covercache_define_wrapper method, file, line, block_given?, is_class_method
127
+ end
128
+
129
+ def class_define_cached(method, *args, &block)
130
+ options = args.extract_options!
131
+ options[:is_class_method] = true
132
+ self.send :define_cached, method, *args, options, &block
113
133
  end
114
134
 
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)
135
+ private
136
+ def covercache_define_wrapper(method, file, line, with_block=false, is_class_method=false)
137
+ cached_method = "cached_#{method}"
138
+
139
+ class_eval(<<-EOS, file, line - 2)
140
+ def #{'self.' if is_class_method}#{cached_method}(*args, &block)
141
+ settings = Array.wrap(#{cached_method}_settings[:args]) + extract_cache_key_from(*args)
142
+ covercache(*settings, #{cached_method}_settings[:opts]) do
143
+ if #{with_block}
144
+ #{cached_method}_settings[:block].call(#{'self,' unless is_class_method}*args)
145
+ else
146
+ self.__send__ :#{method}, *args, &block
147
+ end
128
148
  end
129
149
  end
130
- end
150
+ EOS
151
+ end
152
+
153
+ def covercache_method_arguments(method, *args, &block)
154
+ settings = collect_method_args_to_hash(*args, &block)
155
+ puts settings.inspect
156
+ class_attribute :"cached_#{method}_settings"
157
+ self.send(:"cached_#{method}_settings=", settings)
158
+ end
159
+
160
+ def collect_method_args_to_hash(*args, &block)
161
+ puts args.inspect
162
+ Hash[ %w{args opts block}.map do |x|
163
+ [ x, (args.shift || block) ]
164
+ end].to_options
131
165
  end
132
166
  end
133
167
 
168
+
134
169
  # Extend and Include to model Base helper so cache method is available in all contexts.
135
170
  # <em>(yes, it is form PackRat too)</em>
136
171
  module ModelConcern
@@ -143,7 +178,7 @@ module Covercache
143
178
  end
144
179
 
145
180
  self.covercache_keys ||= []
146
- self.covercache_model_source = Where.is_class self, of: 'app/models'
181
+ self.covercache_model_source ||= @covercache_caller_source #Where.is_class self, of: 'app/models'
147
182
 
148
183
  generate_model_digest!
149
184
 
@@ -165,14 +200,12 @@ module Covercache
165
200
 
166
201
  # Generates and sets file_digest attribute
167
202
  def generate_model_digest!
168
- self.covercache_model_digest = self.generate_model_digest
203
+ self.covercache_model_digest = generate_model_digest
169
204
  end
170
205
 
171
206
  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?
207
+ self.covercache_keys.each { |key| Rails.cache.delete(key) }.clear # if Rails.cache.exist?(key)
208
+ covercache_keys.empty?
176
209
  end
177
210
  end
178
211
 
@@ -185,7 +218,10 @@ module Covercache
185
218
  # module CoversWithCache
186
219
  # add Covercache supporting to model
187
220
  def covers_with_cache
221
+ caller_source = caller.first[/[^:]+/]
222
+
188
223
  class_eval do
224
+ @covercache_caller_source = caller_source
189
225
  include Covercache::ModelConcern
190
226
  extend Covercache::DefiningHelper
191
227
  end
Binary file
@@ -5,10 +5,6 @@ describe "covercache" do
5
5
  it 'should respond to covers_with_cache' do
6
6
  Post.should respond_to(:covers_with_cache)
7
7
  end
8
- it 'should hove class keys storage' do
9
- pp Post.covercache_keys
10
- Post.covercache_keys.should be_an(Array)
11
- end
12
8
  it 'should have covercache_model_source attribute' do
13
9
  pp Post.covercache_model_source
14
10
  Post.covercache_model_source.should be_an(String)
@@ -36,4 +32,12 @@ describe "covercache" do
36
32
  pp test.cached_comments.inspect
37
33
  test.cached_comments.count.should == test.comments.count
38
34
  end
35
+ it 'post should have class keys storage' do
36
+ pp Post.covercache_keys
37
+ Post.covercache_keys.should be_an(Array)
38
+ end
39
+ it 'comments should have class keys storage' do
40
+ pp Comment.covercache_keys
41
+ Comment.covercache_keys.should be_an(Array)
42
+ end
39
43
  end
data/spec/spec_helper.rb CHANGED
@@ -62,17 +62,20 @@ end
62
62
  class Post < ActiveRecord::Base
63
63
  has_many :comments
64
64
  covers_with_cache
65
- def cached_comments
66
- covercache debug: true do
67
- comments.all
68
- end
69
- end
65
+ define_cached :comments, debug: true
66
+ # def cached_comments
67
+ # covercache debug: true do
68
+ # comments.all
69
+ # end
70
+ # end
70
71
  end
71
72
 
72
73
  class Comment < ActiveRecord::Base
73
74
  belongs_to :post
74
75
  covers_with_cache
75
- define_cached :post, debug: true
76
+ define_cached :post, debug: true do |record|
77
+ record.post
78
+ end
76
79
  class_define_cached :for_post, debug: true do |post_id|
77
80
  where(post_id: post_id).all
78
81
  end
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.1.0
4
+ version: '0.2'
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-20 00:00:00.000000000 Z
12
+ date: 2013-05-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -139,11 +139,10 @@ files:
139
139
  - covercache.gemspec
140
140
  - lib/covercache.rb
141
141
  - lib/covercache/version.rb
142
- - lib/where.rb
143
142
  - spec/covercache.sqlite3
144
143
  - spec/libs/covercache_spec.rb
145
144
  - spec/spec_helper.rb
146
- homepage: http://github.com/tonissimo/covercache
145
+ homepage: http://github.com/estum/covercache
147
146
  licenses:
148
147
  - MIT
149
148
  metadata: {}
data/lib/where.rb DELETED
@@ -1,69 +0,0 @@
1
- # A little Ruby module for finding the source location where class and methods are defined.
2
- # https://gist.github.com/wtaysom/1236979
3
-
4
- module Where
5
- #== Example
6
- #
7
- # Where.is_class Post, of: 'app/models'
8
- #
9
- class <<self
10
- def is_class(klass, opts={})
11
- methods = defined_methods(klass)
12
- file_groups = methods.group_by{|sl| sl[0]}
13
- file_counts = file_groups.map do |file, sls|
14
- lines = sls.map{|sl| sl[1]}
15
- count = lines.size
16
- line = lines.min
17
- {file: file, count: count, line: line}
18
- end
19
- file_counts.sort_by!{|fc| fc[:count]}
20
-
21
- if opts[:of].present?
22
- path_expand = joins_path(opts[:of])
23
- return File.expand_path("../../spec/spec_helper.rb", __FILE__) unless !!path_expand
24
- pattern = Regexp.new "^#{path_expand}/.*"
25
- matches = file_counts.select do |fc|
26
- !!fc[:file][pattern]
27
- end
28
- return matches.first[:file] if matches.first.present?
29
- end
30
-
31
- source_locations = file_counts.map{|fc| [fc[:file], fc[:line]]}
32
- source_locations
33
- end
34
-
35
- private
36
- def joins_path(of)
37
- Rails.root.join(of).to_s
38
- rescue NameError
39
- return false
40
- end
41
-
42
- def source_location(method)
43
- method.source_location || (
44
- method.to_s =~ /: (.*)>/
45
- $1
46
- )
47
- end
48
-
49
- def defined_methods(klass)
50
- methods = klass.methods(false).map{|m| klass.method(m)} +
51
- klass.instance_methods(false).map{|m| klass.instance_method(m)}
52
- methods.map!(&:source_location)
53
- methods.compact!
54
- methods
55
- end
56
- end
57
- end
58
-
59
- def where_is(klass, method = nil)
60
- Where.edit(if method
61
- begin
62
- Where.is_instance_method(klass, method)
63
- rescue NameError
64
- Where.is_method(klass, method)
65
- end
66
- else
67
- Where.is_class_primarily(klass)
68
- end)
69
- end