preheatable_cache 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'rake'
4
+ gem 'rspec'
5
+ gem 'memcache-client', :require => 'memcache'
6
+ gem 'activesupport', '2.3.8', :require => 'active_support'
7
+ gem 'actionpack', '2.3.8', :require => 'action_pack'
data/Gemfile.lock ADDED
@@ -0,0 +1,21 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ actionpack (2.3.8)
5
+ activesupport (= 2.3.8)
6
+ rack (~> 1.1.0)
7
+ activesupport (2.3.8)
8
+ memcache-client (1.8.5)
9
+ rack (1.1.0)
10
+ rake (0.8.7)
11
+ rspec (1.3.0)
12
+
13
+ PLATFORMS
14
+ ruby
15
+
16
+ DEPENDENCIES
17
+ actionpack (= 2.3.8)
18
+ activesupport (= 2.3.8)
19
+ memcache-client
20
+ rake
21
+ rspec
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ task :default => :spec
2
+ require 'spec/rake/spectask'
3
+ Spec::Rake::SpecTask.new {|t| t.spec_opts = ['--color --backtrace']}
4
+
5
+ begin
6
+ require 'jeweler'
7
+ project_name = 'preheatable_cache'
8
+ Jeweler::Tasks.new do |gem|
9
+ gem.name = project_name
10
+ gem.summary = "Reduce cache requests by preheating via multi_get"
11
+ gem.email = "grosser.michael@gmail.com"
12
+ gem.homepage = "http://github.com/grosser/#{project_name}"
13
+ gem.authors = ["Michael Grosser"]
14
+ end
15
+
16
+ Jeweler::GemcutterTasks.new
17
+ rescue LoadError
18
+ puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
19
+ end
data/Readme.md ADDED
@@ -0,0 +1,27 @@
1
+ Reduce cache requests by preheating via multi_get.
2
+
3
+ Makes Rails MemCacheStore preheatable via read_multi, for keys that will later be used.
4
+ Clears the preheated cache after each request.
5
+
6
+ - not threadsave
7
+ - not altered when writing/incrementing/... underlying cache store
8
+
9
+ # Install
10
+ script/plugin install http://github.com/grosser/preheatable_cache
11
+
12
+ # Usage
13
+
14
+ # controller - multi_get to fetch all keys at once
15
+ Rails.cache.preheat @products.map{|p| "views/product_#{p.id}" }
16
+
17
+ # view - no requests to the cache server
18
+ <% cache "product_#{product.id}" do %>
19
+ ...
20
+ <% end %>
21
+
22
+
23
+ Author
24
+ ======
25
+ [Michael Grosser](http://pragmatig.wordpress.com)
26
+ grosser.michael@gmail.com
27
+ Hereby placed under public domain, do what you want, just do not hold me accountable...
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'preheatable_cache'
@@ -0,0 +1,73 @@
1
+ module PreheatableCache
2
+ VERSION = File.read( File.join(File.dirname(__FILE__),'..','VERSION') ).strip
3
+
4
+ NULL = 'preheatable_cache:null'
5
+
6
+ def self.included(base)
7
+ base.class_eval do
8
+ def read_with_preheatable_cache(key, options=nil)
9
+ if not @preheatable_cache
10
+ return read_without_preheatable_cache(key, options)
11
+ end
12
+
13
+ locally_cached = @preheatable_cache[key]
14
+ if locally_cached == NULL
15
+ nil
16
+ elsif locally_cached.nil?
17
+ read_without_preheatable_cache(key, options)
18
+ else
19
+ # keep preheatable cached immutable
20
+ locally_cached.duplicable? ? locally_cached.dup : locally_cached
21
+ end
22
+ end
23
+
24
+ alias_method_chain :read, :preheatable_cache
25
+ end
26
+ end
27
+
28
+ def preheat(keys)
29
+ @preheatable_cache ||= {}
30
+
31
+ data = fetch_via_read_multi(keys)
32
+ store_into_preheatable_cache data
33
+ add_cache_clearing_callback
34
+
35
+ data
36
+ end
37
+
38
+ def clear_preheatable_cache
39
+ @preheatable_cache = nil
40
+ end
41
+
42
+ private
43
+
44
+ def add_cache_clearing_callback
45
+ return if @clear_callback_added
46
+ @clear_callback_added = true
47
+ ActionDispatch::Callbacks.before proc{ clear_preheatable_cache }
48
+ end
49
+
50
+ def fetch_via_read_multi(keys)
51
+ if respond_to?(:read_multi)
52
+ hash = read_multi(keys)
53
+ # add keys for unfound values
54
+ keys.each{|k| hash[k] = nil if hash[k].nil? }
55
+ hash
56
+ else
57
+ keys.map{|key| read_without_preheatable_cache(key) }
58
+ end
59
+ end
60
+
61
+ def store_into_preheatable_cache(data)
62
+ data.each do |key, value|
63
+ @preheatable_cache[key] = if value.nil?
64
+ NULL
65
+ else
66
+ value
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ # must be included in lowest classes, to overwrite reads
73
+ ActiveSupport::Cache::MemCacheStore.send(:include, PreheatableCache)
@@ -0,0 +1,44 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{preheatable_cache}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Michael Grosser"]
12
+ s.date = %q{2010-08-14}
13
+ s.email = %q{grosser.michael@gmail.com}
14
+ s.files = [
15
+ "Gemfile",
16
+ "Gemfile.lock",
17
+ "Rakefile",
18
+ "Readme.md",
19
+ "VERSION",
20
+ "init.rb",
21
+ "lib/preheatable_cache.rb",
22
+ "preheatable_cache.gemspec",
23
+ "spec/preheatable_cache_spec.rb"
24
+ ]
25
+ s.homepage = %q{http://github.com/grosser/preheatable_cache}
26
+ s.rdoc_options = ["--charset=UTF-8"]
27
+ s.require_paths = ["lib"]
28
+ s.rubygems_version = %q{1.3.6}
29
+ s.summary = %q{Reduce cache requests by preheating via multi_get}
30
+ s.test_files = [
31
+ "spec/preheatable_cache_spec.rb"
32
+ ]
33
+
34
+ if s.respond_to? :specification_version then
35
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
36
+ s.specification_version = 3
37
+
38
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
39
+ else
40
+ end
41
+ else
42
+ end
43
+ end
44
+
@@ -0,0 +1,57 @@
1
+ require 'rubygems'
2
+
3
+ $LOAD_PATH << 'lib'
4
+ require 'active_support/all' # very messy to get working with 2.3 otherwise
5
+ require 'action_controller'
6
+ require 'preheatable_cache'
7
+
8
+ describe PreheatableCache do
9
+ let(:cache){ ActiveSupport::Cache::MemCacheStore.new }
10
+ let(:store){ cache.instance_variable_get '@data' }
11
+
12
+ describe :read do
13
+ before do
14
+ store.set('xxx', nil)
15
+ end
16
+
17
+ it "reads nil as usual" do
18
+ cache.read('xxx').should == nil
19
+ end
20
+
21
+ it "reads as usual" do
22
+ store.set('xxx', 1)
23
+ cache.read('xxx').should == 1
24
+ end
25
+
26
+ it "uses get when reading" do
27
+ cache.write('xxx', 1)
28
+ store.should_receive(:get).and_return 2
29
+ cache.read('xxx').should == 2
30
+ end
31
+
32
+ it "does not use get when it is preheated" do
33
+ cache.write('xxx', 1)
34
+ cache.preheat ['xxx']
35
+ store.should_not_receive(:get)
36
+ cache.read('xxx')
37
+ end
38
+
39
+ it "does not use get when it is preheated with nil" do
40
+ cache.preheat ['xxx']
41
+ store.should_not_receive(:get)
42
+ cache.read('xxx').should == nil
43
+ end
44
+
45
+ it "uses get when preheated cache was cleared" do
46
+ cache.write('xxx', 1)
47
+ cache.preheat ['xxx']
48
+ cache.clear_preheatable_cache
49
+ store.should_receive(:get).and_return 2
50
+ cache.read('xxx').should == 2
51
+ end
52
+ end
53
+
54
+ it "has a VERSION" do
55
+ PreheatableCache::VERSION.should =~ /^\d+\.\d+\.\d+$/
56
+ end
57
+ end
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: preheatable_cache
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Michael Grosser
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-08-14 00:00:00 +02:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description:
22
+ email: grosser.michael@gmail.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files: []
28
+
29
+ files:
30
+ - Gemfile
31
+ - Gemfile.lock
32
+ - Rakefile
33
+ - Readme.md
34
+ - VERSION
35
+ - init.rb
36
+ - lib/preheatable_cache.rb
37
+ - preheatable_cache.gemspec
38
+ - spec/preheatable_cache_spec.rb
39
+ has_rdoc: true
40
+ homepage: http://github.com/grosser/preheatable_cache
41
+ licenses: []
42
+
43
+ post_install_message:
44
+ rdoc_options:
45
+ - --charset=UTF-8
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ segments:
53
+ - 0
54
+ version: "0"
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ segments:
60
+ - 0
61
+ version: "0"
62
+ requirements: []
63
+
64
+ rubyforge_project:
65
+ rubygems_version: 1.3.6
66
+ signing_key:
67
+ specification_version: 3
68
+ summary: Reduce cache requests by preheating via multi_get
69
+ test_files:
70
+ - spec/preheatable_cache_spec.rb