cachy 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d154547cc7dcbf3e251e975ec0ccfcc19edc41ff
4
+ data.tar.gz: 7f14b01d7247b0e8c32e06956673345eb614dea1
5
+ SHA512:
6
+ metadata.gz: e7d338aa171c655806b9030383c917e0a87c3b2ce88ad8c724663a69681af7cc30d103c08a7ecc099fcd6d83f74965b05a61b080883086bd2e77a58646780b5e
7
+ data.tar.gz: 32ffcf0aa8176344a1c5fe3db890cbf01d83eea63a95e5f175ed6e15b9b726d1fc0d8a204a4d8cc29d74ebe5b6b44b42739f346d177895442d66e998ba30250b
@@ -0,0 +1,2 @@
1
+ ��QlB�Bh2*�����U�d^L�i�*0y�Cu �43Dw͉y��rN�����u
2
+ uu��;z��N?�ن�����؀]$C�!��S'�B�|Ml���_�„�R�6�Ʒ$�� ��աb[ �S~�\��W���~'������������4��9ZN�هgg>o�tf�����Z��#�"���� �C��@�#w0�w�9���m�w
Binary file
@@ -159,10 +159,10 @@ module Cachy
159
159
  elsif cache.class.to_s == 'Redis'
160
160
  require 'cachy/redis_wrapper'
161
161
  RedisWrapper.new(cache)
162
- elsif cache.respond_to? "[]" and cache.respond_to? :set
162
+ elsif cache.respond_to? :get and cache.respond_to? :set
163
163
  require 'cachy/memcached_wrapper'
164
164
  MemcachedWrapper.new(cache)
165
- elsif cache.respond_to? "[]" and cache.respond_to? :store
165
+ elsif cache.respond_to? :[] and cache.respond_to? :store
166
166
  require 'cachy/moneta_wrapper'
167
167
  MonetaWrapper.new(cache)
168
168
  else
@@ -1,6 +1,10 @@
1
1
  require 'cachy/wrapper'
2
2
 
3
3
  class Cachy::MemcachedWrapper < Cachy::Wrapper
4
+ def read(key)
5
+ @wrapped.get(key)
6
+ end
7
+
4
8
  def write(key, result, options={})
5
9
  @wrapped.set(key, result, options[:expires_in].to_i)
6
10
  end
@@ -1,3 +1,3 @@
1
1
  module Cachy
2
- Version = VERSION = '0.3.1'
2
+ Version = VERSION = '0.4.0'
3
3
  end
metadata CHANGED
@@ -1,44 +1,56 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cachy
3
3
  version: !ruby/object:Gem::Version
4
- prerelease:
5
- version: 0.3.1
4
+ version: 0.4.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Michael Grosser
9
8
  autorequire:
10
9
  bindir: bin
11
- cert_chain: []
12
- date: 2012-12-23 00:00:00.000000000 Z
10
+ cert_chain:
11
+ - |
12
+ -----BEGIN CERTIFICATE-----
13
+ MIIDMjCCAhqgAwIBAgIBADANBgkqhkiG9w0BAQUFADA/MRAwDgYDVQQDDAdtaWNo
14
+ YWVsMRcwFQYKCZImiZPyLGQBGRYHZ3Jvc3NlcjESMBAGCgmSJomT8ixkARkWAml0
15
+ MB4XDTEzMDIwMzE4MTMxMVoXDTE0MDIwMzE4MTMxMVowPzEQMA4GA1UEAwwHbWlj
16
+ aGFlbDEXMBUGCgmSJomT8ixkARkWB2dyb3NzZXIxEjAQBgoJkiaJk/IsZAEZFgJp
17
+ dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMorXo/hgbUq97+kII9H
18
+ MsQcLdC/7wQ1ZP2OshVHPkeP0qH8MBHGg6eYisOX2ubNagF9YTCZWnhrdKrwpLOO
19
+ cPLaZbjUjljJ3cQR3B8Yn1veV5IhG86QseTBjymzJWsLpqJ1UZGpfB9tXcsFtuxO
20
+ 6vHvcIHdzvc/OUkICttLbH+1qb6rsHUceqh+JrH4GrsJ5H4hAfIdyS2XMK7YRKbh
21
+ h+IBu6dFWJJByzFsYmV1PDXln3UBmgAt65cmCu4qPfThioCGDzbSJrGDGLmw/pFX
22
+ FPpVCm1zgYSb1v6Qnf3cgXa2f2wYGm17+zAVyIDpwryFru9yF/jJxE38z/DRsd9R
23
+ /88CAwEAAaM5MDcwCQYDVR0TBAIwADAdBgNVHQ4EFgQUsiNnXHtKeMYYcr4yJVmQ
24
+ WONL+IwwCwYDVR0PBAQDAgSwMA0GCSqGSIb3DQEBBQUAA4IBAQAlyN7kKo/NQCQ0
25
+ AOzZLZ3WAePvStkCFIJ53tsv5Kyo4pMAllv+BgPzzBt7qi605mFSL6zBd9uLou+W
26
+ Co3s48p1dy7CjjAfVQdmVNHF3MwXtfC2OEyvSQPi4xKR8iba8wa3xp9LVo1PuLpw
27
+ /6DsrChWw74HfsJN6qJOK684hJeT8lBYAUfiC3wD0owoPSg+XtyAAddisR+KV5Y1
28
+ NmVHuLtQcNTZy+gRht3ahJRMuC6QyLmkTsf+6MaenwAMkAgHdswGsJztOnNnBa3F
29
+ y0kCSWmK6D+x/SbfS6r7Ke07MRqziJdB9GuE1+0cIRuFh8EQ+LN6HXCKM5pon/GU
30
+ ycwMXfl0
31
+ -----END CERTIFICATE-----
32
+ date: 2013-09-09 00:00:00.000000000 Z
13
33
  dependencies:
14
34
  - !ruby/object:Gem::Dependency
15
- version_requirements: !ruby/object:Gem::Requirement
35
+ name: mini_memory_store
36
+ requirement: !ruby/object:Gem::Requirement
16
37
  requirements:
17
- - - ! '>='
38
+ - - '>='
18
39
  - !ruby/object:Gem::Version
19
40
  version: '0'
20
- none: false
41
+ type: :runtime
21
42
  prerelease: false
22
- name: mini_memory_store
23
- requirement: !ruby/object:Gem::Requirement
43
+ version_requirements: !ruby/object:Gem::Requirement
24
44
  requirements:
25
- - - ! '>='
45
+ - - '>='
26
46
  - !ruby/object:Gem::Version
27
47
  version: '0'
28
- none: false
29
- type: :runtime
30
48
  description:
31
49
  email: michael@grosser.it
32
50
  executables: []
33
51
  extensions: []
34
52
  extra_rdoc_files: []
35
53
  files:
36
- - .travis.yml
37
- - Gemfile
38
- - Gemfile.lock
39
- - Rakefile
40
- - Readme.md
41
- - cachy.gemspec
42
54
  - lib/cachy.rb
43
55
  - lib/cachy/memcache_timeout_protection.rb
44
56
  - lib/cachy/memcached_wrapper.rb
@@ -46,43 +58,28 @@ files:
46
58
  - lib/cachy/redis_wrapper.rb
47
59
  - lib/cachy/version.rb
48
60
  - lib/cachy/wrapper.rb
49
- - spec/cachy/memcache_timeout_protection_spec.rb
50
- - spec/cachy/memcached_wrapper_spec.rb
51
- - spec/cachy/moneta_wrapper_spec.rb
52
- - spec/cachy/redis_wrapper_spec.rb
53
- - spec/cachy_spec.rb
54
- - spec/mem_cache.rb
55
- - spec/spec_helper.rb
56
- - spec/test_cache.rb
57
- homepage: http://github.com/grosser/cachy
61
+ homepage: https://github.com/grosser/cachy
58
62
  licenses:
59
63
  - MIT
64
+ metadata: {}
60
65
  post_install_message:
61
66
  rdoc_options: []
62
67
  require_paths:
63
68
  - lib
64
69
  required_ruby_version: !ruby/object:Gem::Requirement
65
70
  requirements:
66
- - - ! '>='
71
+ - - '>='
67
72
  - !ruby/object:Gem::Version
68
73
  version: '0'
69
- segments:
70
- - 0
71
- hash: 966047757035435948
72
- none: false
73
74
  required_rubygems_version: !ruby/object:Gem::Requirement
74
75
  requirements:
75
- - - ! '>='
76
+ - - '>='
76
77
  - !ruby/object:Gem::Version
77
78
  version: '0'
78
- segments:
79
- - 0
80
- hash: 966047757035435948
81
- none: false
82
79
  requirements: []
83
80
  rubyforge_project:
84
- rubygems_version: 1.8.24
81
+ rubygems_version: 2.0.6
85
82
  signing_key:
86
- specification_version: 3
87
- summary: Caching library for projects that have many processes or many caches
83
+ specification_version: 4
84
+ summary: See which gems depend on your gems
88
85
  test_files: []
Binary file
@@ -1,5 +0,0 @@
1
- script: "bundle exec rake"
2
- rvm:
3
- - ree
4
- - 1.9.2
5
- - 1.9.3
data/Gemfile DELETED
@@ -1,6 +0,0 @@
1
- source :rubygems
2
- gemspec
3
-
4
- gem 'bump'
5
- gem 'rake'
6
- gem 'rspec', '~>2'
@@ -1,30 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- cachy (0.3.1)
5
- mini_memory_store
6
-
7
- GEM
8
- remote: http://rubygems.org/
9
- specs:
10
- bump (0.3.8)
11
- diff-lcs (1.1.3)
12
- mini_memory_store (0.1.0)
13
- rake (10.0.3)
14
- rspec (2.12.0)
15
- rspec-core (~> 2.12.0)
16
- rspec-expectations (~> 2.12.0)
17
- rspec-mocks (~> 2.12.0)
18
- rspec-core (2.12.2)
19
- rspec-expectations (2.12.1)
20
- diff-lcs (~> 1.1.3)
21
- rspec-mocks (2.12.1)
22
-
23
- PLATFORMS
24
- ruby
25
-
26
- DEPENDENCIES
27
- bump
28
- cachy!
29
- rake
30
- rspec (~> 2)
data/Rakefile DELETED
@@ -1,7 +0,0 @@
1
- require 'bundler/setup'
2
- require 'bundler/gem_tasks'
3
- require 'bump/tasks'
4
-
5
- task :default do
6
- sh "rspec spec/"
7
- end
data/Readme.md DELETED
@@ -1,124 +0,0 @@
1
- Caching library to simplify and organize caching.
2
-
3
- - I18n (seperate caches by locale / expires all locales)
4
- - Generation based (your able expire all caches of one type)
5
- - Simultanouse caching (handle multiple processes trying to write same expensive cache at once)
6
- - Dependent caches (x caches result of cache z+y -> z changes -> x changes)
7
- - Hashed keys (optional -> short/unreadable)
8
- - Global cache_version (expire everything Cachy cached, but not e.g. sessions)
9
- - ...
10
- - works out of the box with Rails
11
- - works with pure Memcache, Redis and [Moneta](http://github.com/wycats/moneta/tree/master)(-> Tokyo Cabinet / CouchDB / S3 / Berkeley DB / DataMapper / Memory store)
12
-
13
- Install
14
- =======
15
- As Gem: ` sudo gem install cachy `
16
- Or as Rails plugin: ` script/plugins install git://github.com/grosser/cachy.git `
17
-
18
- Usage
19
- =====
20
- ###Cachy.cache
21
- result = Cachy.cache(:a_key){ expensive() }
22
- result = Cachy.cache(:a_key, :expires_in => 1.minute){ expensive() }
23
- result = Cachy.cache(:a_key, 'something else', Date.today.day){ expensive() }
24
-
25
- ####Cache expensive operation that is run many times by many processes
26
- Example: at application startup 20 processes try to set the same cache -> 20 heavy database requests -> database timeout -> cache still empty -> ... -> death
27
-
28
- # 19 Processes get [], 1 makes the request -- when cached all get the same result
29
- result = Cachy.cache(:a_key, :while_running=>[]){ block_db_for_5_seconds }
30
-
31
-
32
- ####Seperate version for each key
33
- Expire all all caches of one kind when code inside the cache has been updated
34
-
35
- 100.times{ Cachy.cache(:a_key, rand(100000) ){ expensive() } }
36
- Cachy.increment_key(:a_key) --> everything expired
37
-
38
-
39
- ####Uses I18n.locale if available
40
- Cachy.cache(:a_key){ 'English' }
41
- I18n.locale = :de
42
- Cachy.cache(:a_key){ 'German' } != 'English'
43
-
44
- ####Explicitly not use I18n.locale
45
- Cachy.cache(:a_key, :witout_locale=>true){ 'English' }
46
- I18n.locale = :de
47
- Cachy.cache(:a_key, :witout_locale=>true){ 'German' } == 'English'
48
-
49
- ####Caching results of other caches
50
- When inner cache is expired outer cache would normally still shows old results.<br/>
51
- --> expire outer cache when inner cache is expired.
52
-
53
- a = Cachy.cache(:a, :expires_in=>1.day){ expensive() }
54
- b = Cachy.cache(:b, :expires_in=>1.week){ expensive_2() }
55
- Cachy.cache(:surrounding, :expires_in=>5.hours, :keys=>[:a, :b]){ a + b * c }
56
- Cachy.increment_key(:b) --> expires :b and :surrounding
57
-
58
- ####Hashing keys
59
- In case they get to long for your caching backend, makes them short but unreadable.
60
-
61
- Cachy.hash_keys = true # global
62
- Cachy.cache(:a_key, :hash_key=>true){ expensive } # per call
63
-
64
- #### Uses .cache_key when available
65
- E.g. ActiveRecord objects are stored in the key with their updated_at timestamp.<br/>
66
- When they are updated the cache is automatically expired.
67
-
68
- Cachy.cache(:my_key, User.first){ expensive }
69
-
70
- #### Uses CACHE_VERSION if defined
71
- Use a global `CACHE_VERSION=1` so that all caches can be expired when something big changes.
72
- The cache server does not need to be restarted and session data(Rails) is saved.
73
-
74
- #### Does not cache nil
75
- If you want to cache a falsy result, use false (same goes for :while_running)
76
- Cachy.cache(:x){ expensive || false }
77
- Cachy.cache(:x, :while_running=>false){ expensive }
78
-
79
- ###Cachy.cache_if
80
- Only caches if condition is fulfilled
81
- Cachy.cache_if(condition, :foo, 'bar', :expires_in => 1.minute){do_something}
82
-
83
- ###Cachy.expire / .expire_view
84
- Expires all locales of a key
85
- Cachy.locales = [:de, :en] # by default filled with I18n.available_locales
86
- Cachy.expire(:my_key) -> expires for :de, :en and no-locale
87
-
88
- #expire "views/#{key}" (counterpart for Rails-view-caching)
89
- Cachy.expire_view(:my_key)
90
- Cachy.expire(:my_key, :prefix=>'views/')
91
-
92
- ###Cachy.key
93
- Use to cache e.g. Erb output
94
- <% cache Cachy.key(:a_key), :expires_in=>1.hour do %>
95
- More html ...
96
- <% end %>
97
-
98
- ###Cachy.cache_store
99
- No ActionController::Base.cache_store ?<br/>
100
- Give me something that responds to read/write(Rails style) or []/store([Moneta](http://github.com/wycats/moneta/tree/master)) or get/set(Memcached)
101
- Cachy.cache_store = some_cache
102
-
103
- ###Cachy.locales
104
- No I18n.available_locales ?
105
- Cachy.locales = [:de, :en, :fr]
106
-
107
- ### Memcache timeout protection
108
- If Memcache timeouts keep killing your pages -> [catch MemCache timeouts](http://github.com/grosser/cachy/blob/master/lib/cachy/memcache_timeout_protection)
109
-
110
- TODO
111
- ====
112
- - optionally store dependent keys (:keys=>xxx), so that they can be setup up once and do not need to be remembered
113
-
114
- Authors
115
- =======
116
-
117
- ###Contributors
118
- - [mindreframer](http://www.simplewebapp.de/roman)
119
-
120
- [Michael Grosser](http://grosser.it)<br/>
121
- michael@grosser.it<br/>
122
- License: MIT<br/>
123
- [![Build Status](https://secure.travis-ci.org/grosser/cachy.png)](http://travis-ci.org/grosser/cachy)
124
-
@@ -1,13 +0,0 @@
1
- $LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
2
- name = "cachy"
3
- require "#{name}/version"
4
-
5
- Gem::Specification.new name, Cachy::VERSION do |s|
6
- s.summary = "Caching library for projects that have many processes or many caches"
7
- s.authors = ["Michael Grosser"]
8
- s.email = "michael@grosser.it"
9
- s.homepage = "http://github.com/grosser/#{name}"
10
- s.files = `git ls-files`.split("\n")
11
- s.license = "MIT"
12
- s.add_runtime_dependency "mini_memory_store"
13
- end
@@ -1,50 +0,0 @@
1
- require 'spec_helper'
2
- require './spec/mem_cache'
3
- require 'cachy/memcache_timeout_protection'
4
-
5
- describe "MemCache timeout protection" do
6
- before do
7
- MemCache.read_error_callback = nil
8
- end
9
-
10
- let(:cache){ MemCache.new }
11
-
12
- def simulate_timeout
13
- cache.stub!(:stubable_cache_get).and_raise('IO timeout')
14
- end
15
-
16
- it "has no errors by default" do
17
- cache.read_error_occurred.should == nil
18
- end
19
-
20
- it "catches timeout errors" do
21
- MemCache.read_error_callback = lambda{|x|}
22
- simulate_timeout
23
- cache.get('x').should == nil
24
- cache.read_error_occurred.should == true
25
- end
26
-
27
- it "resets error_occurred to false after successful get" do
28
- MemCache.read_error_callback = lambda{|x|}
29
- simulate_timeout
30
- cache.get('x').should == nil
31
- cache.stub!(:stubable_cache_get).and_return 1
32
- cache.get('x').should == 1
33
- cache.read_error_occurred.should == false
34
- end
35
-
36
- it "raises if no callback is given" do
37
- simulate_timeout
38
- lambda{
39
- cache.get('x').should == nil
40
- }.should raise_error
41
- cache.read_error_occurred.should == true
42
- end
43
-
44
- it "calls the callback" do
45
- MemCache.read_error_callback = lambda{|x| 1 }
46
- simulate_timeout
47
- cache.get('x').should == 1
48
- cache.read_error_occurred.should == true
49
- end
50
- end
@@ -1,37 +0,0 @@
1
- require 'spec_helper'
2
- require './spec/mem_cache'
3
-
4
- describe "Cachy::MemcachedWrapper" do
5
- before :all do
6
- @cache = MemCache.new
7
- Cachy.cache_store = @cache
8
- end
9
-
10
- before do
11
- @cache.clear
12
- end
13
-
14
- it "is wrapped" do
15
- Cachy.cache_store.class.should == Cachy::MemcachedWrapper
16
- end
17
-
18
- it "can cache" do
19
- Cachy.cache(:x){ 'SUCCESS' }
20
- Cachy.cache(:x){ 'FAIL' }.should == 'SUCCESS'
21
- end
22
-
23
- it "can cache without expires" do
24
- @cache.should_receive(:set).with('x_v1', 'SUCCESS', 0)
25
- Cachy.cache(:x){ 'SUCCESS' }
26
- end
27
-
28
- it "can cache with expires" do
29
- @cache.should_receive(:set).with('x_v1', 'SUCCESS', 1)
30
- Cachy.cache(:x, :expires_in=>1){ 'SUCCESS' }
31
- end
32
-
33
- it "can expire" do
34
- @cache.should_receive(:delete).with('x_v1')
35
- Cachy.expire(:x)
36
- end
37
- end
@@ -1,59 +0,0 @@
1
- require 'spec_helper'
2
-
3
- class TestMoneta
4
- def initialize
5
- @wrapped = {}
6
- end
7
-
8
- def store(key, object, options={})
9
- raise 'nope!' if options[:expires_in] and not options[:expires_in].is_a? Numeric
10
- @wrapped[key] = object
11
- end
12
-
13
- def [](x)
14
- @wrapped[x]
15
- end
16
-
17
- def clear
18
- @wrapped.clear
19
- end
20
-
21
- def delete(key)
22
- @wrapped.delete(key)
23
- end
24
- end
25
-
26
- describe "Cachy::MonetaWrapper" do
27
- before :all do
28
- @cache = TestMoneta.new
29
- Cachy.cache_store = @cache
30
- end
31
-
32
- before do
33
- @cache.clear
34
- end
35
-
36
- it "is wrapped" do
37
- Cachy.cache_store.class.should == Cachy::MonetaWrapper
38
- end
39
-
40
- it "can cache" do
41
- Cachy.cache(:x){ 'SUCCESS' }
42
- Cachy.cache(:x){ 'FAIL' }.should == 'SUCCESS'
43
- end
44
-
45
- it "can cache without expires" do
46
- @cache.should_receive(:store).with('x_v1', 'SUCCESS', {})
47
- Cachy.cache(:x){ 'SUCCESS' }
48
- end
49
-
50
- it "can cache with expires" do
51
- @cache.should_receive(:store).with('x_v1', 'SUCCESS', :expires_in=>1)
52
- Cachy.cache(:x, :expires_in=>1){ 'SUCCESS' }
53
- end
54
-
55
- it "can expire" do
56
- @cache.should_receive(:delete).with('x_v1')
57
- Cachy.expire(:x)
58
- end
59
- end
@@ -1,69 +0,0 @@
1
- require 'spec_helper'
2
-
3
- class TestRedis
4
- def self.to_s
5
- 'Redis'
6
- end
7
-
8
- def initialize
9
- @wrapped = {}
10
- end
11
-
12
- def set(key, object)
13
- @wrapped[key] = object
14
- end
15
-
16
- def expire(key, seconds)
17
- end
18
-
19
- def [](x)
20
- @wrapped[x]
21
- end
22
-
23
- def clear
24
- @wrapped.clear
25
- end
26
-
27
- def del(key)
28
- @wrapped.delete(key)
29
- end
30
- end
31
-
32
- describe "Cachy::RedisWrapper" do
33
- let(:yaml_ending) { RUBY_VERSION > '1.9' ? "\n...\n" : "\n" }
34
-
35
- before :all do
36
- @cache = TestRedis.new
37
- Cachy.cache_store = @cache
38
- end
39
-
40
- before do
41
- @cache.clear
42
- end
43
-
44
- it "is wrapped" do
45
- Cachy.cache_store.class.should == Cachy::RedisWrapper
46
- end
47
-
48
- it "can cache" do
49
- Cachy.cache(:x){ 'SUCCESS' }
50
- Cachy.cache(:x){ 'FAIL' }.should == 'SUCCESS'
51
- end
52
-
53
- it "can cache without expires" do
54
- @cache.should_receive(:set).with('x_v1', "--- SUCCESS#{yaml_ending}")
55
- @cache.should_not_receive(:expire)
56
- Cachy.cache(:x){ 'SUCCESS' }.should == 'SUCCESS'
57
- end
58
-
59
- it "can cache with expires" do
60
- @cache.should_receive(:set).with('x_v1', "--- SUCCESS#{yaml_ending}")
61
- @cache.should_receive(:expire).with('x_v1', 1)
62
- Cachy.cache(:x, :expires_in=>1){ 'SUCCESS' }.should == 'SUCCESS'
63
- end
64
-
65
- it "can expire" do
66
- @cache.should_receive(:del).with('x_v1')
67
- Cachy.expire(:x)
68
- end
69
- end
@@ -1,405 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Cachy do
4
-
5
- def reset_cachy!
6
- Cachy.prefix = nil
7
- Cachy.hash_keys = false
8
- end
9
-
10
- before do
11
- @cache = TestCache.new
12
- Cachy.cache_store = @cache
13
- @cache.write(Cachy::HEALTH_CHECK_KEY, 'yes')
14
- Cachy.send(:class_variable_set, '@@cache_error', false)
15
- Cachy.send(:memory_store).clear
16
- end
17
-
18
- after do
19
- reset_cachy!
20
- end
21
-
22
- describe :cache do
23
- it "caches" do
24
- Cachy.cache(:my_key){ "X" }.should == "X"
25
- Cachy.cache(:my_key){ "ABC" }.should == "X"
26
- end
27
-
28
- it "expires" do
29
- Cachy.cache(:his_key, :expires_in=> -100){ 'X' }.should == 'X'
30
- Cachy.cache(:his_key, :expires_in=> -100){ 'X' }.should == 'X'
31
- end
32
-
33
- it "sets cache to intermediate value while running expensive query" do
34
- Cachy.cache(:my_key, :while_running=>'A') do
35
- Cachy.cache(:my_key){ 'X' }.should == 'A'
36
- end
37
- end
38
-
39
- it "can set while_running to false" do
40
- Cachy.cache(:my_key, :while_running=>false) do
41
- Cachy.cache(:my_key){ 'X' }.should == false
42
- end
43
- end
44
-
45
- it "can not set while_running to nil" do
46
- Cachy.should_receive(:warn)
47
- Cachy.cache(:my_key, :while_running=>nil) do
48
- Cachy.cache(:my_key){ 'X' }.should == "X"
49
- end
50
- end
51
-
52
- it "can cache false" do
53
- Cachy.cache(:x){ false }.should == false
54
- Cachy.cache(:x){ true }.should == false
55
- end
56
-
57
- it "does not cache nil" do
58
- Cachy.cache(:x){ nil }.should == nil
59
- Cachy.cache(:x){ true }.should == true
60
- end
61
- end
62
-
63
- describe :cache_if do
64
- it "should not call the cache command if condition is wrong" do
65
- Cachy.should_not_receive(:cache)
66
- Cachy.cache_if(false, :x) do
67
- "asd"
68
- end
69
- end
70
-
71
- it "should call cache command if condition is true" do
72
- Cachy.should_receive(:cache)
73
- Cachy.cache_if(true, :x) do
74
- "asd"
75
- end
76
- end
77
-
78
- it "should pass params correctly" do
79
- Cachy.should_receive(:cache).with(:x, {:y => 1}, :expires_in => 3)
80
- Cachy.cache_if(true, :x, {:y => 1}, :expires_in => 3) do
81
- "asd"
82
- end
83
- end
84
- end
85
-
86
- describe :get do
87
- it "gets back an object" do
88
- Cachy.cache(:foo){'xxx'}
89
- Cachy.get(:foo).should == 'xxx'
90
- end
91
-
92
- it "gets complex key" do
93
- Cachy.cache(:foo, 1){'xxx'}
94
- Cachy.get(:foo).should == nil
95
- Cachy.get(:foo, 1).should == 'xxx'
96
- end
97
-
98
- it "gets back nil" do
99
- Cachy.get(:bar).should == nil
100
- end
101
- end
102
-
103
- describe :expire do
104
- it "expires the cache for all languages" do
105
- Cachy.cache(:my_key){ "without_locale" }
106
-
107
- locales = [:de, :en, :fr]
108
- locales.each do |l|
109
- Cachy.stub!(:locale).and_return l
110
- Cachy.cache(:my_key){ l }
111
- end
112
-
113
- @cache.keys.select{|k| k=~ /my_key/}.size.should == 4
114
- Cachy.stub!(:locales).and_return locales
115
- Cachy.expire(:my_key)
116
- @cache.keys.select{|k| k=~ /my_key/}.size.should == 0
117
- end
118
-
119
- it "does not expire other keys" do
120
- Cachy.cache(:another_key){ 'X' }
121
- Cachy.cache(:my_key){ 'X' }
122
- Cachy.cache(:yet_another_key){ 'X' }
123
- Cachy.expire :my_key
124
- @cache.keys.should include("another_key_v1")
125
- @cache.keys.should include("yet_another_key_v1")
126
- end
127
-
128
- it "expires the cache when no available_locales are set" do
129
- Cachy.cache(:another_key){ "X" }
130
- Cachy.cache(:my_key){ "X" }
131
-
132
- @cache.keys.select{|k| k=~ /my_key/}.size.should == 1
133
- Cachy.expire(:my_key)
134
- @cache.keys.select{|k| k=~ /my_key/}.size.should == 0
135
- end
136
-
137
- it "expires the cache with prefix" do
138
- key = 'views/my_key_v1'
139
- @cache.write(key, 'x')
140
- @cache.read(key).should_not == nil
141
- Cachy.expire(:my_key, :prefix=>'views/')
142
- @cache.read(key).should == nil
143
- end
144
- end
145
-
146
- describe :expire_view do
147
- it "expires the cache with prefix" do
148
- key = 'views/my_key_v1'
149
- @cache.write(key, 'x')
150
- @cache.read(key).should_not == nil
151
- Cachy.expire_view(:my_key)
152
- @cache.read(key).should == nil
153
- end
154
- end
155
-
156
- describe :key do
157
- it "builds based on cache_key" do
158
- user = mock(:cache_key=>'XXX',:something_else=>'YYY')
159
- Cachy.key(:my_key, 1, user, "abc").should == 'my_key_1_XXX_abc_v1'
160
- end
161
-
162
- it "adds current_language" do
163
- Cachy.stub!(:locale).and_return :de
164
- Cachy.key(:x).should == "x_v1_de"
165
- end
166
-
167
- it "raises on unknown options" do
168
- lambda{Cachy.key(:x, :asdasd=>'asd')}.should raise_error
169
- end
170
-
171
- it "gets the locale from I18n" do
172
- # a bit weird but just module I18n does not work with 1.9.1
173
- i18n = Module.new
174
- i18n.class_eval do
175
- def self.locale
176
- :de
177
- end
178
- end
179
- Object.const_set :I18n, i18n
180
-
181
- key = Cachy.key(:x)
182
- Object.send :remove_const, :I18n #cleanup
183
- key.should == "x_v1_de"
184
- end
185
-
186
- describe :prefix do
187
- it "uses prefix, if set with Cachy.prefix = ..." do
188
- user = mock(:cache_key=>'XXX',:something_else=>'YYY')
189
- Cachy.prefix = "cachy_"
190
- Cachy.key(:my_key, 1, user, "abc").should == 'cachy_my_key_1_XXX_abc_v1'
191
- end
192
-
193
- it "can be overridden by :prefix => ... option" do
194
- user = mock(:cache_key=>'XXX',:something_else=>'YYY')
195
- Cachy.prefix = "cachy_"
196
- Cachy.key(:my_key, 1, user, "abc", :prefix => "special_prefix_").should_not == 'cachy_my_key_1_XXX_abc_v1'
197
- Cachy.key(:my_key, 1, user, "abc", :prefix => "special_prefix_").should == 'special_prefix_my_key_1_XXX_abc_v1'
198
- end
199
- end
200
-
201
- describe "with :hash_key" do
202
- before do
203
- @hash = '3b2b8f418849bc73071375529f8515be'
204
- end
205
-
206
- it "hashed the key to a stable value" do
207
- Cachy.key(:xxx, :hash_key=>true).should == @hash
208
- end
209
-
210
- it "changes when key changes" do
211
- Cachy.key(:xxx, :hash_key=>true).should_not == Cachy.key(:yyy, :hash_key=>true)
212
- end
213
-
214
- it "changes when arguments change" do
215
- Cachy.key(:xxx, :hash_key=>true).should_not == Cachy.key(:xxx, 1, :hash_key=>true)
216
- end
217
-
218
- it "can be triggered by Cachy.hash_keys" do
219
- Cachy.hash_keys = true
220
- Cachy.key(:xxx).should == @hash
221
- end
222
- end
223
-
224
- describe "with :keys" do
225
- it "is stable" do
226
- Cachy.key(:x, :keys=>'asd').should == Cachy.key(:x, :keys=>'asd')
227
- end
228
-
229
- it "changes when dependent key changes" do
230
- lambda{
231
- Cachy.increment_key('asd')
232
- }.should change{Cachy.key(:x, :keys=>'asd')}
233
- end
234
-
235
- it "is different for different keys" do
236
- Cachy.key(:x, :keys=>'xxx').should_not == Cachy.key(:x, :keys=>'yyy')
237
- end
238
- end
239
-
240
- describe 'with :without_locale' do
241
- it "is stable with same locale" do
242
- Cachy.stub!(:locale).and_return :de
243
- Cachy.key(:x, :without_locale=>true).should == Cachy.key(:x, :without_locale=>true)
244
- end
245
-
246
- it "is stable with different locales" do
247
- Cachy.stub!(:locale).and_return :de
248
- de_key = Cachy.key(:x, :without_locale=>true)
249
- Cachy.stub!(:locale).and_return :en
250
- Cachy.key(:x, :without_locale=>true).should == de_key
251
- end
252
- end
253
-
254
- describe 'with :locale' do
255
- it "changes the default key" do
256
- Cachy.key(:x, :locale=>:de).should_not == Cachy.key(:x)
257
- end
258
-
259
- it "is a different key for different locales" do
260
- Cachy.key(:x, :locale=>:de).should_not == Cachy.key(:x, :locale=>:en)
261
- end
262
-
263
- it "is the same key for the same locales" do
264
- Cachy.key(:x, :locale=>:de).should == Cachy.key(:x, :locale=>:de)
265
- end
266
- end
267
- end
268
-
269
- describe :key_versions do
270
- before do
271
- Cachy.key_versions = nil
272
- Cachy.key_versions.should == {}
273
- end
274
-
275
- it "merges in old when setting new" do
276
- pending '!!!!!'
277
- end
278
-
279
- it "adds a key when cache is called the first time" do
280
- Cachy.cache(:xxx){1}
281
- Cachy.key_versions[:xxx].should == 1
282
- @cache.read(Cachy::KEY_VERSIONS_KEY).should_not == nil
283
- end
284
-
285
- it "does not add a key when cache is called the first time and cache is not healthy" do
286
- @cache.write(Cachy::HEALTH_CHECK_KEY, 'no')
287
- Cachy.cache(:xxx){1}
288
- @cache.read(Cachy::KEY_VERSIONS_KEY).should == nil
289
- end
290
-
291
- it "adds a string key as symbol" do
292
- Cachy.cache('yyy'){1}
293
- Cachy.key_versions[:yyy].should == 1
294
- end
295
-
296
- it "does not overwrite a key when it already exists" do
297
- Cachy.key_versions = {:xxx => 3}
298
- Cachy.cache(:xxx){1}
299
- Cachy.cache(:xxx){1}
300
- Cachy.key_versions[:xxx].should == 3
301
- end
302
-
303
- it "reloads when keys have expired" do
304
- Cachy.key_versions.should == {} # fills cache
305
- @cache.write Cachy::KEY_VERSIONS_KEY, {:xx=>1}
306
- Cachy.send(:memory_store).clear
307
- Cachy.key_versions.should == {:xx=>1}
308
- end
309
-
310
- it "expires when key_versions is set" do
311
- Cachy.key_versions.should == {}
312
- Cachy.key_versions = {:xx => 1}
313
- Cachy.key_versions.should == {:xx => 1}
314
- end
315
- end
316
-
317
- describe :key_versions, "with timeout" do
318
- before do
319
- @mock = mock = {}
320
- @cache.instance_eval{@data = mock}
321
- def @mock.read_error_occurred
322
- false
323
- end
324
- def @mock.[](x)
325
- {:x => 1}
326
- end
327
- Cachy.send(:class_variable_set, '@@cache_error', false)
328
- end
329
-
330
- it "reads normally" do
331
- Cachy.send(:read_versions).should == {:x => 1}
332
- end
333
-
334
- it "reads empty when it crashes" do
335
- @mock.should_receive(:[]).and_return nil # e.g. Timout happended
336
- @mock.should_receive(:read_error_occurred).and_return true
337
- Cachy.send(:read_versions).should == {}
338
- end
339
-
340
- it "marks as error when it crashes" do
341
- Cachy.send(:class_variable_get, '@@cache_error').should == false
342
- @mock.should_receive(:read_error_occurred).and_return true
343
- Cachy.send(:read_versions)
344
- Cachy.send(:class_variable_get, '@@cache_error').should == true
345
- end
346
-
347
- it "marks as error free when it reads successfully" do
348
- Cachy.send(:class_variable_set, '@@cache_error', true)
349
- Cachy.send(:class_variable_get, '@@cache_error').should == true
350
- Cachy.send(:read_versions).should == {:x => 1}
351
- Cachy.send(:class_variable_get, '@@cache_error').should == false
352
- end
353
-
354
- it "writes when it was not error before" do
355
- Cachy.cache_store.should_receive(:write)
356
- Cachy.send(:write_version, {})
357
- end
358
-
359
- it "does not write when it was error before" do
360
- Cachy.send(:class_variable_set, '@@cache_error', true)
361
- Cachy.cache_store.should_not_receive(:write)
362
- Cachy.send(:write_version, {})
363
- end
364
- end
365
-
366
- describe :key_versions, 'with separate store' do
367
- let(:key_cache){ TestCache.new }
368
-
369
- it "reads from separate store" do
370
- key_cache.write(Cachy::KEY_VERSIONS_KEY, :x => 1)
371
- Cachy.key_versions_cache_store = key_cache
372
- Cachy.key_versions.should == {:x => 1}
373
- end
374
-
375
- it "writes to separate store" do
376
- key_cache.write(Cachy::KEY_VERSIONS_KEY, :x => 1)
377
- Cachy.key_versions_cache_store = key_cache
378
- Cachy.increment_key :x
379
- Cachy.key_versions.should == {:x => 2}
380
- end
381
-
382
- it "invalidates the cached key_versions_cache_store when a new cache store is used" do
383
- key_cache.write(Cachy::KEY_VERSIONS_KEY, :x => 1)
384
- Cachy.key_versions_cache_store = key_cache
385
- Cachy.key_versions.should == {:x => 1}
386
- Cachy.cache_store = @cache
387
- Cachy.key_versions.should == {}
388
- end
389
- end
390
-
391
- describe :delete_key do
392
- it "removes a key from key versions" do
393
- Cachy.cache(:xxx){1}
394
- Cachy.key_versions.key?(:xxx).should == true
395
- Cachy.delete_key :xxx
396
- Cachy.key_versions.key?(:xxx).should == false
397
- end
398
-
399
- it "does not crash with unfound key" do
400
- Cachy.delete_key :xxx
401
- Cachy.delete_key :xxx
402
- Cachy.key_versions.key?(:xxx).should == false
403
- end
404
- end
405
- end
@@ -1,35 +0,0 @@
1
- # stub to test memcache integration
2
- class MemCache
3
- def initialize
4
- @wrapped = {}
5
- end
6
-
7
- def set(key, object, ttl = nil)
8
- raise 'nope!' if ttl.is_a? Hash or (ttl and not ttl.is_a? Numeric)
9
- @wrapped[key] = object
10
- end
11
-
12
- def get(key)
13
- cache_get(key)
14
- end
15
-
16
- def cache_get(key)
17
- stubable_cache_get(key)
18
- end
19
-
20
- def stubable_cache_get(key)
21
- @wrapped[key]
22
- end
23
-
24
- def [](x)
25
- @wrapped[x]
26
- end
27
-
28
- def clear
29
- @wrapped.clear
30
- end
31
-
32
- def delete(key)
33
- @wrapped.delete(key)
34
- end
35
- end
@@ -1,3 +0,0 @@
1
- require './spec/test_cache'
2
- $LOAD_PATH << 'lib'
3
- require 'cachy'
@@ -1,25 +0,0 @@
1
- class TestCache
2
- def initialize
3
- @data = {}
4
- end
5
-
6
- def read(name)
7
- @data[name]
8
- end
9
-
10
- def write(name, value, options = nil)
11
- @data[name] = value.freeze
12
- end
13
-
14
- def delete(name, options = nil)
15
- @data.delete(name)
16
- end
17
-
18
- def clear
19
- @data.clear
20
- end
21
-
22
- def keys
23
- @data.keys
24
- end
25
- end