juno 0.1.1 → 0.2.0
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 +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
|