juno 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -1
- data/.travis.yml +6 -0
- data/Gemfile +16 -9
- data/README.md +92 -34
- data/Rakefile +23 -5
- data/benchmarks/run.rb +19 -22
- data/juno.gemspec +0 -3
- data/lib/juno/adapters/activerecord.rb +58 -0
- data/lib/juno/adapters/cassandra.rb +47 -0
- data/lib/juno/adapters/couch.rb +43 -0
- data/lib/juno/adapters/datamapper.rb +64 -0
- data/lib/juno/adapters/dbm.rb +17 -0
- data/lib/juno/adapters/file.rb +58 -0
- data/lib/juno/adapters/fog.rb +42 -0
- data/lib/juno/adapters/gdbm.rb +17 -0
- data/lib/juno/adapters/localmemcache.rb +18 -0
- data/lib/juno/adapters/memcached.rb +11 -0
- data/lib/juno/adapters/memcached_dalli.rb +46 -0
- data/lib/juno/adapters/memcached_native.rb +47 -0
- data/lib/juno/adapters/memory.rb +30 -0
- data/lib/juno/adapters/mongo.rb +43 -0
- data/lib/juno/adapters/null.rb +28 -0
- data/lib/juno/adapters/pstore.rb +51 -0
- data/lib/juno/adapters/redis.rb +43 -0
- data/lib/juno/adapters/riak.rb +46 -0
- data/lib/juno/adapters/sdbm.rb +27 -0
- data/lib/juno/adapters/sequel.rb +50 -0
- data/lib/juno/adapters/sqlite.rb +52 -0
- data/lib/juno/adapters/tokyocabinet.rb +33 -0
- data/lib/juno/adapters/yaml.rb +13 -0
- data/lib/juno/base.rb +11 -89
- data/lib/juno/builder.rb +30 -0
- data/lib/juno/cache.rb +64 -0
- data/lib/juno/expires.rb +6 -10
- data/lib/juno/proxy.rb +62 -3
- data/lib/juno/stack.rb +27 -11
- data/lib/juno/transformer.rb +106 -0
- data/lib/juno/version.rb +1 -1
- data/lib/juno.rb +81 -29
- data/spec/adapter_activerecord_spec.rb +41 -0
- data/spec/adapter_cassandra_spec.rb +27 -0
- data/spec/adapter_couch_spec.rb +27 -0
- data/spec/adapter_datamapper_spec.rb +61 -0
- data/spec/adapter_dbm_spec.rb +27 -0
- data/spec/adapter_file_spec.rb +27 -0
- data/spec/adapter_fog_spec.rb +35 -0
- data/spec/adapter_gdbm_spec.rb +27 -0
- data/spec/adapter_localmemcache_spec.rb +27 -0
- data/spec/adapter_memcached_dalli_spec.rb +28 -0
- data/spec/adapter_memcached_native_spec.rb +28 -0
- data/spec/adapter_memcached_spec.rb +28 -0
- data/spec/adapter_memory_spec.rb +42 -0
- data/spec/adapter_mongo_spec.rb +27 -0
- data/spec/adapter_pstore_spec.rb +30 -0
- data/spec/adapter_redis_spec.rb +28 -0
- data/spec/adapter_riak_spec.rb +31 -0
- data/spec/adapter_sdbm_spec.rb +27 -0
- data/spec/adapter_sequel_spec.rb +27 -0
- data/spec/adapter_sqlite_spec.rb +27 -0
- data/spec/adapter_tokyocabinet_spec.rb +27 -0
- data/spec/adapter_yaml_spec.rb +30 -0
- data/spec/cache_file_memory_spec.rb +50 -0
- data/spec/cache_memory_null_spec.rb +39 -0
- data/spec/expires_file_spec.rb +82 -0
- data/spec/expires_memory_spec.rb +59 -0
- data/spec/generate.rb +736 -0
- data/spec/helper.rb +39 -0
- data/spec/junospecs.rb +1540 -0
- data/spec/null_adapter_spec.rb +33 -0
- data/spec/proxy_expires_memory_spec.rb +63 -0
- data/spec/proxy_redis_spec.rb +38 -0
- data/spec/simple_activerecord_spec.rb +52 -0
- data/spec/simple_cassandra_spec.rb +53 -0
- data/spec/simple_couch_spec.rb +52 -0
- data/spec/simple_datamapper_spec.rb +54 -0
- data/spec/simple_datamapper_with_repository_spec.rb +54 -0
- data/spec/simple_dbm_spec.rb +52 -0
- data/spec/simple_file_spec.rb +52 -0
- data/spec/simple_fog_spec.rb +60 -0
- data/spec/simple_gdbm_spec.rb +52 -0
- data/spec/simple_hashfile_spec.rb +52 -0
- data/spec/simple_localmemcache_spec.rb +52 -0
- data/spec/simple_memcached_dalli_spec.rb +53 -0
- data/spec/simple_memcached_native_spec.rb +53 -0
- data/spec/simple_memcached_spec.rb +53 -0
- data/spec/simple_memory_spec.rb +52 -0
- data/spec/simple_mongo_spec.rb +52 -0
- data/spec/simple_null_spec.rb +43 -0
- data/spec/simple_pstore_spec.rb +52 -0
- data/spec/simple_redis_spec.rb +53 -0
- data/spec/simple_riak_spec.rb +56 -0
- data/spec/simple_sdbm_spec.rb +52 -0
- data/spec/simple_sequel_spec.rb +52 -0
- data/spec/simple_sqlite_spec.rb +52 -0
- data/spec/simple_tokyocabinet_spec.rb +52 -0
- data/spec/simple_yaml_spec.rb +52 -0
- data/spec/stack_file_memory_spec.rb +43 -0
- data/spec/stack_memory_file_spec.rb +42 -0
- data/spec/transformer_bson_spec.rb +44 -0
- data/spec/transformer_json_spec.rb +44 -0
- data/spec/transformer_marshal_base64_spec.rb +60 -0
- data/spec/transformer_marshal_escape_spec.rb +60 -0
- data/spec/transformer_marshal_md5_spec.rb +60 -0
- data/spec/transformer_marshal_md5_spread_spec.rb +60 -0
- data/spec/transformer_msgpack_spec.rb +44 -0
- data/spec/transformer_yaml_spec.rb +59 -0
- metadata +164 -108
- data/lib/juno/activerecord.rb +0 -55
- data/lib/juno/cassandra.rb +0 -45
- data/lib/juno/couch.rb +0 -43
- data/lib/juno/datamapper.rb +0 -63
- data/lib/juno/dbm.rb +0 -15
- data/lib/juno/file.rb +0 -62
- data/lib/juno/fog.rb +0 -48
- data/lib/juno/gdbm.rb +0 -15
- data/lib/juno/hashfile.rb +0 -12
- data/lib/juno/localmemcache.rb +0 -16
- data/lib/juno/memcached.rb +0 -7
- data/lib/juno/memcached_dalli.rb +0 -55
- data/lib/juno/memcached_native.rb +0 -56
- data/lib/juno/memory.rb +0 -7
- data/lib/juno/mongodb.rb +0 -43
- data/lib/juno/null.rb +0 -23
- data/lib/juno/pstore.rb +0 -49
- data/lib/juno/redis.rb +0 -46
- data/lib/juno/riak.rb +0 -45
- data/lib/juno/sdbm.rb +0 -15
- data/lib/juno/sequel.rb +0 -48
- data/lib/juno/sqlite.rb +0 -50
- data/lib/juno/tokyocabinet.rb +0 -36
- data/lib/juno/yaml.rb +0 -9
- data/test/helper.rb +0 -212
- data/test/test_activerecord.rb +0 -33
- data/test/test_cassandra.rb +0 -13
- data/test/test_couch.rb +0 -13
- data/test/test_datamapper.rb +0 -64
- data/test/test_dbm.rb +0 -13
- data/test/test_expires.rb +0 -9
- data/test/test_file.rb +0 -9
- data/test/test_fog.rb +0 -17
- data/test/test_gdbm.rb +0 -13
- data/test/test_hashfile.rb +0 -9
- data/test/test_localmemcache.rb +0 -13
- data/test/test_memcached.rb +0 -14
- data/test/test_memcached_dalli.rb +0 -14
- data/test/test_memcached_native.rb +0 -14
- data/test/test_memory.rb +0 -9
- data/test/test_mongodb.rb +0 -13
- data/test/test_null.rb +0 -9
- data/test/test_proxy.rb +0 -9
- data/test/test_pstore.rb +0 -9
- data/test/test_redis.rb +0 -13
- data/test/test_riak.rb +0 -13
- data/test/test_sdbm.rb +0 -13
- data/test/test_sequel.rb +0 -13
- data/test/test_sqlite.rb +0 -13
- data/test/test_stack.rb +0 -10
- data/test/test_tokyocabinet.rb +0 -13
- data/test/test_yaml.rb +0 -9
- data/unsupported/test_tokyotyrant.rb +0 -13
- data/unsupported/tokyotyrant.rb +0 -29
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'localmemcache'
|
2
|
+
|
3
|
+
module Juno
|
4
|
+
module Adapters
|
5
|
+
class LocalMemCache < Memory
|
6
|
+
def initialize(options = {})
|
7
|
+
raise 'No option :file specified' unless options[:file]
|
8
|
+
@memory = ::LocalMemCache.new(:filename => options[:file])
|
9
|
+
end
|
10
|
+
|
11
|
+
def delete(key, options = {})
|
12
|
+
value = load(key, options)
|
13
|
+
@memory.delete(key)
|
14
|
+
value
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'dalli'
|
2
|
+
|
3
|
+
module Juno
|
4
|
+
module Adapters
|
5
|
+
class MemcachedDalli < Base
|
6
|
+
def initialize(options = {})
|
7
|
+
server = options.delete(:server) || 'localhost:11211'
|
8
|
+
@cache = ::Dalli::Client.new(server, options)
|
9
|
+
end
|
10
|
+
|
11
|
+
def key?(key, options = {})
|
12
|
+
!!@cache.get(key)
|
13
|
+
end
|
14
|
+
|
15
|
+
def load(key, options = {})
|
16
|
+
value = @cache.get(key)
|
17
|
+
if value && options.include?(:expires)
|
18
|
+
store(key, value, options)
|
19
|
+
else
|
20
|
+
value
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def store(key, value, options = {})
|
25
|
+
@cache.set(key, value, options[:expires])
|
26
|
+
value
|
27
|
+
end
|
28
|
+
|
29
|
+
def delete(key, options = {})
|
30
|
+
value = @cache.get(key)
|
31
|
+
@cache.delete(key)
|
32
|
+
value
|
33
|
+
end
|
34
|
+
|
35
|
+
def clear(options = {})
|
36
|
+
@cache.flush_all
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
def close
|
41
|
+
@cache.close
|
42
|
+
nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'memcached'
|
2
|
+
|
3
|
+
module Juno
|
4
|
+
module Adapters
|
5
|
+
class MemcachedNative < Base
|
6
|
+
def initialize(options = {})
|
7
|
+
server = options.delete(:server) || 'localhost:11211'
|
8
|
+
options.merge!(:prefix_key => options.delete(:namespace)) if options[:namespace]
|
9
|
+
@cache = ::Memcached.new(server, options)
|
10
|
+
end
|
11
|
+
|
12
|
+
def key?(key, options = {})
|
13
|
+
@cache.get(key, false)
|
14
|
+
true
|
15
|
+
rescue ::Memcached::NotFound
|
16
|
+
false
|
17
|
+
end
|
18
|
+
|
19
|
+
def load(key, options = {})
|
20
|
+
value = @cache.get(key, false)
|
21
|
+
if value && options.include?(:expires)
|
22
|
+
store(key, value, options)
|
23
|
+
else
|
24
|
+
value
|
25
|
+
end
|
26
|
+
rescue ::Memcached::NotFound
|
27
|
+
end
|
28
|
+
|
29
|
+
def delete(key, options = {})
|
30
|
+
value = @cache.get(key, false)
|
31
|
+
@cache.delete(key)
|
32
|
+
value
|
33
|
+
rescue ::Memcached::NotFound
|
34
|
+
end
|
35
|
+
|
36
|
+
def store(key, value, options = {})
|
37
|
+
@cache.set(key, value, options[:expires] || @cache.options[:default_ttl], false)
|
38
|
+
value
|
39
|
+
end
|
40
|
+
|
41
|
+
def clear(options = {})
|
42
|
+
@cache.flush
|
43
|
+
self
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Juno
|
2
|
+
module Adapters
|
3
|
+
class Memory < Base
|
4
|
+
def initialize(options = {})
|
5
|
+
@memory = {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def key?(key, options = {})
|
9
|
+
@memory.has_key?(key)
|
10
|
+
end
|
11
|
+
|
12
|
+
def load(key, options = {})
|
13
|
+
@memory[key]
|
14
|
+
end
|
15
|
+
|
16
|
+
def store(key, value, options = {})
|
17
|
+
@memory[key] = value
|
18
|
+
end
|
19
|
+
|
20
|
+
def delete(key, options = {})
|
21
|
+
@memory.delete(key)
|
22
|
+
end
|
23
|
+
|
24
|
+
def clear(options = {})
|
25
|
+
@memory.clear
|
26
|
+
self
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'mongo'
|
2
|
+
|
3
|
+
module Juno
|
4
|
+
module Adapters
|
5
|
+
class Mongo < Base
|
6
|
+
def initialize(options = {})
|
7
|
+
collection = options.delete(:collection) || 'juno'
|
8
|
+
host = options.delete(:host) || 'localhost'
|
9
|
+
port = options.delete(:port) || ::Mongo::Connection::DEFAULT_PORT
|
10
|
+
db = options.delete(:db) || 'juno'
|
11
|
+
connection = ::Mongo::Connection.new(host, port, options)
|
12
|
+
@collection = connection.db(db).collection(collection)
|
13
|
+
end
|
14
|
+
|
15
|
+
def key?(key, options = {})
|
16
|
+
!!load(key, options)
|
17
|
+
end
|
18
|
+
|
19
|
+
def load(key, options = {})
|
20
|
+
value = @collection.find_one('_id' => key)
|
21
|
+
value ? value['data'] : nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def delete(key, options = {})
|
25
|
+
value = load(key, options)
|
26
|
+
@collection.remove('_id' => key) if value
|
27
|
+
value
|
28
|
+
end
|
29
|
+
|
30
|
+
def store(key, value, options = {})
|
31
|
+
@collection.update({ '_id' => key },
|
32
|
+
{ '_id' => key, 'data' => value },
|
33
|
+
{ :upsert => true })
|
34
|
+
value
|
35
|
+
end
|
36
|
+
|
37
|
+
def clear(options = {})
|
38
|
+
@collection.remove
|
39
|
+
self
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Juno
|
2
|
+
module Adapters
|
3
|
+
class Null < Base
|
4
|
+
def initialize(options = {})
|
5
|
+
end
|
6
|
+
|
7
|
+
def key?(key, options = {})
|
8
|
+
false
|
9
|
+
end
|
10
|
+
|
11
|
+
def load(key, options = {})
|
12
|
+
nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def store(key, value, options = {})
|
16
|
+
value
|
17
|
+
end
|
18
|
+
|
19
|
+
def delete(key, options = {})
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def clear(options = {})
|
24
|
+
self
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'pstore'
|
2
|
+
|
3
|
+
module Juno
|
4
|
+
module Adapters
|
5
|
+
class PStore < Base
|
6
|
+
def initialize(options = {})
|
7
|
+
raise 'No option :file specified' unless options[:file]
|
8
|
+
FileUtils.mkpath(::File.dirname(options[:file]))
|
9
|
+
@pstore = new_store(options)
|
10
|
+
end
|
11
|
+
|
12
|
+
def key?(key, options = {})
|
13
|
+
@pstore.transaction(true) { @pstore.root?(key) }
|
14
|
+
end
|
15
|
+
|
16
|
+
def load(key, options = {})
|
17
|
+
@pstore.transaction(true) { @pstore[key] }
|
18
|
+
end
|
19
|
+
|
20
|
+
def delete(key, options = {})
|
21
|
+
@pstore.transaction { @pstore.delete(key) }
|
22
|
+
end
|
23
|
+
|
24
|
+
def store(key, value, options = {})
|
25
|
+
@pstore.transaction { @pstore[key] = value }
|
26
|
+
end
|
27
|
+
|
28
|
+
def clear(options = {})
|
29
|
+
@pstore.transaction do
|
30
|
+
@pstore.roots.each do |key|
|
31
|
+
@pstore.delete(key)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
protected
|
38
|
+
|
39
|
+
if RUBY_VERSION > '1.9'
|
40
|
+
def new_store(options)
|
41
|
+
# Create a thread-safe pstore by default
|
42
|
+
::PStore.new(options[:file], options.include?(:thread_safe) ? options[:thread_safe] : true)
|
43
|
+
end
|
44
|
+
else
|
45
|
+
def new_store(options)
|
46
|
+
::PStore.new(options[:file])
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'redis'
|
2
|
+
|
3
|
+
module Juno
|
4
|
+
module Adapters
|
5
|
+
class Redis < Base
|
6
|
+
def initialize(options = {})
|
7
|
+
@redis = ::Redis.new(options)
|
8
|
+
end
|
9
|
+
|
10
|
+
def key?(key, options = {})
|
11
|
+
@redis.exists(key)
|
12
|
+
end
|
13
|
+
|
14
|
+
def load(key, options = {})
|
15
|
+
value = @redis.get(key)
|
16
|
+
if value && (expires = options[:expires])
|
17
|
+
@redis.expire(key, expires)
|
18
|
+
end
|
19
|
+
value
|
20
|
+
end
|
21
|
+
|
22
|
+
def delete(key, options = {})
|
23
|
+
if value = load(key, options)
|
24
|
+
@redis.del(key)
|
25
|
+
value
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def store(key, value, options = {})
|
30
|
+
@redis.set(key, value)
|
31
|
+
if expires = options[:expires]
|
32
|
+
@redis.expire(key, expires)
|
33
|
+
end
|
34
|
+
value
|
35
|
+
end
|
36
|
+
|
37
|
+
def clear(options = {})
|
38
|
+
@redis.flushdb
|
39
|
+
self
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# Copyright: 2011 TMX Credit
|
2
|
+
# Author: Potapov Sergey (aka Blake)
|
3
|
+
|
4
|
+
require 'riak'
|
5
|
+
|
6
|
+
module Juno
|
7
|
+
module Adapters
|
8
|
+
class Riak < Base
|
9
|
+
def initialize(options = {})
|
10
|
+
bucket = options.delete(:bucket) || 'juno'
|
11
|
+
@bucket = ::Riak::Client.new(options).bucket(bucket)
|
12
|
+
end
|
13
|
+
|
14
|
+
def key?(key, options = {})
|
15
|
+
@bucket.exists?(key, options)
|
16
|
+
end
|
17
|
+
|
18
|
+
def load(key, options = {})
|
19
|
+
@bucket.get(key, options).raw_data
|
20
|
+
rescue ::Riak::FailedRequest => ex
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def delete(key, options = {})
|
25
|
+
value = load(key, options)
|
26
|
+
@bucket.delete(key, options)
|
27
|
+
value
|
28
|
+
end
|
29
|
+
|
30
|
+
def store(key, value, options = {})
|
31
|
+
obj = ::Riak::RObject.new(@bucket, key)
|
32
|
+
obj.content_type = 'application/octet-stream'
|
33
|
+
obj.raw_data = value
|
34
|
+
obj.store(options)
|
35
|
+
value
|
36
|
+
end
|
37
|
+
|
38
|
+
def clear(options = {})
|
39
|
+
@bucket.keys do |keys|
|
40
|
+
keys.each{ |key| @bucket.delete(key) }
|
41
|
+
end
|
42
|
+
self
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'sdbm'
|
2
|
+
|
3
|
+
module Juno
|
4
|
+
module Adapters
|
5
|
+
class SDBM < Memory
|
6
|
+
def initialize(options = {})
|
7
|
+
raise 'No option :file specified' unless options[:file]
|
8
|
+
@memory = ::SDBM.new(options[:file])
|
9
|
+
end
|
10
|
+
|
11
|
+
def close
|
12
|
+
@memory.close
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def store(key, value, options = {})
|
17
|
+
super
|
18
|
+
value
|
19
|
+
rescue SDBMError
|
20
|
+
# SDBM is not very robust!
|
21
|
+
# You shouldn't put to much data into it, otherwise
|
22
|
+
# it might raise a SDBMError.
|
23
|
+
value
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'sequel'
|
2
|
+
|
3
|
+
module Juno
|
4
|
+
module Adapters
|
5
|
+
class Sequel < Base
|
6
|
+
def initialize(options = {})
|
7
|
+
raise 'No option :db specified' unless db = options.delete(:db)
|
8
|
+
@table = options.delete(:table) || :juno
|
9
|
+
@db = ::Sequel.connect(db, options)
|
10
|
+
@db.create_table?(@table) do
|
11
|
+
primary_key :k
|
12
|
+
String :k
|
13
|
+
String :v
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def key?(key, options = {})
|
18
|
+
!!sequel_table[:k => key]
|
19
|
+
end
|
20
|
+
|
21
|
+
def load(key, options = {})
|
22
|
+
result = sequel_table[:k => key]
|
23
|
+
result ? result[:v] : nil
|
24
|
+
end
|
25
|
+
|
26
|
+
def store(key, value, options = {})
|
27
|
+
sequel_table.insert(:k => key, :v => value)
|
28
|
+
value
|
29
|
+
end
|
30
|
+
|
31
|
+
def delete(key, options = {})
|
32
|
+
if value = load(key, options)
|
33
|
+
sequel_table.filter(:k => key).delete
|
34
|
+
value
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def clear(options = {})
|
39
|
+
sequel_table.delete
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def sequel_table
|
46
|
+
@sequel_table ||= @db[@table]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'sqlite3'
|
2
|
+
|
3
|
+
module Juno
|
4
|
+
module Adapters
|
5
|
+
class Sqlite < Base
|
6
|
+
def initialize(options = {})
|
7
|
+
raise 'No option :file specified' unless options[:file]
|
8
|
+
table = options[:table] || 'juno'
|
9
|
+
@db = ::SQLite3::Database.new(options[:file])
|
10
|
+
@db.execute("create table if not exists #{table} (key string primary key, value string)")
|
11
|
+
@select = @db.prepare("select value from #{table} where key = ?")
|
12
|
+
@insert = @db.prepare("insert into #{table} values (?, ?)")
|
13
|
+
@delete = @db.prepare("delete from #{table} where key = ?")
|
14
|
+
@clear = @db.prepare("delete from #{table}")
|
15
|
+
end
|
16
|
+
|
17
|
+
def key?(key, options = {})
|
18
|
+
!@select.execute!(key).empty?
|
19
|
+
end
|
20
|
+
|
21
|
+
def load(key, options = {})
|
22
|
+
rows = @select.execute!(key)
|
23
|
+
rows.empty? ? nil : rows.first.first
|
24
|
+
end
|
25
|
+
|
26
|
+
def store(key, value, options = {})
|
27
|
+
@insert.execute!(key, value)
|
28
|
+
value
|
29
|
+
end
|
30
|
+
|
31
|
+
def delete(key, options = {})
|
32
|
+
value = load(key, options)
|
33
|
+
@delete.execute!(key)
|
34
|
+
value
|
35
|
+
end
|
36
|
+
|
37
|
+
def clear(options = {})
|
38
|
+
@clear.execute!
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
42
|
+
def close
|
43
|
+
@select.close
|
44
|
+
@insert.close
|
45
|
+
@delete.close
|
46
|
+
@clear.close
|
47
|
+
@db.close
|
48
|
+
nil
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'tokyocabinet'
|
2
|
+
|
3
|
+
module Juno
|
4
|
+
module Adapters
|
5
|
+
class TokyoCabinet < Memory
|
6
|
+
def initialize(options = {})
|
7
|
+
file = options[:file]
|
8
|
+
raise 'No option :file specified' unless options[:file]
|
9
|
+
@memory = ::TokyoCabinet::HDB.new
|
10
|
+
unless @memory.open(file, ::TokyoCabinet::HDB::OWRITER | ::TokyoCabinet::HDB::OCREAT)
|
11
|
+
raise @memory.errmsg(@memory.ecode)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def key?(key, options = {})
|
16
|
+
!!load(key, options)
|
17
|
+
end
|
18
|
+
|
19
|
+
def delete(key, options = {})
|
20
|
+
value = load(key, options)
|
21
|
+
if value
|
22
|
+
@memory.delete(key)
|
23
|
+
value
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def close
|
28
|
+
@memory.close
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/juno/base.rb
CHANGED
@@ -1,72 +1,29 @@
|
|
1
1
|
module Juno
|
2
2
|
# Simple interface to key/value stores with Hash-like interface.
|
3
|
-
#
|
4
|
-
# @abstract
|
5
3
|
class Base
|
6
|
-
#
|
7
|
-
#
|
8
|
-
# @param [Object] key
|
9
|
-
# @return [Boolean]
|
10
|
-
# @param [Hash] options
|
11
|
-
# @api public
|
12
|
-
def key?(key, options = {})
|
13
|
-
@store.has_key?(key_for(key))
|
14
|
-
end
|
15
|
-
|
16
|
-
def has_key?(key, options = {})
|
17
|
-
key?(key, options)
|
18
|
-
end
|
19
|
-
|
20
|
-
# Fetch value with key. Return nil if the key doesn't exist
|
21
|
-
#
|
22
|
-
# @param [Object] key
|
23
|
-
# @return [Object] value
|
24
|
-
# @api public
|
25
|
-
def [](key)
|
26
|
-
deserialize(@store[key_for(key)])
|
27
|
-
end
|
28
|
-
|
29
|
-
# Store value with key
|
30
|
-
#
|
31
|
-
# @param [Object] key
|
32
|
-
# @param [Object] value
|
33
|
-
# @param [Hash] options
|
34
|
-
# @return value
|
4
|
+
# Explicitly close the store
|
35
5
|
# @api public
|
36
|
-
def
|
37
|
-
@store[key_for(key)] = serialize(value)
|
38
|
-
value
|
6
|
+
def close
|
39
7
|
end
|
40
8
|
|
41
|
-
#
|
9
|
+
# Fetch value with key. Return default if value is nil.
|
42
10
|
#
|
43
11
|
# @param [Object] key
|
44
|
-
# @
|
45
|
-
# @param [Hash] options
|
46
|
-
# @api public
|
47
|
-
def delete(key, options = {})
|
48
|
-
deserialize(@store.delete(key_for(key)))
|
49
|
-
end
|
50
|
-
|
51
|
-
# Clear all keys in this store
|
52
|
-
#
|
12
|
+
# @param [Object] value Default value
|
53
13
|
# @param [Hash] options
|
54
|
-
# @return [
|
14
|
+
# @return [Object] value from store
|
55
15
|
# @api public
|
56
|
-
def
|
57
|
-
|
58
|
-
nil
|
16
|
+
def fetch(key, value = nil, options = {})
|
17
|
+
load(key, options) || (block_given? && yield(key)) || value
|
59
18
|
end
|
60
19
|
|
61
|
-
# Fetch value with key. Return
|
20
|
+
# Fetch value with key. Return nil if the key doesn't exist
|
62
21
|
#
|
63
22
|
# @param [Object] key
|
64
|
-
# @
|
65
|
-
# @param [Hash] options
|
66
|
-
# @return [Object] value from store
|
23
|
+
# @return [Object] value
|
67
24
|
# @api public
|
68
|
-
def
|
69
|
-
|
25
|
+
def [](key)
|
26
|
+
load(key)
|
70
27
|
end
|
71
28
|
|
72
29
|
# Store value with key
|
@@ -78,40 +35,5 @@ module Juno
|
|
78
35
|
def []=(key, value)
|
79
36
|
store(key, value)
|
80
37
|
end
|
81
|
-
|
82
|
-
# Explicitly close the store
|
83
|
-
# @api public
|
84
|
-
def close
|
85
|
-
nil
|
86
|
-
end
|
87
|
-
|
88
|
-
protected
|
89
|
-
|
90
|
-
# Serialize value
|
91
|
-
#
|
92
|
-
# @param [Object] value Serializable object
|
93
|
-
# @return [String] serialized object
|
94
|
-
# @api private
|
95
|
-
def serialize(value)
|
96
|
-
Marshal.dump(value)
|
97
|
-
end
|
98
|
-
|
99
|
-
# Deserialize value
|
100
|
-
#
|
101
|
-
# @param [String] value Serialized object
|
102
|
-
# @return [Object] Deserialized object
|
103
|
-
# @api private
|
104
|
-
def deserialize(value)
|
105
|
-
value && Marshal.load(value)
|
106
|
-
end
|
107
|
-
|
108
|
-
# Convert key to string
|
109
|
-
#
|
110
|
-
# @param [Object] key Key
|
111
|
-
# @return [String] Marshalled key
|
112
|
-
# @api private
|
113
|
-
def key_for(key)
|
114
|
-
String === key ? key : Marshal.dump(key)
|
115
|
-
end
|
116
38
|
end
|
117
39
|
end
|