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
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -16,7 +16,13 @@ before_install:
|
|
16
16
|
- sudo apt-get install -qq libtokyocabinet8 libtokyocabinet-dev # tokyotyrant
|
17
17
|
- sudo /bin/bash /etc/init.d/mongodb start
|
18
18
|
- memcached -d -p 22122
|
19
|
+
env:
|
20
|
+
- "TASK=test:parallel"
|
21
|
+
- "TASK=test:non_parallel"
|
19
22
|
matrix:
|
20
23
|
allow_failures:
|
21
24
|
# - rvm: ruby-head
|
22
25
|
- rvm: jruby
|
26
|
+
- rvm: rbx-18mode
|
27
|
+
- rvm: rbx-19mode
|
28
|
+
script: "bundle exec rake $TASK"
|
data/Gemfile
CHANGED
@@ -1,21 +1,29 @@
|
|
1
1
|
source :rubygems
|
2
2
|
gemspec
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
4
|
+
# Testing
|
5
|
+
gem 'rake'
|
6
|
+
gem 'rspec'
|
7
|
+
gem 'parallel_tests'
|
8
|
+
|
9
|
+
# Serializer
|
10
|
+
#gem 'tnetstring'
|
11
|
+
gem 'msgpack'
|
12
|
+
gem 'bson'
|
13
|
+
gem 'multi_json'
|
14
|
+
gem 'json' # Ripple/Riak needs json
|
10
15
|
|
16
|
+
# Backends
|
17
|
+
gem 'datamapper'
|
18
|
+
gem 'dm-sqlite-adapter'
|
11
19
|
gem 'fog'
|
12
20
|
gem 'activerecord'
|
13
21
|
gem 'redis'
|
14
22
|
gem 'mongo'
|
23
|
+
gem 'couchrest'
|
15
24
|
gem 'sequel'
|
16
25
|
gem 'dalli'
|
17
|
-
gem '
|
18
|
-
gem 'ripple'
|
26
|
+
gem 'riak-client'
|
19
27
|
|
20
28
|
if defined?(JRUBY_VERSION)
|
21
29
|
gem 'jdbc-sqlite3'
|
@@ -29,4 +37,3 @@ end
|
|
29
37
|
|
30
38
|
#gem 'cassandra'
|
31
39
|
#gem 'localmemcache'
|
32
|
-
#gem 'tokyotyrant'
|
data/README.md
CHANGED
@@ -9,38 +9,64 @@ fork was that Moneta was unmaintained for a long time.
|
|
9
9
|
|
10
10
|
Out of the box, it supports:
|
11
11
|
|
12
|
-
*
|
13
|
-
*
|
14
|
-
*
|
15
|
-
*
|
16
|
-
*
|
17
|
-
*
|
18
|
-
*
|
19
|
-
*
|
20
|
-
*
|
21
|
-
*
|
22
|
-
*
|
23
|
-
*
|
24
|
-
*
|
25
|
-
*
|
26
|
-
*
|
27
|
-
*
|
28
|
-
*
|
29
|
-
*
|
30
|
-
*
|
31
|
-
*
|
12
|
+
* Memory:
|
13
|
+
* In-memory store (:Memory)
|
14
|
+
* LocalMemCache (:LocalMemCache)
|
15
|
+
* Memcached store (:Memcached, :MemcachedNative and :MemcachedDalli)
|
16
|
+
* Relational Databases:
|
17
|
+
* DataMapper (:DataMapper)
|
18
|
+
* ActiveRecord (:ActiveRecord)
|
19
|
+
* Sequel (:Sequel)
|
20
|
+
* Sqlite3 (:Sqlite)
|
21
|
+
* Filesystem:
|
22
|
+
* PStore (:PStore)
|
23
|
+
* YAML store (:YAML)
|
24
|
+
* Filesystem directory store (:File)
|
25
|
+
* Filesystem directory store which spreads files in subdirectories using md5 hash (:HashFile)
|
26
|
+
* Key/value databases:
|
27
|
+
* Berkeley DB (:DBM)
|
28
|
+
* GDBM (:GDBM)
|
29
|
+
* SDBM (:SDBM)
|
30
|
+
* Redis (:Redis)
|
31
|
+
* Riak (:Riak)
|
32
|
+
* TokyoCabinet (:TokyoCabinet)
|
33
|
+
* Cassandra (:Cassandra)
|
34
|
+
* Document databases:
|
35
|
+
* CouchDB (:Couch)
|
36
|
+
* MongoDB (:Mongo)
|
37
|
+
* Other
|
38
|
+
* Fog cloud storage which supports Amazon S3, Rackspace, etc. (:Fog)
|
39
|
+
* Storage which doesn't store anything (:Null)
|
40
|
+
|
41
|
+
Special proxies:
|
42
|
+
* Juno::Expires to add expiration support to stores
|
43
|
+
* Juno::Stack to stack multiple stores
|
44
|
+
* Juno::Proxy basic proxy class
|
45
|
+
* Juno::Transformer transforms keys and values (Marshal, YAML, JSON, Base64, MD5, ...)
|
46
|
+
* Juno::Cache combine two stores, one as backend and one as cache (e.g. Juno::Adapters::File + Juno::Adapters::Memory)
|
32
47
|
|
33
48
|
The Juno API is purposely extremely similar to the Hash API. In order so support an
|
34
49
|
identical API across stores, it does not support iteration or partial matches.
|
35
50
|
|
36
|
-
|
37
|
-
|
51
|
+
Links
|
52
|
+
-----
|
38
53
|
|
39
|
-
|
54
|
+
* Source: <http://github.com/minad/juno>
|
55
|
+
* Bugs: <http://github.com/minad/juno/issues>
|
56
|
+
* API documentation:
|
57
|
+
* Latest Gem: <http://rubydoc.info/gems/juno/frames>
|
58
|
+
* GitHub master: <http://rubydoc.info/github/minad/juno/master/frames>
|
59
|
+
|
60
|
+
Store API
|
61
|
+
---------
|
62
|
+
|
63
|
+
~~~
|
40
64
|
#initialize(options) options differs per-store, and is used to set up the store
|
41
65
|
|
42
66
|
#[](key) retrieve a key. if the key is not available, return nil
|
43
67
|
|
68
|
+
#load(key, options = {}) retrieve a key. if the key is not available, return nil
|
69
|
+
|
44
70
|
#fetch(key, options = {}, &block) retrieve a key. if the key is not available, execute the
|
45
71
|
block and return its return value.
|
46
72
|
|
@@ -58,28 +84,60 @@ The API
|
|
58
84
|
#clear(options = {}) clear all keys in this store
|
59
85
|
|
60
86
|
#close close database connection
|
61
|
-
|
87
|
+
~~~
|
88
|
+
|
89
|
+
Creating a Store
|
90
|
+
----------------
|
91
|
+
|
92
|
+
There is a simple interface to create a store using `Juno.new`:
|
62
93
|
|
63
|
-
|
64
|
-
|
94
|
+
~~~ ruby
|
95
|
+
store = Juno.new(:Memcached, :server => 'localhost:11211')
|
96
|
+
~~~
|
65
97
|
|
66
|
-
|
98
|
+
If you want to have control over the proxies, you have to use `Juno.build`:
|
67
99
|
|
68
|
-
|
69
|
-
|
100
|
+
~~~ ruby
|
101
|
+
store = Juno.build do
|
102
|
+
# Adds expires proxy
|
103
|
+
use :Expires
|
104
|
+
# Transform key and value using Marshal
|
105
|
+
use :Transformer, :key => :marshal, :value => :marshal
|
106
|
+
# Memory backend
|
107
|
+
adapter :Memory
|
108
|
+
end
|
109
|
+
|
110
|
+
Expiration
|
111
|
+
----------
|
112
|
+
|
113
|
+
The Cassandra, Memcached and Redis backends supports expires values directly:
|
114
|
+
|
115
|
+
~~~ ruby
|
116
|
+
cache = Juno::Adapters::Memcached.new
|
70
117
|
# Expires in 10 seconds
|
71
118
|
cache.store(key, value, :expires => 10)
|
72
|
-
|
119
|
+
|
120
|
+
# Or using the builder...
|
121
|
+
cache = Juno.build do
|
122
|
+
adapter :Memcached
|
123
|
+
end
|
124
|
+
~~~
|
73
125
|
|
74
126
|
You can add the expires feature to other backends using the Expires proxy:
|
75
127
|
|
76
|
-
|
77
|
-
cache = Juno::Expires.new(Juno::File.new(...))
|
128
|
+
~~~ ruby
|
129
|
+
cache = Juno::Expires.new(Juno::Adapters::File.new(:dir => '...'))
|
78
130
|
cache.store(key, value, :expires => 10)
|
79
|
-
|
131
|
+
|
132
|
+
# Or using the builder...
|
133
|
+
cache = Juno.build do
|
134
|
+
use :Expires
|
135
|
+
adapter :File, :dir => '...'
|
136
|
+
end
|
137
|
+
~~~
|
80
138
|
|
81
139
|
Authors
|
82
|
-
|
140
|
+
-------
|
83
141
|
|
84
142
|
* Moneta originally by wycats
|
85
143
|
* Juno by Daniel Mendler
|
data/Rakefile
CHANGED
@@ -4,12 +4,30 @@ begin
|
|
4
4
|
rescue Exception
|
5
5
|
end
|
6
6
|
|
7
|
-
|
7
|
+
task :test => %w(test:parallel test:non_parallel)
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
# memcached and redis specs cannot be used in parallel
|
10
|
+
# because of flushing and namespace lacking in redis
|
11
|
+
|
12
|
+
namespace :test do
|
13
|
+
task :parallel do
|
14
|
+
if defined?(JRUBY_VERSION)
|
15
|
+
puts 'No tests executed in parallel in JRuby'
|
16
|
+
else
|
17
|
+
specs = Dir['spec/*_spec.rb'].reject {|s| s =~ /memcached|redis/ }
|
18
|
+
sh("parallel_rspec -m 15 #{specs.join(' ')}")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
task :non_parallel do
|
23
|
+
if defined?(JRUBY_VERSION)
|
24
|
+
# Run all tests in jruby non-parallel
|
25
|
+
sh('rspec spec/*_spec.rb')
|
26
|
+
else
|
27
|
+
specs = Dir['spec/*_spec.rb'].select {|s| s =~ /memcached|redis/ }
|
28
|
+
sh("rspec #{specs.join(' ')}")
|
29
|
+
end
|
30
|
+
end
|
13
31
|
end
|
14
32
|
|
15
33
|
task :default => :test
|
data/benchmarks/run.rb
CHANGED
@@ -34,25 +34,24 @@ class HackedArray < Array
|
|
34
34
|
end
|
35
35
|
|
36
36
|
stores = {
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
# 'Couch' => {:db => "couch_test"},
|
37
|
+
:Redis => { },
|
38
|
+
:MemcachedDalli => { :server => "localhost:11211", :namespace => 'juno_dalli' },
|
39
|
+
:MemcachedNative => { :server => "localhost:11211", :namespace => 'juno_native' },
|
40
|
+
#:MongoDB => { :host => 'localhost', :port => 27017, :db => 'juno_bench' },
|
41
|
+
:LocalMemCache => { :file => "bench.lmc" },
|
42
|
+
:DBM => { :file => "bench.dbm" },
|
43
|
+
:SDBM => { :file => "bench.sdbm" },
|
44
|
+
:GDBM => { :file => "bench.gdbm" },
|
45
|
+
:Sqlite => { :file => ":memory:" },
|
46
|
+
:Memory => { },
|
47
|
+
:YAML => { :file => "bench.yaml" },
|
48
|
+
:PStore => { :file => "bench.pstore" },
|
49
|
+
:File => { :dir => "bench.file" },
|
50
|
+
:HashFile => { :dir => "bench.hashfile" },
|
51
|
+
:DataMapper => { :setup => "sqlite3::memory:" },
|
52
|
+
:ActiveRecord => { :connection => { :adapter => 'sqlite3', :database => ':memory:' } },
|
53
|
+
:Sequel => { :db => "sqlite:/" },
|
54
|
+
# :Couch => {:db => "couch_test"},
|
56
55
|
}
|
57
56
|
|
58
57
|
stats, keys, data, errors, summary = {}, [], HackedArray.new, HackedArray.new, HackedArray.new
|
@@ -94,12 +93,10 @@ puts "Lenght Stats % 10i % 10i % 10i % 10i " % [vlen_min, vlen_max, vlen_ttl,
|
|
94
93
|
|
95
94
|
|
96
95
|
stores.each do |name, options|
|
97
|
-
cname = options.delete(:class_name) || name
|
98
96
|
puts "======================================================================"
|
99
97
|
puts name
|
100
98
|
puts "----------------------------------------------------------------------"
|
101
|
-
|
102
|
-
@cache = klass.new(options)
|
99
|
+
@cache = Juno.new(name, options)
|
103
100
|
stats[name] = {
|
104
101
|
:writes => [],
|
105
102
|
:reads => [],
|
data/juno.gemspec
CHANGED
@@ -16,7 +16,4 @@ Gem::Specification.new do |s|
|
|
16
16
|
s.homepage = 'http://github.com/minad/juno'
|
17
17
|
s.require_paths = ['lib']
|
18
18
|
s.summary = %{A unified interface to key/value stores, including MongoDB, Redis, Tokyo, and ActiveRecord}
|
19
|
-
|
20
|
-
s.add_development_dependency 'rake'
|
21
|
-
s.add_development_dependency 'minitest'
|
22
19
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
module Juno
|
4
|
+
module Adapters
|
5
|
+
class ActiveRecord < Base
|
6
|
+
def self.tables
|
7
|
+
@tables ||= {}
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :table
|
11
|
+
|
12
|
+
def initialize(options = {})
|
13
|
+
table = options[:table] || 'juno'
|
14
|
+
@table = self.class.tables[table] ||= begin
|
15
|
+
c = Class.new(::ActiveRecord::Base)
|
16
|
+
c.table_name = table
|
17
|
+
c
|
18
|
+
end
|
19
|
+
@table.establish_connection(options[:connection]) if options[:connection]
|
20
|
+
@table.connection.create_table @table.table_name do |t|
|
21
|
+
t.binary 'key', :primary => true
|
22
|
+
t.binary 'value'
|
23
|
+
end unless @table.table_exists?
|
24
|
+
end
|
25
|
+
|
26
|
+
def key?(key, options = {})
|
27
|
+
!!@table.find_by_key(key)
|
28
|
+
end
|
29
|
+
|
30
|
+
def load(key, options = {})
|
31
|
+
record = @table.find_by_key(key)
|
32
|
+
record ? record.value : nil
|
33
|
+
end
|
34
|
+
|
35
|
+
def delete(key, options = {})
|
36
|
+
record = @table.find_by_key(key)
|
37
|
+
if record
|
38
|
+
value = record.value
|
39
|
+
record.destroy
|
40
|
+
value
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def store(key, value, options = {})
|
45
|
+
record = @table.find_by_key(key)
|
46
|
+
record ||= @table.new(:key => key)
|
47
|
+
record.value = value
|
48
|
+
record.save!
|
49
|
+
value
|
50
|
+
end
|
51
|
+
|
52
|
+
def clear(options = {})
|
53
|
+
@table.delete_all
|
54
|
+
self
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# Copyright: 2011 TMX Credit
|
2
|
+
# Author: Potapov Sergey (aka Blake)
|
3
|
+
|
4
|
+
require 'cassandra'
|
5
|
+
|
6
|
+
module Juno
|
7
|
+
module Adapters
|
8
|
+
class Cassandra < Base
|
9
|
+
def initialize(options = {})
|
10
|
+
options[:keyspace] ||= 'Juno'
|
11
|
+
options[:host] ||= '127.0.0.1'
|
12
|
+
options[:port] ||= 9160
|
13
|
+
@column_family = options[:column_family] || :Juno
|
14
|
+
@client = ::Cassandra.new(options[:keyspace], "#{options[:host]}:#{options[:port]}")
|
15
|
+
end
|
16
|
+
|
17
|
+
def key?(key, options = {})
|
18
|
+
@client.exists?(@column_family, key)
|
19
|
+
end
|
20
|
+
|
21
|
+
def load(key, options = {})
|
22
|
+
value = @client.get(@column_family, key)
|
23
|
+
value ? value['value'] : nil
|
24
|
+
end
|
25
|
+
|
26
|
+
def delete(key, options = {})
|
27
|
+
if value = load(key, options)
|
28
|
+
@client.remove(@column_family, key)
|
29
|
+
value
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def store(key, value, options = {})
|
34
|
+
@client.insert(@column_family, key,
|
35
|
+
{'value' => value}, :ttl => options[:expires])
|
36
|
+
value
|
37
|
+
end
|
38
|
+
|
39
|
+
def clear(options = {})
|
40
|
+
@client.each_key(@column_family) do |key|
|
41
|
+
delete(key)
|
42
|
+
end
|
43
|
+
self
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'couchrest'
|
2
|
+
|
3
|
+
module Juno
|
4
|
+
module Adapters
|
5
|
+
class Couch < Base
|
6
|
+
def initialize(options = {})
|
7
|
+
@db = ::CouchRest.database!(options[:db])
|
8
|
+
end
|
9
|
+
|
10
|
+
def key?(key, options = {})
|
11
|
+
!!@db.get(key)
|
12
|
+
rescue RestClient::ResourceNotFound
|
13
|
+
false
|
14
|
+
end
|
15
|
+
|
16
|
+
def load(key, options = {})
|
17
|
+
@db.get(key)['data']
|
18
|
+
rescue RestClient::ResourceNotFound
|
19
|
+
nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def store(key, value, options = {})
|
23
|
+
@db.save_doc('_id' => key, 'data' => value)
|
24
|
+
value
|
25
|
+
rescue RestClient::RequestFailed
|
26
|
+
value
|
27
|
+
end
|
28
|
+
|
29
|
+
def delete(key, options = {})
|
30
|
+
value = @db.get(key)
|
31
|
+
@db.delete_doc('_id' => value['_id'], '_rev' => value['_rev'])
|
32
|
+
value['data']
|
33
|
+
rescue RestClient::ResourceNotFound
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
|
37
|
+
def clear(options = {})
|
38
|
+
@db.recreate!
|
39
|
+
self
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'dm-core'
|
2
|
+
require 'dm-migrations'
|
3
|
+
|
4
|
+
module Juno
|
5
|
+
module Adapters
|
6
|
+
class DataMapper < Base
|
7
|
+
class Store
|
8
|
+
include ::DataMapper::Resource
|
9
|
+
property :k, String, :key => true
|
10
|
+
property :v, Object, :lazy => false
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(options = {})
|
14
|
+
raise 'No option :setup specified' unless options[:setup]
|
15
|
+
@repository = options.delete(:repository) || :juno
|
16
|
+
Store.storage_names[@repository] = (options.delete(:table) || :juno).to_s
|
17
|
+
::DataMapper.setup(@repository, options[:setup])
|
18
|
+
context { Store.auto_upgrade! }
|
19
|
+
end
|
20
|
+
|
21
|
+
def key?(key, options = {})
|
22
|
+
context { !!Store.get(key) }
|
23
|
+
end
|
24
|
+
|
25
|
+
def load(key, options = {})
|
26
|
+
context do
|
27
|
+
record = Store.get(key)
|
28
|
+
record ? record.v : nil
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def store(key, value, options = {})
|
33
|
+
context do
|
34
|
+
record = Store.get(key)
|
35
|
+
if record
|
36
|
+
record.update(key, value)
|
37
|
+
else
|
38
|
+
Store.create(:k => key, :v => value)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
value
|
42
|
+
end
|
43
|
+
|
44
|
+
def delete(key, options = {})
|
45
|
+
context do
|
46
|
+
value = load(key, options)
|
47
|
+
Store.all(:k => key).destroy!
|
48
|
+
value
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def clear(options = {})
|
53
|
+
context { Store.all.destroy! }
|
54
|
+
self
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def context
|
60
|
+
::DataMapper.repository(@repository) { yield }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'dbm'
|
2
|
+
|
3
|
+
module Juno
|
4
|
+
module Adapters
|
5
|
+
class DBM < Memory
|
6
|
+
def initialize(options = {})
|
7
|
+
raise 'No option :file specified' unless options[:file]
|
8
|
+
@memory = ::DBM.new(options[:file])
|
9
|
+
end
|
10
|
+
|
11
|
+
def close
|
12
|
+
@memory.close
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module Juno
|
4
|
+
module Adapters
|
5
|
+
class File < Base
|
6
|
+
def initialize(options = {})
|
7
|
+
raise 'No option :dir specified' unless @dir = options[:dir]
|
8
|
+
FileUtils.mkpath(@dir)
|
9
|
+
raise "#{@dir} is not a dir" unless ::File.directory?(@dir)
|
10
|
+
end
|
11
|
+
|
12
|
+
def key?(key, options = {})
|
13
|
+
::File.exist?(store_path(key))
|
14
|
+
end
|
15
|
+
|
16
|
+
def load(key, options = {})
|
17
|
+
::File.read(store_path(key))
|
18
|
+
rescue Errno::ENOENT
|
19
|
+
end
|
20
|
+
|
21
|
+
def store(key, value, options = {})
|
22
|
+
path = store_path(key)
|
23
|
+
temp_file = ::File.join(@dir, "value-#{$$}-#{Thread.current.object_id}")
|
24
|
+
FileUtils.mkpath(::File.dirname(path))
|
25
|
+
::File.open(temp_file, 'wb') {|file| file.write(value) }
|
26
|
+
::File.unlink(path) if ::File.exist?(path)
|
27
|
+
::File.rename(temp_file, path)
|
28
|
+
value
|
29
|
+
rescue Errno::ENOENT
|
30
|
+
::File.unlink(temp_file) rescue nil
|
31
|
+
value
|
32
|
+
end
|
33
|
+
|
34
|
+
def delete(key, options = {})
|
35
|
+
value = load(key, options)
|
36
|
+
::File.unlink(store_path(key))
|
37
|
+
value
|
38
|
+
rescue Errno::ENOENT
|
39
|
+
end
|
40
|
+
|
41
|
+
def clear(options = {})
|
42
|
+
temp_dir = "#{@dir}-#{$$}-#{Thread.current.object_id}"
|
43
|
+
::File.rename(@dir, temp_dir)
|
44
|
+
FileUtils.mkpath(@dir)
|
45
|
+
FileUtils.rm_rf(temp_dir)
|
46
|
+
self
|
47
|
+
rescue Errno::ENOENT
|
48
|
+
self
|
49
|
+
end
|
50
|
+
|
51
|
+
protected
|
52
|
+
|
53
|
+
def store_path(key)
|
54
|
+
::File.join(@dir, key)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'fog'
|
2
|
+
|
3
|
+
module Juno
|
4
|
+
module Adapters
|
5
|
+
class Fog < Base
|
6
|
+
def initialize(options = {})
|
7
|
+
raise 'No option :dir specified' unless dir = options.delete(:dir)
|
8
|
+
storage = ::Fog::Storage.new(options)
|
9
|
+
@directory = storage.directories.create(:key => dir)
|
10
|
+
end
|
11
|
+
|
12
|
+
def key?(key, options = {})
|
13
|
+
!!@directory.files.head(key)
|
14
|
+
end
|
15
|
+
|
16
|
+
def load(key, options = {})
|
17
|
+
value = @directory.files.get(key)
|
18
|
+
value ? value.body : nil
|
19
|
+
end
|
20
|
+
|
21
|
+
def delete(key, options = {})
|
22
|
+
if value = @directory.files.get(key)
|
23
|
+
body = value.body
|
24
|
+
value.destroy
|
25
|
+
body
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def store(key, value, options = {})
|
30
|
+
@directory.files.create(:key => key, :body => value)
|
31
|
+
value
|
32
|
+
end
|
33
|
+
|
34
|
+
def clear(options = {})
|
35
|
+
@directory.files.all.each do |file|
|
36
|
+
file.destroy
|
37
|
+
end
|
38
|
+
self
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'gdbm'
|
2
|
+
|
3
|
+
module Juno
|
4
|
+
module Adapters
|
5
|
+
class GDBM < Memory
|
6
|
+
def initialize(options = {})
|
7
|
+
raise 'No option :file specified' unless options[:file]
|
8
|
+
@memory = ::GDBM.new(options[:file])
|
9
|
+
end
|
10
|
+
|
11
|
+
def close
|
12
|
+
@memory.close
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|