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