juno 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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