juno 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (161) hide show
  1. data/.gitignore +2 -1
  2. data/.travis.yml +6 -0
  3. data/Gemfile +16 -9
  4. data/README.md +92 -34
  5. data/Rakefile +23 -5
  6. data/benchmarks/run.rb +19 -22
  7. data/juno.gemspec +0 -3
  8. data/lib/juno/adapters/activerecord.rb +58 -0
  9. data/lib/juno/adapters/cassandra.rb +47 -0
  10. data/lib/juno/adapters/couch.rb +43 -0
  11. data/lib/juno/adapters/datamapper.rb +64 -0
  12. data/lib/juno/adapters/dbm.rb +17 -0
  13. data/lib/juno/adapters/file.rb +58 -0
  14. data/lib/juno/adapters/fog.rb +42 -0
  15. data/lib/juno/adapters/gdbm.rb +17 -0
  16. data/lib/juno/adapters/localmemcache.rb +18 -0
  17. data/lib/juno/adapters/memcached.rb +11 -0
  18. data/lib/juno/adapters/memcached_dalli.rb +46 -0
  19. data/lib/juno/adapters/memcached_native.rb +47 -0
  20. data/lib/juno/adapters/memory.rb +30 -0
  21. data/lib/juno/adapters/mongo.rb +43 -0
  22. data/lib/juno/adapters/null.rb +28 -0
  23. data/lib/juno/adapters/pstore.rb +51 -0
  24. data/lib/juno/adapters/redis.rb +43 -0
  25. data/lib/juno/adapters/riak.rb +46 -0
  26. data/lib/juno/adapters/sdbm.rb +27 -0
  27. data/lib/juno/adapters/sequel.rb +50 -0
  28. data/lib/juno/adapters/sqlite.rb +52 -0
  29. data/lib/juno/adapters/tokyocabinet.rb +33 -0
  30. data/lib/juno/adapters/yaml.rb +13 -0
  31. data/lib/juno/base.rb +11 -89
  32. data/lib/juno/builder.rb +30 -0
  33. data/lib/juno/cache.rb +64 -0
  34. data/lib/juno/expires.rb +6 -10
  35. data/lib/juno/proxy.rb +62 -3
  36. data/lib/juno/stack.rb +27 -11
  37. data/lib/juno/transformer.rb +106 -0
  38. data/lib/juno/version.rb +1 -1
  39. data/lib/juno.rb +81 -29
  40. data/spec/adapter_activerecord_spec.rb +41 -0
  41. data/spec/adapter_cassandra_spec.rb +27 -0
  42. data/spec/adapter_couch_spec.rb +27 -0
  43. data/spec/adapter_datamapper_spec.rb +61 -0
  44. data/spec/adapter_dbm_spec.rb +27 -0
  45. data/spec/adapter_file_spec.rb +27 -0
  46. data/spec/adapter_fog_spec.rb +35 -0
  47. data/spec/adapter_gdbm_spec.rb +27 -0
  48. data/spec/adapter_localmemcache_spec.rb +27 -0
  49. data/spec/adapter_memcached_dalli_spec.rb +28 -0
  50. data/spec/adapter_memcached_native_spec.rb +28 -0
  51. data/spec/adapter_memcached_spec.rb +28 -0
  52. data/spec/adapter_memory_spec.rb +42 -0
  53. data/spec/adapter_mongo_spec.rb +27 -0
  54. data/spec/adapter_pstore_spec.rb +30 -0
  55. data/spec/adapter_redis_spec.rb +28 -0
  56. data/spec/adapter_riak_spec.rb +31 -0
  57. data/spec/adapter_sdbm_spec.rb +27 -0
  58. data/spec/adapter_sequel_spec.rb +27 -0
  59. data/spec/adapter_sqlite_spec.rb +27 -0
  60. data/spec/adapter_tokyocabinet_spec.rb +27 -0
  61. data/spec/adapter_yaml_spec.rb +30 -0
  62. data/spec/cache_file_memory_spec.rb +50 -0
  63. data/spec/cache_memory_null_spec.rb +39 -0
  64. data/spec/expires_file_spec.rb +82 -0
  65. data/spec/expires_memory_spec.rb +59 -0
  66. data/spec/generate.rb +736 -0
  67. data/spec/helper.rb +39 -0
  68. data/spec/junospecs.rb +1540 -0
  69. data/spec/null_adapter_spec.rb +33 -0
  70. data/spec/proxy_expires_memory_spec.rb +63 -0
  71. data/spec/proxy_redis_spec.rb +38 -0
  72. data/spec/simple_activerecord_spec.rb +52 -0
  73. data/spec/simple_cassandra_spec.rb +53 -0
  74. data/spec/simple_couch_spec.rb +52 -0
  75. data/spec/simple_datamapper_spec.rb +54 -0
  76. data/spec/simple_datamapper_with_repository_spec.rb +54 -0
  77. data/spec/simple_dbm_spec.rb +52 -0
  78. data/spec/simple_file_spec.rb +52 -0
  79. data/spec/simple_fog_spec.rb +60 -0
  80. data/spec/simple_gdbm_spec.rb +52 -0
  81. data/spec/simple_hashfile_spec.rb +52 -0
  82. data/spec/simple_localmemcache_spec.rb +52 -0
  83. data/spec/simple_memcached_dalli_spec.rb +53 -0
  84. data/spec/simple_memcached_native_spec.rb +53 -0
  85. data/spec/simple_memcached_spec.rb +53 -0
  86. data/spec/simple_memory_spec.rb +52 -0
  87. data/spec/simple_mongo_spec.rb +52 -0
  88. data/spec/simple_null_spec.rb +43 -0
  89. data/spec/simple_pstore_spec.rb +52 -0
  90. data/spec/simple_redis_spec.rb +53 -0
  91. data/spec/simple_riak_spec.rb +56 -0
  92. data/spec/simple_sdbm_spec.rb +52 -0
  93. data/spec/simple_sequel_spec.rb +52 -0
  94. data/spec/simple_sqlite_spec.rb +52 -0
  95. data/spec/simple_tokyocabinet_spec.rb +52 -0
  96. data/spec/simple_yaml_spec.rb +52 -0
  97. data/spec/stack_file_memory_spec.rb +43 -0
  98. data/spec/stack_memory_file_spec.rb +42 -0
  99. data/spec/transformer_bson_spec.rb +44 -0
  100. data/spec/transformer_json_spec.rb +44 -0
  101. data/spec/transformer_marshal_base64_spec.rb +60 -0
  102. data/spec/transformer_marshal_escape_spec.rb +60 -0
  103. data/spec/transformer_marshal_md5_spec.rb +60 -0
  104. data/spec/transformer_marshal_md5_spread_spec.rb +60 -0
  105. data/spec/transformer_msgpack_spec.rb +44 -0
  106. data/spec/transformer_yaml_spec.rb +59 -0
  107. metadata +164 -108
  108. data/lib/juno/activerecord.rb +0 -55
  109. data/lib/juno/cassandra.rb +0 -45
  110. data/lib/juno/couch.rb +0 -43
  111. data/lib/juno/datamapper.rb +0 -63
  112. data/lib/juno/dbm.rb +0 -15
  113. data/lib/juno/file.rb +0 -62
  114. data/lib/juno/fog.rb +0 -48
  115. data/lib/juno/gdbm.rb +0 -15
  116. data/lib/juno/hashfile.rb +0 -12
  117. data/lib/juno/localmemcache.rb +0 -16
  118. data/lib/juno/memcached.rb +0 -7
  119. data/lib/juno/memcached_dalli.rb +0 -55
  120. data/lib/juno/memcached_native.rb +0 -56
  121. data/lib/juno/memory.rb +0 -7
  122. data/lib/juno/mongodb.rb +0 -43
  123. data/lib/juno/null.rb +0 -23
  124. data/lib/juno/pstore.rb +0 -49
  125. data/lib/juno/redis.rb +0 -46
  126. data/lib/juno/riak.rb +0 -45
  127. data/lib/juno/sdbm.rb +0 -15
  128. data/lib/juno/sequel.rb +0 -48
  129. data/lib/juno/sqlite.rb +0 -50
  130. data/lib/juno/tokyocabinet.rb +0 -36
  131. data/lib/juno/yaml.rb +0 -9
  132. data/test/helper.rb +0 -212
  133. data/test/test_activerecord.rb +0 -33
  134. data/test/test_cassandra.rb +0 -13
  135. data/test/test_couch.rb +0 -13
  136. data/test/test_datamapper.rb +0 -64
  137. data/test/test_dbm.rb +0 -13
  138. data/test/test_expires.rb +0 -9
  139. data/test/test_file.rb +0 -9
  140. data/test/test_fog.rb +0 -17
  141. data/test/test_gdbm.rb +0 -13
  142. data/test/test_hashfile.rb +0 -9
  143. data/test/test_localmemcache.rb +0 -13
  144. data/test/test_memcached.rb +0 -14
  145. data/test/test_memcached_dalli.rb +0 -14
  146. data/test/test_memcached_native.rb +0 -14
  147. data/test/test_memory.rb +0 -9
  148. data/test/test_mongodb.rb +0 -13
  149. data/test/test_null.rb +0 -9
  150. data/test/test_proxy.rb +0 -9
  151. data/test/test_pstore.rb +0 -9
  152. data/test/test_redis.rb +0 -13
  153. data/test/test_riak.rb +0 -13
  154. data/test/test_sdbm.rb +0 -13
  155. data/test/test_sequel.rb +0 -13
  156. data/test/test_sqlite.rb +0 -13
  157. data/test/test_stack.rb +0 -10
  158. data/test/test_tokyocabinet.rb +0 -13
  159. data/test/test_yaml.rb +0 -9
  160. data/unsupported/test_tokyotyrant.rb +0 -13
  161. data/unsupported/tokyotyrant.rb +0 -29
data/.gitignore CHANGED
@@ -1,5 +1,6 @@
1
- test/tmp
1
+ spec/tmp
2
2
  *~
3
3
  *.swp
4
4
  *.rdb
5
5
  benchmarks/bench.*
6
+ Gemfile.lock
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
- if RUBY_VERSION > '1.9'
5
- # HACK - Juno::DataMapper and CouchRest don't work currently on 1.8
6
- gem 'datamapper'
7
- gem 'dm-sqlite-adapter'
8
- gem 'couchrest'
9
- end
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 'json' # Ripple/Riak needs json
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
- * File Store
13
- * Memcached store (memcached and dalli)
14
- * In-memory store
15
- * DataMapper
16
- * BerkeleyDB (dbm)
17
- * GDBM
18
- * SDBM
19
- * Redis
20
- * Riak
21
- * TokyoCabinet
22
- * CouchDB
23
- * MongoDB
24
- * ActiveRecord
25
- * YAML store
26
- * PStore
27
- * LocalMemCache
28
- * Sequel
29
- * Sqlite3
30
- * Fog cloud storage (Amazon S3, Rackspace, ...)
31
- * Cassandra
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
- The API
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
- Proxy store & Expiry
64
- ====================
94
+ ~~~ ruby
95
+ store = Juno.new(:Memcached, :server => 'localhost:11211')
96
+ ~~~
65
97
 
66
- The memcached and redis backends supports expires values directly:
98
+ If you want to have control over the proxies, you have to use `Juno.build`:
67
99
 
68
- ```ruby
69
- cache = Juno::Memcached.new
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
- ```ruby
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
- require 'rake/testtask'
7
+ task :test => %w(test:parallel test:non_parallel)
8
8
 
9
- Rake::TestTask.new(:test) do |t|
10
- t.libs << 'lib' << 'test'
11
- t.test_files = FileList['test/test_*.rb']
12
- t.verbose = true
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
- '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' => { :db => "sqlite:/" },
53
- 'ActiveRecord' => { :connection => { :adapter => 'sqlite3', :database => ':memory:' } },
54
- 'Sequel' => { :db => "sqlite:/" },
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
- klass = Juno.const_get(cname)
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