cache-client 0.0.3
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/.gitignore +17 -0
- data/.rvmrc +1 -0
- data/CHANGELOG.md +8 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +22 -0
- data/README.md +52 -0
- data/Rakefile +9 -0
- data/cache-client.gemspec +19 -0
- data/lib/cache-backend/noop_backend.rb +15 -0
- data/lib/cache-client.rb +50 -0
- data/lib/cache-client/error.rb +4 -0
- data/lib/cache-client/key_builder.rb +18 -0
- data/lib/cache-client/utils.rb +7 -0
- data/lib/cache-client/version.rb +5 -0
- data/spec/cache_client_spec.rb +64 -0
- data/spec/in_memory_backend.rb +15 -0
- data/spec/key_building_spec.rb +74 -0
- data/spec/spec_helper.rb +7 -0
- metadata +68 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use 1.9.3
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Thorben Schröder
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# Cache::Client
|
2
|
+
|
3
|
+
A client to store and retrieve data in a cache backend. The client is backend agnostic and can be used as a *noop-cache* without any backend.
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
### Setup
|
8
|
+
|
9
|
+
To instantiate a new cache client you pass in a class of a cache backend and a list of parameters for that array. If either the backend class or all parameters are ``nil`` the cache will fall back to a noon mode. In that mode it will work without any errors but not cache anything at all. This is useful for tests and development mode.
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
cache_client = Cache::Client.new(Cache::BackendClass, 'http://localhost', '8080')
|
13
|
+
```
|
14
|
+
|
15
|
+
Instead of an actual class instance you can also pass in a string of the backend's class name
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
cache_client = Cache::Client.new('Cache::BackendClass', 'http://localhost', '8080')
|
19
|
+
```
|
20
|
+
|
21
|
+
### Cache keys
|
22
|
+
|
23
|
+
Cache keys can be any objects or arrays of objects. The ``Cache::Client`` will turn each object to a cache key using this methods in a top to bottom order:
|
24
|
+
|
25
|
+
* ``#to_cache_key``
|
26
|
+
* the key itself if it is a string
|
27
|
+
* the string version of the key if it is a number
|
28
|
+
* A SHA1 hash of the ``Marshal.dump`` of the key object
|
29
|
+
|
30
|
+
Objects in an array will each be turned into cache key first and then concatenated.
|
31
|
+
|
32
|
+
### Set a value in the cache
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
cache_client.set(['my', 'key'], 123) # => 123
|
36
|
+
```
|
37
|
+
|
38
|
+
### Get a value from the cache
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
cache_client.get(['my', 'key']) # => 123
|
42
|
+
```
|
43
|
+
|
44
|
+
### Set or get in the cache
|
45
|
+
|
46
|
+
This will set a value in the cache if the given key does not exist, otherwise it just returns the value under that key from the cache.
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
cache_client.get(['my', 'key']) do
|
50
|
+
123
|
51
|
+
end # => 123
|
52
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'cache-client/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "cache-client"
|
8
|
+
gem.version = Cache::Client::VERSION
|
9
|
+
gem.authors = ["Thorben Schröder"]
|
10
|
+
gem.email = ["stillepost@gmail.com"]
|
11
|
+
gem.description = %q{A client to store and retrieve data in a cache backend.}
|
12
|
+
gem.summary = %q{A client to store and retrieve data in a cache backend.}
|
13
|
+
gem.homepage = ""
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
end
|
data/lib/cache-client.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
module Cache
|
2
|
+
class Client
|
3
|
+
end
|
4
|
+
end
|
5
|
+
|
6
|
+
require "cache-client/version"
|
7
|
+
require "cache-client/error"
|
8
|
+
require "cache-client/utils"
|
9
|
+
require "cache-client/key_builder"
|
10
|
+
require "cache-backend/noop_backend"
|
11
|
+
|
12
|
+
module Cache
|
13
|
+
class Client
|
14
|
+
attr_reader :backend
|
15
|
+
def initialize(backend, *args)
|
16
|
+
@backend = backendify(backend).new(*args)
|
17
|
+
end
|
18
|
+
|
19
|
+
def set(key, value)
|
20
|
+
@backend.set(keyify(key), value)
|
21
|
+
end
|
22
|
+
|
23
|
+
def get(key)
|
24
|
+
@backend.get(keyify(key))
|
25
|
+
end
|
26
|
+
|
27
|
+
def fetch(key)
|
28
|
+
existing_value = get(key)
|
29
|
+
return existing_value if existing_value
|
30
|
+
set(key, yield)
|
31
|
+
end
|
32
|
+
|
33
|
+
protected
|
34
|
+
def backendify(backend)
|
35
|
+
return Cache::Backend::NoopBackend unless backend
|
36
|
+
|
37
|
+
return backend if backend.kind_of?(Class)
|
38
|
+
|
39
|
+
clazz = Class
|
40
|
+
Utils.camelize_string(backend).split('::').each do |const|
|
41
|
+
clazz = clazz.const_get(const)
|
42
|
+
end
|
43
|
+
clazz
|
44
|
+
end
|
45
|
+
|
46
|
+
def keyify(keys)
|
47
|
+
Array(keys).map {|key| KeyBuilder.new(key)}.join('-')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'digest/sha1'
|
2
|
+
|
3
|
+
class Cache::Client
|
4
|
+
class KeyBuilder
|
5
|
+
def initialize(key)
|
6
|
+
@key = key
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_s
|
10
|
+
return @key.to_cache_key if @key.respond_to?(:to_cache_key)
|
11
|
+
|
12
|
+
return @key if @key.kind_of?(String)
|
13
|
+
return @key.to_s if @key.kind_of?(Numeric)
|
14
|
+
|
15
|
+
return Digest::SHA1.hexdigest(Marshal.dump(@key))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require_relative './spec_helper'
|
2
|
+
|
3
|
+
describe Cache::Client do
|
4
|
+
describe "without a cache class" do
|
5
|
+
before do
|
6
|
+
@client = Cache::Client.new(nil)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "does not cache anything" do
|
10
|
+
@client.set('bla', 123).must_equal(123)
|
11
|
+
@client.get('bla').must_be_nil
|
12
|
+
@client.fetch('bla') do
|
13
|
+
456
|
14
|
+
end.must_equal 456
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "backends" do
|
19
|
+
it "can be set using a class as a backend descriptor" do
|
20
|
+
client = Cache::Client.new(Cache::InMemoryBackend)
|
21
|
+
client.backend.kind_of?(Cache::InMemoryBackend).must_equal true
|
22
|
+
end
|
23
|
+
|
24
|
+
it "can be set using a class name string as a backend descriptor" do
|
25
|
+
client = Cache::Client.new('Cache::InMemoryBackend')
|
26
|
+
client.backend.kind_of?(Cache::InMemoryBackend).must_equal true
|
27
|
+
end
|
28
|
+
|
29
|
+
it "passes a list of options through to the backend" do
|
30
|
+
class ArgumentTestBackend
|
31
|
+
attr_reader :args
|
32
|
+
def initialize(*args)
|
33
|
+
@args = args
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
client = Cache::Client.new(ArgumentTestBackend, 1, 2, 3, {'four' => :five})
|
38
|
+
client.backend.args.must_equal([1, 2, 3, {'four' => :five}])
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "that are initialized" do
|
42
|
+
before do
|
43
|
+
@client = Cache::Client.new(Cache::InMemoryBackend)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "can set/get values" do
|
47
|
+
@client.set('bla', 123).must_equal(123)
|
48
|
+
@client.get('bla').must_equal(123)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "can fetch values" do
|
52
|
+
@client.fetch(['bla', 'fetch']) do
|
53
|
+
123
|
54
|
+
end.must_equal(123)
|
55
|
+
|
56
|
+
@client.fetch(['bla', 'fetch']) do
|
57
|
+
456
|
58
|
+
end.must_equal(123)
|
59
|
+
|
60
|
+
@client.get(['bla', 'fetch']).must_equal(123)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require_relative './spec_helper'
|
2
|
+
|
3
|
+
require 'digest/sha1'
|
4
|
+
|
5
|
+
class ObectWithToCacheKey
|
6
|
+
def initialize(arg)
|
7
|
+
@arg = arg
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_cache_key
|
11
|
+
"_#{@arg}_#{@arg}_"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class ObectWithoutToCacheKey
|
16
|
+
def initialize(arg)
|
17
|
+
@arg = arg
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class TestingBackend
|
22
|
+
attr_reader :last_key
|
23
|
+
|
24
|
+
def get(key)
|
25
|
+
@last_key = key
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe Cache::Client do
|
31
|
+
describe "cache keys" do
|
32
|
+
before do
|
33
|
+
@client = Cache::Client.new(TestingBackend)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "uses #to_cache_key method when available" do
|
37
|
+
key = ObectWithToCacheKey.new('bla')
|
38
|
+
@client.get(key)
|
39
|
+
@client.backend.last_key.must_equal(key.to_cache_key())
|
40
|
+
end
|
41
|
+
|
42
|
+
it "uses the key itself if it is a string" do
|
43
|
+
@client.get('bla')
|
44
|
+
@client.backend.last_key.must_equal('bla')
|
45
|
+
end
|
46
|
+
|
47
|
+
it "uses a string version of the key if it is a number" do
|
48
|
+
@client.get(10)
|
49
|
+
@client.backend.last_key.must_equal('10')
|
50
|
+
|
51
|
+
@client.get(7.3)
|
52
|
+
@client.backend.last_key.must_equal('7.3')
|
53
|
+
end
|
54
|
+
|
55
|
+
it "uses a SHA1 of the marshalled key when #to_cache_key is not available and the key is neither a string nor a number" do
|
56
|
+
key = ObectWithoutToCacheKey.new('bla')
|
57
|
+
@client.get(key)
|
58
|
+
expected_key = Digest::SHA1.hexdigest(Marshal.dump(key))
|
59
|
+
|
60
|
+
@client.backend.last_key.must_equal(expected_key)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "concatenates built keys for arrays of keys" do
|
64
|
+
key1 = ObectWithToCacheKey.new('bla')
|
65
|
+
key2 = ObectWithoutToCacheKey.new('bla')
|
66
|
+
key3 = 'yeah'
|
67
|
+
key4 = 65.7
|
68
|
+
|
69
|
+
@client.get([key1, key2, key3, key4])
|
70
|
+
expected_key = "#{key1.to_cache_key}-#{Digest::SHA1.hexdigest(Marshal.dump(key2))}-#{key3}-#{key4}"
|
71
|
+
@client.backend.last_key.must_equal(expected_key)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cache-client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Thorben Schröder
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-02-20 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: A client to store and retrieve data in a cache backend.
|
15
|
+
email:
|
16
|
+
- stillepost@gmail.com
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- .gitignore
|
22
|
+
- .rvmrc
|
23
|
+
- CHANGELOG.md
|
24
|
+
- Gemfile
|
25
|
+
- LICENSE.txt
|
26
|
+
- README.md
|
27
|
+
- Rakefile
|
28
|
+
- cache-client.gemspec
|
29
|
+
- lib/cache-backend/noop_backend.rb
|
30
|
+
- lib/cache-client.rb
|
31
|
+
- lib/cache-client/error.rb
|
32
|
+
- lib/cache-client/key_builder.rb
|
33
|
+
- lib/cache-client/utils.rb
|
34
|
+
- lib/cache-client/version.rb
|
35
|
+
- spec/cache_client_spec.rb
|
36
|
+
- spec/in_memory_backend.rb
|
37
|
+
- spec/key_building_spec.rb
|
38
|
+
- spec/spec_helper.rb
|
39
|
+
homepage: ''
|
40
|
+
licenses: []
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options: []
|
43
|
+
require_paths:
|
44
|
+
- lib
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
+
none: false
|
47
|
+
requirements:
|
48
|
+
- - ! '>='
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '0'
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ! '>='
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
requirements: []
|
58
|
+
rubyforge_project:
|
59
|
+
rubygems_version: 1.8.24
|
60
|
+
signing_key:
|
61
|
+
specification_version: 3
|
62
|
+
summary: A client to store and retrieve data in a cache backend.
|
63
|
+
test_files:
|
64
|
+
- spec/cache_client_spec.rb
|
65
|
+
- spec/in_memory_backend.rb
|
66
|
+
- spec/key_building_spec.rb
|
67
|
+
- spec/spec_helper.rb
|
68
|
+
has_rdoc:
|