juno 0.1.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.
Files changed (67) hide show
  1. data/.gitignore +4 -0
  2. data/.travis.yml +25 -0
  3. data/Gemfile +19 -0
  4. data/LICENSE +20 -0
  5. data/README.md +83 -0
  6. data/Rakefile +15 -0
  7. data/SPEC.md +95 -0
  8. data/juno.gemspec +22 -0
  9. data/lib/juno.rb +31 -0
  10. data/lib/juno/activerecord.rb +58 -0
  11. data/lib/juno/base.rb +113 -0
  12. data/lib/juno/couch.rb +43 -0
  13. data/lib/juno/datamapper.rb +63 -0
  14. data/lib/juno/dbm.rb +15 -0
  15. data/lib/juno/expires.rb +45 -0
  16. data/lib/juno/file.rb +62 -0
  17. data/lib/juno/gdbm.rb +15 -0
  18. data/lib/juno/hashfile.rb +12 -0
  19. data/lib/juno/localmemcache.rb +16 -0
  20. data/lib/juno/memcached.rb +7 -0
  21. data/lib/juno/memcached_dalli.rb +55 -0
  22. data/lib/juno/memcached_native.rb +56 -0
  23. data/lib/juno/memory.rb +7 -0
  24. data/lib/juno/mongodb.rb +43 -0
  25. data/lib/juno/proxy.rb +5 -0
  26. data/lib/juno/pstore.rb +49 -0
  27. data/lib/juno/redis.rb +34 -0
  28. data/lib/juno/riak.rb +45 -0
  29. data/lib/juno/sdbm.rb +15 -0
  30. data/lib/juno/sequel.rb +51 -0
  31. data/lib/juno/sqlite.rb +50 -0
  32. data/lib/juno/tokyocabinet.rb +36 -0
  33. data/lib/juno/version.rb +3 -0
  34. data/lib/juno/yaml.rb +9 -0
  35. data/test/helper.rb +182 -0
  36. data/test/test_active_record.rb +36 -0
  37. data/test/test_couch.rb +13 -0
  38. data/test/test_datamapper.rb +64 -0
  39. data/test/test_dbm.rb +13 -0
  40. data/test/test_expires.rb +10 -0
  41. data/test/test_file.rb +9 -0
  42. data/test/test_gdbm.rb +13 -0
  43. data/test/test_hashfile.rb +9 -0
  44. data/test/test_localmemcache.rb +13 -0
  45. data/test/test_memcached.rb +15 -0
  46. data/test/test_memcached_dalli.rb +15 -0
  47. data/test/test_memcached_native.rb +15 -0
  48. data/test/test_memory.rb +9 -0
  49. data/test/test_mongodb.rb +13 -0
  50. data/test/test_proxy.rb +9 -0
  51. data/test/test_pstore.rb +9 -0
  52. data/test/test_redis.rb +13 -0
  53. data/test/test_riak.rb +13 -0
  54. data/test/test_sdbm.rb +13 -0
  55. data/test/test_sequel.rb +13 -0
  56. data/test/test_sqlite.rb +13 -0
  57. data/test/test_tokyocabinet.rb +13 -0
  58. data/test/test_yaml.rb +9 -0
  59. data/unsupported/benchmarks.rb +234 -0
  60. data/unsupported/cassandra.rb +45 -0
  61. data/unsupported/fog.rb +60 -0
  62. data/unsupported/test_cassandra.rb +13 -0
  63. data/unsupported/test_rackspace.rb +15 -0
  64. data/unsupported/test_s3.rb +15 -0
  65. data/unsupported/test_tokyotyrant.rb +13 -0
  66. data/unsupported/tokyotyrant.rb +29 -0
  67. metadata +165 -0
@@ -0,0 +1,43 @@
1
+ require 'couchrest'
2
+
3
+ module Juno
4
+ class Couch < Base
5
+ def initialize(options = {})
6
+ @db = ::CouchRest.database!(options[:db])
7
+ end
8
+
9
+ def key?(key, options = {})
10
+ !!self[key_for(key)]
11
+ rescue RestClient::ResourceNotFound
12
+ false
13
+ end
14
+
15
+ def [](key)
16
+ deserialize(@db.get(key_for(key))['data'])
17
+ rescue RestClient::ResourceNotFound
18
+ nil
19
+ end
20
+
21
+ def store(key, value, options = {})
22
+ @db.save_doc('_id' => key_for(key), :data => serialize(value))
23
+ value
24
+ rescue RestClient::RequestFailed
25
+ value
26
+ end
27
+
28
+ def delete(key, options = {})
29
+ value = @db.get(key_for(key))
30
+ if value
31
+ @db.delete_doc({'_id' => value['_id'], '_rev' => value['_rev']}) if value
32
+ deserialize(value['data'])
33
+ end
34
+ rescue RestClient::ResourceNotFound
35
+ nil
36
+ end
37
+
38
+ def clear(options = {})
39
+ @db.recreate!
40
+ nil
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,63 @@
1
+ require 'dm-core'
2
+ require 'dm-migrations'
3
+
4
+ module Juno
5
+ class DataMapper < Base
6
+ class Store
7
+ include ::DataMapper::Resource
8
+ property :k, String, :key => true
9
+ property :v, Object, :lazy => false
10
+ end
11
+
12
+ def initialize(options = {})
13
+ raise 'No option :setup specified' unless options[:setup]
14
+ @repository = options.delete(:repository) || :juno
15
+ Store.storage_names[@repository] = options.delete(:table) || :juno
16
+ ::DataMapper.setup(@repository, options[:setup])
17
+ context { Store.auto_upgrade! }
18
+ end
19
+
20
+ def key?(key, options = {})
21
+ context { !!Store.get(key_for(key)) }
22
+ end
23
+
24
+ def [](key)
25
+ context do
26
+ record = Store.get(key_for(key))
27
+ record ? record.v : nil
28
+ end
29
+ end
30
+
31
+ def store(key, value, options = {})
32
+ key = key_for(key)
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 = self[key]
47
+ Store.all(:k => key_for(key)).destroy!
48
+ value
49
+ end
50
+ end
51
+
52
+ def clear(options = {})
53
+ context { Store.all.destroy! }
54
+ nil
55
+ end
56
+
57
+ private
58
+
59
+ def context
60
+ ::DataMapper.repository(@repository) { yield }
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,15 @@
1
+ require 'dbm'
2
+
3
+ module Juno
4
+ class DBM < Base
5
+ def initialize(options = {})
6
+ raise 'No option :file specified' unless options[:file]
7
+ @store = ::DBM.new(options[:file])
8
+ end
9
+
10
+ def close
11
+ @store.close
12
+ nil
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,45 @@
1
+ module Juno
2
+ class Expires < Proxy
3
+ def key?(key, options = {})
4
+ !!self[key]
5
+ end
6
+
7
+ def fetch(key, value = nil, options = {}, &block)
8
+ result = check_expired(key, super(key, value, options, &block))
9
+ if result && options.include?(:expires)
10
+ store(key, result, options)
11
+ else
12
+ result
13
+ end
14
+ end
15
+
16
+ def [](key)
17
+ check_expired(key, super(key))
18
+ end
19
+
20
+ def store(key, value, options = {})
21
+ if expires = options.delete(:expires)
22
+ super(key, [value, Time.now.to_i + expires].compact, options)
23
+ else
24
+ super(key, [value], options)
25
+ end
26
+ value
27
+ end
28
+
29
+ def delete(key, options = {})
30
+ check_expired(key, super, false)
31
+ end
32
+
33
+ protected
34
+
35
+ def check_expired(key, value, delete_expired = true)
36
+ value, expires = value
37
+ if expires && Time.now.to_i > expires
38
+ delete(key) if delete_expired
39
+ nil
40
+ else
41
+ value
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,62 @@
1
+ require 'fileutils'
2
+
3
+ module Juno
4
+ class File < Base
5
+ def initialize(options = {})
6
+ raise 'No option :dir specified' unless @dir = options[:dir]
7
+ FileUtils.mkpath(@dir)
8
+ raise "#{@dir} is not a dir" unless ::File.directory?(@dir)
9
+ end
10
+
11
+ def key?(key, options = {})
12
+ ::File.exist?(store_path(key))
13
+ end
14
+
15
+ def [](key)
16
+ deserialize(::File.read(store_path(key)))
17
+ rescue Errno::ENOENT
18
+ end
19
+
20
+ def store(key, value, options = {})
21
+ path = store_path(key)
22
+ temp_file = ::File.join(@dir, "value-#{$$}-#{Thread.current.object_id}")
23
+ FileUtils.mkpath(::File.dirname(path))
24
+ ::File.open(temp_file, 'wb') {|file| file.write(serialize(value)) }
25
+ ::File.unlink(path) if ::File.exist?(path)
26
+ ::File.rename(temp_file, path)
27
+ value
28
+ rescue Errno::ENOENT
29
+ ::File.unlink(temp_file) rescue nil
30
+ value
31
+ end
32
+
33
+ def delete(key, options = {})
34
+ value = self[key]
35
+ ::File.unlink(store_path(key))
36
+ value
37
+ rescue Errno::ENOENT
38
+ end
39
+
40
+ def clear(options = {})
41
+ temp_dir = "#{@dir}-#{$$}-#{Thread.current.object_id}"
42
+ ::File.rename(@dir, temp_dir)
43
+ FileUtils.mkpath(@dir)
44
+ FileUtils.rm_rf(temp_dir)
45
+ nil
46
+ rescue Errno::ENOENT
47
+ nil
48
+ end
49
+
50
+ protected
51
+
52
+ def escape(s)
53
+ s.gsub(/[^a-zA-Z0-9_-]+/) do
54
+ '%' + $&.unpack('H2' * $&.bytesize).join('%').upcase
55
+ end
56
+ end
57
+
58
+ def store_path(key)
59
+ ::File.join(@dir, escape(key_for(key)))
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,15 @@
1
+ require 'gdbm'
2
+
3
+ module Juno
4
+ class GDBM < Base
5
+ def initialize(options = {})
6
+ raise 'No option :file specified' unless options[:file]
7
+ @store = ::GDBM.new(options[:file])
8
+ end
9
+
10
+ def close
11
+ @store.close
12
+ nil
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,12 @@
1
+ require 'digest/md5'
2
+
3
+ module Juno
4
+ class HashFile < Juno::File
5
+ protected
6
+
7
+ def store_path(key)
8
+ hash = Digest::MD5.hexdigest(key_for(key))
9
+ ::File.join(@dir, hash[0..1], hash[2..-1])
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,16 @@
1
+ require 'localmemcache'
2
+
3
+ module Juno
4
+ class LocalMemCache < Base
5
+ def initialize(options = {})
6
+ raise 'No option :file specified' unless options[:file]
7
+ @store = ::LocalMemCache.new(:filename => options[:file])
8
+ end
9
+
10
+ def delete(key, options = {})
11
+ value = self[key]
12
+ @store.delete(key_for(key))
13
+ value
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,7 @@
1
+ module Juno
2
+ begin
3
+ Memcached = MemcachedNative
4
+ rescue LoadError
5
+ Memcached = MemcachedDalli
6
+ end
7
+ end
@@ -0,0 +1,55 @@
1
+ require 'dalli'
2
+
3
+ module Juno
4
+ class MemcachedDalli < Base
5
+ def initialize(options = {})
6
+ server = options.delete(:server) || 'localhost:11211'
7
+ @cache = ::Dalli::Client.new(server, options)
8
+ end
9
+
10
+ def key?(key, options = {})
11
+ !!@cache.get(key_for(key))
12
+ end
13
+
14
+ def fetch(key, value = nil, options = {})
15
+ result = super
16
+ if result && options.include?(:expires)
17
+ store(key, result, options)
18
+ else
19
+ result
20
+ end
21
+ end
22
+
23
+ def [](key)
24
+ deserialize(@cache.get(key_for(key)))
25
+ end
26
+
27
+ def store(key, value, options = {})
28
+ @cache.set(key_for(key), serialize(value), options[:expires])
29
+ value
30
+ end
31
+
32
+ def delete(key, options = {})
33
+ key = key_for(key)
34
+ value = deserialize(@cache.get(key))
35
+ @cache.delete(key)
36
+ value
37
+ end
38
+
39
+ def clear(options = {})
40
+ @cache.flush_all
41
+ nil
42
+ end
43
+
44
+ def close
45
+ @cache.close
46
+ nil
47
+ end
48
+
49
+ private
50
+
51
+ def key_for(key)
52
+ [super].pack('m').strip
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,56 @@
1
+ require 'memcached'
2
+
3
+ module Juno
4
+ class MemcachedNative < Base
5
+ def initialize(options = {})
6
+ server = options.delete(:server) || 'localhost:11211'
7
+ @cache = ::Memcached.new(server, options)
8
+ end
9
+
10
+ def key?(key, options = {})
11
+ @cache.get(key_for(key), false)
12
+ true
13
+ rescue ::Memcached::NotFound
14
+ false
15
+ end
16
+
17
+ def fetch(key, value = nil, options = {})
18
+ result = super
19
+ if result && options.include?(:expires)
20
+ store(key, result, options)
21
+ else
22
+ result
23
+ end
24
+ end
25
+
26
+ def [](key)
27
+ deserialize(@cache.get(key_for(key), false))
28
+ rescue ::Memcached::NotFound
29
+ end
30
+
31
+ def delete(key, options = {})
32
+ key = key_for(key)
33
+ value = deserialize(@cache.get(key, false))
34
+ @cache.delete(key)
35
+ value
36
+ rescue ::Memcached::NotFound
37
+ end
38
+
39
+ def store(key, value, options = {})
40
+ ttl = options[:expires] || ::Memcached::DEFAULTS[:default_ttl]
41
+ @cache.set(key_for(key), serialize(value), ttl, false)
42
+ value
43
+ end
44
+
45
+ def clear(options = {})
46
+ @cache.flush
47
+ nil
48
+ end
49
+
50
+ private
51
+
52
+ def key_for(key)
53
+ [super].pack('m').strip
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,7 @@
1
+ module Juno
2
+ class Memory < Base
3
+ def initialize(options = {})
4
+ @store = {}
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,43 @@
1
+ require 'mongo'
2
+ require 'uri'
3
+
4
+ module Juno
5
+ class MongoDB < 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
+ @store = connection.db(db).collection(collection)
13
+ end
14
+
15
+ def key?(key, options = {})
16
+ !!self[key]
17
+ end
18
+
19
+ def [](key)
20
+ value = @store.find_one('_id' => key_for(key))
21
+ value ? deserialize(value['data']) : nil
22
+ end
23
+
24
+ def delete(key, options = {})
25
+ value = self[key]
26
+ @store.remove('_id' => key_for(key)) if value
27
+ value
28
+ end
29
+
30
+ def store(key, value, options = {})
31
+ key = key_for(key)
32
+ @store.update({ '_id' => key },
33
+ { '_id' => key, 'data' => serialize(value) },
34
+ { :upsert => true })
35
+ value
36
+ end
37
+
38
+ def clear(options = {})
39
+ @store.remove
40
+ nil
41
+ end
42
+ end
43
+ end