cache_advance 1.1.4

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ rdoc
2
+ pkg
3
+ *.gem
data/CHANGELOG ADDED
@@ -0,0 +1,8 @@
1
+ 1.1.2
2
+
3
+ * Strip whitespace from keys in order to avoid errors from memcache.
4
+ * Symbolize cache names.
5
+
6
+ 1.1.1
7
+
8
+ * Fixed a bug where the enabled flag would expire, causing caches to be reenabled.
data/README.textile ADDED
@@ -0,0 +1,47 @@
1
+ h1. cache advance
2
+
3
+ CacheAdvance is a wrapper around the Rails caching system that provides a simple, centralized
4
+ configuration file for defining caches and an even simpler way to apply them.
5
+
6
+ Written by "Aubrey Holland":mailto:aubreyholland@gmail.com.
7
+
8
+ h3. download
9
+
10
+ Github: "Page":http://github.com/aub/cache_advance/tree/master
11
+
12
+ Gem: <pre>gem install aub-cache_advance --source http://gems.github.com</pre>
13
+
14
+ Note: if you install using the gem from Github, you'll need this
15
+ in your environment.rb if you want to use Rails 2.1's dependency manager:
16
+
17
+ <pre><code>
18
+ config.gem 'aub-cache_advance', :lib => 'cache_advance', :source => 'http://gems.github.com'
19
+ </code></pre>
20
+
21
+ h3. cache definition
22
+
23
+ Caches are defined in the file config/caches.rb, which will be loaded automatically by the gem.
24
+ This file is similar in format to the rails routes config file, allowing you to specify named
25
+ caches and configure their keys and how they will be expired.
26
+
27
+ <pre><code>
28
+ CacheAdvance::Caches.define_caches do |config|
29
+
30
+ config.qualifier(:params) do |request|
31
+ request.params
32
+ end
33
+
34
+ config.plugin :template_handler_observer_cache_plugin
35
+
36
+ config.content_block :expiration_time => 10.minutes, :qualifiers => [ :subdomain, :params ]
37
+
38
+ config.change_towns_all :expiration_types => [ :publication ]
39
+ config.change_towns_limited :expiration_types => [ :publication ]
40
+
41
+ config.publication_twitter_update :expiration_time => 10.minutes, :qualifiers => [ :subdomain ]
42
+
43
+ config.weather_widget :expiration_time => 10.minutes, :qualifiers => [ :subdomain ]
44
+ end
45
+ </code></pre>
46
+
47
+ ..............More later.
data/Rakefile ADDED
@@ -0,0 +1,23 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+
5
+ FileList['tasks/**/*.rake'].each { |file| load file }
6
+
7
+ task :default => 'test'
8
+
9
+ begin
10
+ require 'jeweler'
11
+ Jeweler::Tasks.new do |gemspec|
12
+ gemspec.name = 'cache_advance'
13
+ gemspec.summary = 'A declarative system for caching with ActiveRecord'
14
+ gemspec.email = 'aubreyholland@gmail.com'
15
+ gemspec.homepage = 'http://github.com/aub/cache_advance/tree/master'
16
+ gemspec.description = 'hmm'
17
+ gemspec.authors = ['Aubrey Holland']
18
+ end
19
+ Jeweler::GemcutterTasks.new
20
+ rescue LoadError
21
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
22
+ end
23
+
data/TODO.textile ADDED
@@ -0,0 +1,6 @@
1
+ - Fix to allow keys of > 256 characters with memcache
2
+ - Make test coverage not pitiful
3
+ - Add ability for cache to expire when a specific object changes
4
+ - Apply plugins only to specific caches
5
+ - Test with caching strategies other than memcache
6
+ - Improve documentation
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.1.4
@@ -0,0 +1,68 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{cache_advance}
8
+ s.version = "1.1.4"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Aubrey Holland"]
12
+ s.date = %q{2009-10-21}
13
+ s.description = %q{hmm}
14
+ s.email = %q{aubreyholland@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "README.textile"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ "CHANGELOG",
21
+ "README.textile",
22
+ "Rakefile",
23
+ "TODO.textile",
24
+ "VERSION",
25
+ "cache_advance.gemspec",
26
+ "lib/cache_advance.rb",
27
+ "lib/cache_advance/active_record_sweeper.rb",
28
+ "lib/cache_advance/cache_set.rb",
29
+ "lib/cache_advance/cached_key_list.rb",
30
+ "lib/cache_advance/lock.rb",
31
+ "lib/cache_advance/mapper.rb",
32
+ "lib/cache_advance/named_cache.rb",
33
+ "lib/cache_advance/named_cache_configuration.rb",
34
+ "rails/init.rb",
35
+ "script/console",
36
+ "test/active_record_sweeper_test.rb",
37
+ "test/cache_mock.rb",
38
+ "test/cache_set_test.rb",
39
+ "test/key_test.rb",
40
+ "test/mapper_test.rb",
41
+ "test/named_cache_test.rb",
42
+ "test/test_helper.rb"
43
+ ]
44
+ s.homepage = %q{http://github.com/aub/cache_advance/tree/master}
45
+ s.rdoc_options = ["--charset=UTF-8"]
46
+ s.require_paths = ["lib"]
47
+ s.rubygems_version = %q{1.3.5}
48
+ s.summary = %q{A declarative system for caching with ActiveRecord}
49
+ s.test_files = [
50
+ "test/active_record_sweeper_test.rb",
51
+ "test/cache_mock.rb",
52
+ "test/cache_set_test.rb",
53
+ "test/key_test.rb",
54
+ "test/mapper_test.rb",
55
+ "test/named_cache_test.rb",
56
+ "test/test_helper.rb"
57
+ ]
58
+
59
+ if s.respond_to? :specification_version then
60
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
61
+ s.specification_version = 3
62
+
63
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
64
+ else
65
+ end
66
+ else
67
+ end
68
+ end
@@ -0,0 +1,32 @@
1
+ require 'rubygems'
2
+ gem 'activerecord'
3
+ require 'active_record/observer'
4
+
5
+ module CacheAdvance
6
+ class ActiveRecordSweeper < ::ActiveRecord::Observer
7
+
8
+ def self.initialize_observed(classes)
9
+ observe(classes)
10
+ end
11
+
12
+ def reload_sweeper
13
+ observed_classes.each do |klass|
14
+ klass.name.constantize.add_observer(self)
15
+ end
16
+ end
17
+
18
+ def after_create(object)
19
+ expire_caches_for(object)
20
+ end
21
+
22
+ alias_method :after_update, :after_create
23
+ alias_method :after_destroy, :after_create
24
+
25
+ protected
26
+
27
+ def expire_caches_for(object)
28
+ class_symbol = object.class.name.underscore.to_sym
29
+ CacheAdvance.cache_set.expire_for_class(class_symbol)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,57 @@
1
+ module CacheAdvance
2
+ class CacheSet
3
+ attr_reader :named_caches
4
+ attr_reader :qualifiers
5
+ attr_reader :plugins
6
+
7
+ def initialize(store)
8
+ @store, @named_caches, @qualifiers, @plugins = store, {}, {}, []
9
+ end
10
+
11
+ def setup_complete
12
+
13
+ end
14
+
15
+ def apply(cache_name, request, options, &block)
16
+ cache_name = cache_name.to_sym
17
+ if CacheAdvance.caching_enabled
18
+ named_cache = @named_caches[cache_name]
19
+ raise UnknownNamedCacheException if named_cache.nil?
20
+ named_cache.value_for(request, options, &block)
21
+ else
22
+ block.call
23
+ end
24
+ end
25
+
26
+ def add_qualifier(name, proc)
27
+ @qualifiers[name] = proc
28
+ end
29
+
30
+ def add_plugin(plugin)
31
+ @plugins << plugin
32
+ end
33
+
34
+ def add_named_cache(name, options)
35
+ name = name.to_sym
36
+ @named_caches[name] = NamedCache.new(name, options, self, @store)
37
+ end
38
+
39
+ def define_caches
40
+ yield Mapper.new(self)
41
+ end
42
+
43
+ def create_sweepers
44
+ @sweeper_type.initialize_observed(@named_caches.values.map { |c| c.expiration_types }.flatten.compact.uniq)
45
+ end
46
+
47
+ def expire_for_class(class_name)
48
+ @named_caches.values.each do |named_cache|
49
+ named_cache.expire_for(class_name)
50
+ end
51
+ end
52
+
53
+ def sweeper_type=(type)
54
+ @sweeper_type = type
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,46 @@
1
+ module CacheAdvance
2
+ class CachedKeyList
3
+ def initialize(store, cache_key, expiration_time=nil)
4
+ @store, @cache_key, @expiration_time = store, cache_key, expiration_time
5
+ end
6
+
7
+ def all_keys
8
+ key_list.keys
9
+ end
10
+
11
+ def add_key(key)
12
+ Lock.new(@store).execute_locked(@cache_key) do
13
+ data = key_list
14
+ unless data.has_key?(key)
15
+ data[key] = @expiration_time.nil? ? nil : Time.now + @expiration_time
16
+ @store.set(@cache_key, data)
17
+ end
18
+ end
19
+ end
20
+
21
+ def delete_key(key)
22
+ Lock.new(@store).execute_locked(@cache_key) do
23
+ data = key_list
24
+ if data.has_key?(key)
25
+ data.delete(key)
26
+ @store.set(@cache_key, data)
27
+ end
28
+ end
29
+ end
30
+
31
+ def clear
32
+ @store.set(@cache_key, {})
33
+ end
34
+
35
+ protected
36
+
37
+ def key_list
38
+ list = @store.get(@cache_key) || {}
39
+ if @expiration_time
40
+ now = Time.now
41
+ list.delete_if { |k,v| v <= now }
42
+ end
43
+ list
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,40 @@
1
+ module CacheAdvance
2
+ class Lock
3
+
4
+ class LockAcquisitionFailureException < Exception; end
5
+
6
+ DEFAULT_RETRIES = 5
7
+ DEFAULT_EXPIRATION_TIME = 30
8
+
9
+ def initialize(store)
10
+ @store = store
11
+ end
12
+
13
+ def execute_locked(key, lock_expiry = DEFAULT_EXPIRATION_TIME, retries = DEFAULT_RETRIES)
14
+ begin
15
+ acquire(key, lock_expiry, retries)
16
+ yield
17
+ ensure
18
+ release_lock(key)
19
+ end
20
+ end
21
+
22
+ def acquire(key, lock_expiry = DEFAULT_EXPIRATION_TIME, retries = DEFAULT_RETRIES)
23
+ retries.times do |count|
24
+ begin
25
+ return if @store.set("lock/#{key}", Process.pid, lock_expiry) == "STORED\r\n"
26
+ end
27
+ exponential_sleep(count) unless count == retries - 1
28
+ end
29
+ raise LockAcquisitionFailureException, "Couldn't acquire memcache lock for: #{key}"
30
+ end
31
+
32
+ def release_lock(key)
33
+ @store.delete("lock/#{key}")
34
+ end
35
+
36
+ def exponential_sleep(count)
37
+ sleep((2**count) / 10.0)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,29 @@
1
+ gem 'activesupport'
2
+ require 'active_support/core_ext'
3
+
4
+ module CacheAdvance
5
+ class Mapper
6
+ def initialize(cache_set)
7
+ @cache_set = cache_set
8
+ end
9
+
10
+ def qualifier(name, &proc)
11
+ @cache_set.add_qualifier(name, proc)
12
+ end
13
+
14
+ def plugin(name)
15
+ if name.is_a?(Symbol)
16
+ plugin = name.to_s.camelcase.constantize.new
17
+ elsif name.is_a?(Class)
18
+ plugin = name.new
19
+ else
20
+ plugin = name
21
+ end
22
+ @cache_set.add_plugin(plugin)
23
+ end
24
+
25
+ def method_missing(method, options={})
26
+ @cache_set.add_named_cache(method, options)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,124 @@
1
+ module CacheAdvance
2
+ class NamedCache
3
+
4
+ ENABLED_CHECK_INTERVAL = 60
5
+
6
+ def initialize(name, params, cache_set, store)
7
+ @name = name.to_s
8
+ @params = params
9
+ @cache_set = cache_set
10
+ @store = store
11
+ @cached_key_list = CachedKeyList.new(@store, "#{@name}/STORED_CACHES", expiration_time)
12
+ @enabled_check_time = Time.now + ENABLED_CHECK_INTERVAL
13
+ @enabled = nil
14
+ end
15
+
16
+ def value_for(request, options, &block)
17
+ return block.call unless enabled?
18
+
19
+ key = key_for(request, options[:key])
20
+
21
+ if (value = read_from_store(key))
22
+ each_plugin { |p| p.send('after_read', @name, key, value, options) if p.respond_to?('after_read') }
23
+ return value
24
+ end
25
+
26
+ each_plugin { |p| p.send('before_render', @name, key, options) if p.respond_to?('before_render') }
27
+ result = block.call
28
+ each_plugin { |p| p.send('after_render', @name, key, result, options) if p.respond_to?('after_render') }
29
+ each_plugin { |p| p.send('before_write', @name, key, result, options) if p.respond_to?('before_write') }
30
+ write_to_store(key, result)
31
+ each_plugin { |p| p.send('after_write', @name, key, result, options) if p.respond_to?('after_write') }
32
+ result
33
+ end
34
+
35
+ def expire_for(type)
36
+ if expiration_types.include?(type)
37
+ expire_all
38
+ end
39
+ end
40
+
41
+ def expire_all
42
+ delete_all_from_store
43
+ end
44
+
45
+ def all_cached_keys
46
+ @cached_key_list.all_keys
47
+ end
48
+
49
+ def expiration_types
50
+ Array(@params[:expiration_types])
51
+ end
52
+
53
+ def title
54
+ @params[:title] || @name.to_s
55
+ end
56
+
57
+ def enabled=(state)
58
+ @enabled = !!state
59
+ @store.set(enabled_key, @enabled)
60
+ end
61
+
62
+ def enabled?
63
+ if @enabled.nil? || Time.now >= @enabled_check_time
64
+ @enabled = [nil, true].include?(read_from_store(enabled_key, false))
65
+ @enabled_check_time = Time.now + ENABLED_CHECK_INTERVAL
66
+ end
67
+ @enabled
68
+ end
69
+
70
+ protected
71
+
72
+ def read_from_store(key, add_to_key_list=true)
73
+ data = @store.get(key)
74
+ # this is to prevent a situation where the cached key list forgets
75
+ # about keys that are actually cached.
76
+ if data && add_to_key_list
77
+ @cached_key_list.add_key(key)
78
+ end
79
+ data
80
+ end
81
+
82
+ def write_to_store(key, value)
83
+ expiration_time ? @store.set(key, value, expiration_time) : @store.set(key, value)
84
+ @cached_key_list.add_key(key)
85
+ end
86
+
87
+ def delete_from_store(key)
88
+ @store.delete(key)
89
+ @cached_key_list.delete_key(key)
90
+ end
91
+
92
+ def delete_all_from_store
93
+ @cached_key_list.all_keys.each { |key| delete_from_store(key) }
94
+ @cached_key_list.clear
95
+ end
96
+
97
+ def each_plugin
98
+ @cache_set.plugins.each do |p|
99
+ yield p
100
+ end
101
+ end
102
+
103
+ def key_for(request, suffix='')
104
+ qualifier_data = qualifiers.map do |q|
105
+ if (qualifier = @cache_set.qualifiers[q])
106
+ (qualifier.call(request) || '').to_s
107
+ end
108
+ end.join('/')
109
+ "#{@name}/#{suffix}/[#{qualifier_data}]".gsub(/\s/, '')
110
+ end
111
+
112
+ def enabled_key
113
+ "#{@name}/ENABLED_STATUS"
114
+ end
115
+
116
+ def expiration_time
117
+ @params[:expiration_time]
118
+ end
119
+
120
+ def qualifiers
121
+ Array(@params[:qualifiers])
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,7 @@
1
+ module CacheAdvance
2
+ class NamedCacheConfiguration
3
+ def initialize(options)
4
+ @options = options
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,21 @@
1
+ %w( cache_set cached_key_list lock mapper named_cache named_cache_configuration).each do |file|
2
+ require File.join(File.dirname(__FILE__), 'cache_advance', file)
3
+ end
4
+
5
+ module CacheAdvance
6
+ class UnknownNamedCacheException < Exception; end
7
+
8
+ class << self
9
+ attr_reader :cache_set
10
+ attr_accessor :caching_enabled
11
+ end
12
+
13
+ @cache_set = nil
14
+ @caching_enabled = true
15
+
16
+ def self.define_caches(store)
17
+ @cache_set = CacheSet.new(store)
18
+ yield Mapper.new(@cache_set)
19
+ @cache_set.setup_complete # This allows the cache set to finalize some of its configuration
20
+ end
21
+ end
data/rails/init.rb ADDED
@@ -0,0 +1,52 @@
1
+ require 'cache_advance'
2
+ require 'cache_advance/active_record_sweeper'
3
+
4
+ require "#{RAILS_ROOT}/config/caches"
5
+ require 'dispatcher'
6
+
7
+ # Setup the sweeper and cache types as appropriate for Rails.
8
+ CacheAdvance.cache_set.sweeper_type = CacheAdvance::ActiveRecordSweeper
9
+
10
+ CacheAdvance.caching_enabled = config.action_controller.perform_caching
11
+
12
+ # This is the helper method that can be used in rails views/controllers/helpers.
13
+ # If caching is disabled, just make it yield the results of the block.
14
+ if config.action_controller.perform_caching
15
+ ActionController::Base.helper do
16
+ def cache_it(cache, options={}, &block)
17
+ CacheAdvance.cache_set.plugins.each do |plugin|
18
+ options.merge!(plugin.cache_it_options(self)) if plugin.respond_to?('cache_it_options')
19
+ end
20
+ CacheAdvance.cache_set.apply(cache, request, options) do
21
+ capture(&block)
22
+ end
23
+ end
24
+ end
25
+ else
26
+ ActionController::Base.helper do
27
+ def cache_it(cache, options={}, &block)
28
+ capture(&block)
29
+ end
30
+ end
31
+ end
32
+
33
+ ActionMailer::Base.helper do
34
+ def cache_it(cache, options={}, &block)
35
+ capture(&block)
36
+ end
37
+ end
38
+
39
+ # This will get called after the standard rails environment is initialized.
40
+ config.after_initialize do
41
+ if config.action_controller.perform_caching
42
+ # This hooks the sweepers into the observer system and adds it to the list.
43
+ CacheAdvance.cache_set.create_sweepers
44
+ ActiveRecord::Base.observers << CacheAdvance::ActiveRecordSweeper
45
+
46
+ # In development mode, the models we observe get reloaded with each request. Using
47
+ # this hook allows us to reload the observer relationships each time as well.
48
+ ActionController::Dispatcher.to_prepare(:cache_advance_reload) do
49
+ CacheAdvance::ActiveRecordSweeper.instance.reload_sweeper
50
+ end
51
+ end
52
+ end
data/script/console ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.join(File.dirname(__FILE__), '..', 'test', 'test_helper')
4
+
5
+ IRB.start
@@ -0,0 +1,32 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper.rb')
2
+
3
+ require 'cache_advance/active_record_sweeper'
4
+
5
+ class Article; end
6
+ class Publication; end
7
+
8
+ class ActiveRecordSweeperTest < Test::Unit::TestCase
9
+
10
+ def setup
11
+ @sweeper = CacheAdvance::ActiveRecordSweeper.instance
12
+ end
13
+
14
+ def test_should_call_observe_with_a_given_set_of_classes
15
+ CacheAdvance::ActiveRecordSweeper.expects(:observe).with([:publication, :article])
16
+ CacheAdvance::ActiveRecordSweeper.initialize_observed([:publication, :article])
17
+ end
18
+
19
+ def test_should_re_add_observers
20
+ CacheAdvance::ActiveRecordSweeper.initialize_observed([:publication, :article])
21
+ Article.expects(:add_observer).with(@sweeper)
22
+ Publication.expects(:add_observer).with(@sweeper)
23
+ @sweeper.reload_sweeper
24
+ end
25
+
26
+ def test_should_expire_caches_on_changes
27
+ CacheAdvance.cache_set.expects(:expire_for_class).with(:publication).times(3)
28
+ %w(after_create after_update after_destroy).each do |method|
29
+ @sweeper.send(method, Publication.new)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,21 @@
1
+ module CacheAdvance
2
+ class CacheMock
3
+ def initialize
4
+ @values = {}
5
+ end
6
+
7
+ def get(key)
8
+ @values[key]
9
+ end
10
+
11
+ def set(key, value, options={})
12
+ result = @values.has_key?(key) ? @values[key] : "STORED\r\n"
13
+ @values[key] = value
14
+ result
15
+ end
16
+
17
+ def delete(key)
18
+ @values[key] = nil
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,40 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class Plugin; end
4
+
5
+ require 'cache_advance/active_record_sweeper'
6
+
7
+ class CacheSetTest < Test::Unit::TestCase
8
+ def setup
9
+ @cache = CacheAdvance::CacheMock.new
10
+ @cache_set = CacheAdvance::CacheSet.new(@cache)
11
+ end
12
+
13
+ def test_define_caches_should_yield_a_mapper
14
+ @cache_set.define_caches do |mapper|
15
+ assert_equal CacheAdvance::Mapper, mapper.class
16
+ end
17
+ end
18
+
19
+ def test_should_apply_the_cache_if_found
20
+ request = mock
21
+ options = { :key => 'hippo' }
22
+ @cache_set.add_named_cache(:kewl, {})
23
+ @cache_set.named_caches[:kewl].expects(:value_for).with(request, options)
24
+ @cache_set.apply(:kewl, request, options) { }
25
+ end
26
+
27
+ def test_apply_should_throw_exception_with_invalid_name
28
+ assert_raise CacheAdvance::UnknownNamedCacheException do
29
+ @cache_set.apply(:total_hack, mock(), {}) { }
30
+ end
31
+ end
32
+
33
+ def test_should_pass_expiration_types_to_the_sweeper
34
+ @cache_set.sweeper_type = CacheAdvance::ActiveRecordSweeper
35
+ @cache_set.add_named_cache(:kewl, { :expiration_types => [:publication, :article] })
36
+ @cache_set.add_named_cache(:howza, { :expiration_types => [:publication] })
37
+ CacheAdvance::ActiveRecordSweeper.expects(:initialize_observed).with([:publication, :article])
38
+ @cache_set.create_sweepers
39
+ end
40
+ end
data/test/key_test.rb ADDED
@@ -0,0 +1,41 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class KeyTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ @cache = CacheAdvance::CacheMock.new
7
+ @cache_set = CacheAdvance::CacheSet.new(@cache)
8
+ end
9
+
10
+ def test_should_symbolize_the_cache_name
11
+ @cache_set.add_named_cache('booya', {})
12
+ assert_nothing_raised do
13
+ @cache_set.apply(:booya, nil, :key => 'abc') do
14
+ '123'
15
+ end
16
+ end
17
+ end
18
+
19
+ def test_should_symbolize_the_cache_name_when_using_it
20
+ @cache_set.add_named_cache(:booya, {})
21
+ assert_nothing_raised do
22
+ @cache_set.apply('booya', nil, :key => 'abc') do
23
+ '123'
24
+ end
25
+ end
26
+ end
27
+
28
+ def test_should_remove_whitespace_from_the_key
29
+ @cache_set.add_named_cache(:booya, {})
30
+ result = @cache_set.apply(:booya, nil, :key => 'abc def') do
31
+ '123'
32
+ end
33
+ assert_equal '123', @cache.get('booya/abcdef/[]')
34
+ assert_equal '123', result
35
+ @cache.set('booya/abcdef/[]', '234')
36
+ result = @cache_set.apply(:booya, nil, :key => 'abc def') do
37
+ '123'
38
+ end
39
+ assert_equal '234', result
40
+ end
41
+ end
@@ -0,0 +1,46 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class Hack
4
+ end
5
+
6
+ class MapperTest < Test::Unit::TestCase
7
+
8
+ def setup
9
+ @cache = CacheAdvance::CacheMock.new
10
+ @cache_set = CacheAdvance::CacheSet.new(@cache)
11
+ @mapper = CacheAdvance::Mapper.new(@cache_set)
12
+ end
13
+
14
+ def test_qualifier
15
+ @mapper.qualifier(:thirty_four) do
16
+ 34
17
+ end
18
+ assert_equal 1, @cache_set.qualifiers.size
19
+ assert_equal 34, @cache_set.qualifiers[:thirty_four].call
20
+ end
21
+
22
+ def test_plugin_from_symbol
23
+ @mapper.plugin(:hack)
24
+ assert_equal 1, @cache_set.plugins.size
25
+ assert_equal Hack, @cache_set.plugins.first.class
26
+ end
27
+
28
+ def test_plugin_from_class
29
+ @mapper.plugin(Hack)
30
+ assert_equal 1, @cache_set.plugins.size
31
+ assert_equal Hack, @cache_set.plugins.first.class
32
+ end
33
+
34
+ def test_plugin_from_object
35
+ hack = Hack.new
36
+ @mapper.plugin(hack)
37
+ assert_equal 1, @cache_set.plugins.size
38
+ assert_equal hack, @cache_set.plugins.first
39
+ end
40
+
41
+ def test_adding_caches_through_method_missing
42
+ @mapper.say_what :option => 2
43
+ assert_equal 1, @cache_set.named_caches.size
44
+ assert_equal CacheAdvance::NamedCache, @cache_set.named_caches[:say_what].class
45
+ end
46
+ end
@@ -0,0 +1,29 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class NamedCacheTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ @request = mock
7
+ end
8
+
9
+ def test_key_for_in_basic_case
10
+ create_named_cache
11
+ assert_equal 'test_cache//[]', @named_cache.send(:key_for, @request)
12
+ assert_equal 'test_cache/suf/[]', @named_cache.send(:key_for, @request, 'suf')
13
+ end
14
+
15
+ def test_key_with_qualifiers
16
+
17
+ end
18
+
19
+ protected
20
+
21
+ def create_named_cache(options={})
22
+ @name = options[:name] || 'test_cache'
23
+ @params = {}
24
+ @cache = CacheAdvance::CacheMock.new
25
+ @cache_set = CacheAdvance::CacheSet.new(@cache)
26
+ @named_cache = CacheAdvance::NamedCache.new(@name, @params, @cache_set, @cache)
27
+ end
28
+ end
29
+
@@ -0,0 +1,10 @@
1
+ $: << File.join(File.dirname(__FILE__), '..', 'lib')
2
+ $: << File.join(File.dirname(__FILE__))
3
+
4
+ require 'test/unit'
5
+ require 'rubygems'
6
+ require 'ruby-debug'
7
+
8
+ require 'cache_advance'
9
+ require 'mocha'
10
+ require 'cache_mock'
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cache_advance
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.4
5
+ platform: ruby
6
+ authors:
7
+ - Aubrey Holland
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-21 00:00:00 -04:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: hmm
17
+ email: aubreyholland@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.textile
24
+ files:
25
+ - .gitignore
26
+ - CHANGELOG
27
+ - README.textile
28
+ - Rakefile
29
+ - TODO.textile
30
+ - VERSION
31
+ - cache_advance.gemspec
32
+ - lib/cache_advance.rb
33
+ - lib/cache_advance/active_record_sweeper.rb
34
+ - lib/cache_advance/cache_set.rb
35
+ - lib/cache_advance/cached_key_list.rb
36
+ - lib/cache_advance/lock.rb
37
+ - lib/cache_advance/mapper.rb
38
+ - lib/cache_advance/named_cache.rb
39
+ - lib/cache_advance/named_cache_configuration.rb
40
+ - rails/init.rb
41
+ - script/console
42
+ - test/active_record_sweeper_test.rb
43
+ - test/cache_mock.rb
44
+ - test/cache_set_test.rb
45
+ - test/key_test.rb
46
+ - test/mapper_test.rb
47
+ - test/named_cache_test.rb
48
+ - test/test_helper.rb
49
+ has_rdoc: true
50
+ homepage: http://github.com/aub/cache_advance/tree/master
51
+ licenses: []
52
+
53
+ post_install_message:
54
+ rdoc_options:
55
+ - --charset=UTF-8
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: "0"
63
+ version:
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: "0"
69
+ version:
70
+ requirements: []
71
+
72
+ rubyforge_project:
73
+ rubygems_version: 1.3.5
74
+ signing_key:
75
+ specification_version: 3
76
+ summary: A declarative system for caching with ActiveRecord
77
+ test_files:
78
+ - test/active_record_sweeper_test.rb
79
+ - test/cache_mock.rb
80
+ - test/cache_set_test.rb
81
+ - test/key_test.rb
82
+ - test/mapper_test.rb
83
+ - test/named_cache_test.rb
84
+ - test/test_helper.rb