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 ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use 1.9.3
data/CHANGELOG.md ADDED
@@ -0,0 +1,8 @@
1
+ # 0.0.3
2
+
3
+ * Fixes cache key generation for arrays of keys
4
+ * Adds specs
5
+
6
+ # 0.0.2
7
+
8
+ * The beginning
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in cache-client.gemspec
4
+ gemspec
5
+
6
+ group :test, :development do
7
+ gem 'rake'
8
+ end
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,9 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rake/testtask'
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.pattern = "spec/**/*_spec.rb"
7
+ end
8
+
9
+ task :default => :test
@@ -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
@@ -0,0 +1,15 @@
1
+ module Cache
2
+ module Backend
3
+ class NoopBackend
4
+ def initialize(*args)
5
+ end
6
+
7
+ def get(key)
8
+ end
9
+
10
+ def set(key, value)
11
+ value
12
+ end
13
+ end
14
+ end
15
+ end
@@ -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,4 @@
1
+ class Cache::Client
2
+ class Error < StandardError
3
+ end
4
+ 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,7 @@
1
+ class Cache::Client
2
+ class Utils
3
+ def self.camelize_string(str)
4
+ str.gsub('-', '_').sub(/^[a-z\d]*/) { $&.capitalize }.gsub(/(?:_|(\/))([a-z\d]*)/i) {$2.capitalize}
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ module Cache
2
+ class Client
3
+ VERSION = "0.0.3"
4
+ end
5
+ 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,15 @@
1
+ module Cache
2
+ class InMemoryBackend
3
+ def initialize(*args)
4
+ @store = {}
5
+ end
6
+
7
+ def get(key)
8
+ @store[key]
9
+ end
10
+
11
+ def set(key, value)
12
+ @store[key] = value
13
+ end
14
+ end
15
+ 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
@@ -0,0 +1,7 @@
1
+ Bundler.require
2
+
3
+ require 'minitest/autorun'
4
+
5
+ require_relative './in_memory_backend'
6
+
7
+ require 'cache-client'
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: