moneta-splattael 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Yehuda Katz
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,56 @@
1
+ Moneta: A unified interface for key/value stores
2
+ ================================================
3
+
4
+ Moneta provides a standard interface for interacting with various kinds of key/value stores.
5
+
6
+ Out of the box, it supports:
7
+
8
+ * File store for xattr
9
+ * Basic File Store
10
+ * Memcache store
11
+ * In-memory store
12
+ * The xattrs in a file system
13
+ * DataMapper
14
+ * S3
15
+ * Berkeley DB
16
+ * Redis
17
+ * SDBM
18
+ * Tokyo
19
+ * CouchDB
20
+
21
+ All stores support key expiration, but only memcache supports it natively. All other stores
22
+ emulate expiration.
23
+
24
+ The Moneta API is purposely extremely similar to the Hash API. In order so support an
25
+ identical API across stores, it does not support iteration or partial matches, but that
26
+ might come in a future release.
27
+
28
+ The API:
29
+
30
+ #initialize(options):: options differs per-store, and is used to set up the store
31
+
32
+ #[](key):: retrieve a key. if the key is not available, return nil
33
+
34
+ #fetch(key, &block):: retrieve a key. if the key is not available, execute the
35
+ block and return its return value.
36
+
37
+ #fetch(key, value) retrieve a key. if the key is not available, return the value
38
+
39
+ #[]=(key, value):: set a value for a key. if the key is already used, clobber it.
40
+ keys set using []= will never expire
41
+
42
+ #delete(key):: delete the key from the store and return the current value
43
+
44
+ #key?(key):: true if the key exists, false if it does not
45
+
46
+ #has_key?(key):: alias for key?
47
+
48
+ #store(key, value, options):: same as []=, but you can supply an :expires_in option,
49
+ which will specify a number of seconds before the key
50
+ should expire. In order to support the same features
51
+ across all stores, only full seconds are supported
52
+
53
+ #update_key(key, options):: updates an existing key with a new :expires_in option.
54
+ if the key has already expired, it will not be updated.
55
+
56
+ #clear:: clear all keys in this store
data/Rakefile ADDED
@@ -0,0 +1,60 @@
1
+ require 'rubygems'
2
+ require 'rubygems/package_task'
3
+ require 'rubygems/specification'
4
+ require 'rspec/core/rake_task'
5
+ require 'date'
6
+
7
+ GEM = "moneta-splattael"
8
+ GEM_VERSION = "0.7.0"
9
+ AUTHOR = "Yehuda Katz"
10
+ EMAIL = "wycats@gmail.com"
11
+ HOMEPAGE = "http://www.yehudakatz.com"
12
+ SUMMARY = "A unified interface to key/value stores (modified version!)"
13
+
14
+ spec = Gem::Specification.new do |s|
15
+ s.name = GEM
16
+ s.version = GEM_VERSION
17
+ s.platform = Gem::Platform::RUBY
18
+ s.has_rdoc = true
19
+ s.extra_rdoc_files = ["README", "LICENSE", 'TODO']
20
+ s.summary = SUMMARY
21
+ s.description = s.summary
22
+ s.author = AUTHOR
23
+ s.email = EMAIL
24
+ s.homepage = HOMEPAGE
25
+
26
+ # Uncomment this to add a dependency
27
+ # s.add_dependency "foo"
28
+
29
+ s.require_path = 'lib'
30
+ s.autorequire = GEM
31
+ s.files = %w(LICENSE README Rakefile TODO) + Dir.glob("{lib,specs}/**/*")
32
+ end
33
+
34
+ Gem::PackageTask.new(spec) do |pkg|
35
+ pkg.gem_spec = spec
36
+ end
37
+
38
+ desc "install the gem locally"
39
+ task :install => [:package] do
40
+ sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION}}
41
+ end
42
+
43
+ desc "create a gemspec file"
44
+ task :make_spec do
45
+ File.open("#{GEM}.gemspec", "w") do |file|
46
+ file.puts spec.to_ruby
47
+ end
48
+ end
49
+
50
+ desc "Run all examples (or a specific spec with TASK=xxxx)"
51
+ RSpec::Core::RakeTask.new('spec') do |t|
52
+ t.rspec_opts = ["-cfs"]
53
+ t.pattern = begin
54
+ if ENV["TASK"]
55
+ ENV["TASK"].split(',').map { |task| "spec/**/#{task}_spec.rb" }
56
+ else
57
+ FileList['spec/**/*_spec.rb']
58
+ end
59
+ end
60
+ end
data/TODO ADDED
@@ -0,0 +1,4 @@
1
+ TODO:
2
+ Fix LICENSE with your name
3
+ Fix Rakefile with your name and contact info
4
+ Add your code to lib/<%= name %>.rb
@@ -0,0 +1,84 @@
1
+ #
2
+ # Basic File Store
3
+ # by Hampton Catlin
4
+ #
5
+ # This cache simply uses a directory that it creates
6
+ # and manages to keep your file stores.
7
+ #
8
+ # Specify :skip_expires => true if you aren't using
9
+ # expiration as this will slightly decrease your file size
10
+ # and memory footprint of the library
11
+ #
12
+ # You can optionally also specify a :namespace
13
+ # option that will create a subfolder.
14
+ #
15
+
16
+
17
+ require 'fileutils'
18
+ require "moneta"
19
+
20
+ module Moneta
21
+ module Adapters
22
+ class BasicFile
23
+ include Moneta::Defaults
24
+
25
+ def initialize(options = {})
26
+ @namespace = options[:namespace]
27
+ @directory = ::File.join(options[:path], @namespace.to_s)
28
+
29
+ ensure_directory_created(@directory)
30
+ end
31
+
32
+ def key?(key, *)
33
+ !self[key].nil?
34
+ end
35
+
36
+ def [](key)
37
+ if ::File.exist?(path(key))
38
+ raw_get(key)
39
+ end
40
+ end
41
+
42
+ def store(key, value, *)
43
+ ensure_directory_created(::File.dirname(path(key)))
44
+ ::File.open(path(key), "w") do |file|
45
+ file.puts(serialize(value))
46
+ end
47
+ end
48
+
49
+ def delete(key, *)
50
+ value = self[key]
51
+ delete!(key)
52
+ value
53
+ end
54
+
55
+ def clear(*)
56
+ FileUtils.rm_rf(@directory)
57
+ FileUtils.mkdir(@directory)
58
+ end
59
+
60
+ private
61
+ def path(key)
62
+ ::File.join(@directory, key_for(key))
63
+ end
64
+
65
+ def raw_get(key)
66
+ deserialize(::File.read(path(key)))
67
+ end
68
+
69
+ def delete!(key)
70
+ FileUtils.rm(path(key))
71
+ nil
72
+ rescue Errno::ENOENT
73
+ end
74
+
75
+ def ensure_directory_created(directory_path)
76
+ if ::File.file?(directory_path)
77
+ raise StandardError, "The path you supplied #{directory_path} is a file"
78
+ elsif !::File.exists?(directory_path)
79
+ FileUtils.mkdir_p(directory_path)
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,51 @@
1
+ begin
2
+ require "couchrest"
3
+ rescue LoadError
4
+ puts "You need the couchrest gem to use the CouchDB store"
5
+ exit
6
+ end
7
+
8
+ module Moneta
9
+ module Adapters
10
+ class Couch
11
+ include Defaults
12
+
13
+ def initialize(options = {})
14
+ @db = ::CouchRest.database!(options[:db])
15
+ end
16
+
17
+ def key?(key, *)
18
+ !self[key_for(key)].nil?
19
+ rescue RestClient::ResourceNotFound
20
+ false
21
+ end
22
+
23
+ def [](key)
24
+ deserialize(@db.get(key_for(key))["data"])
25
+ rescue RestClient::ResourceNotFound
26
+ nil
27
+ end
28
+
29
+ def store(key, value, *)
30
+ @db.save_doc("_id" => key_for(key), :data => serialize(value))
31
+ rescue RestClient::RequestFailed
32
+ self[key_for(key)]
33
+ end
34
+
35
+ def delete(key, *)
36
+ value = @db.get(key_for(key))
37
+
38
+ if value
39
+ @db.delete_doc({"_id" => value["_id"], "_rev" => value["_rev"]}) if value
40
+ deserialize(value["data"])
41
+ end
42
+ rescue RestClient::ResourceNotFound
43
+ nil
44
+ end
45
+
46
+ def clear(*)
47
+ @db.recreate!
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,76 @@
1
+ begin
2
+ gem "dm-core", "~> 1.0.0"
3
+ gem "dm-migrations", "~> 1.0.0"
4
+ gem "dm-sqlite-adapter", "~> 1.0.0"
5
+ require "dm-core"
6
+ require "dm-migrations"
7
+ rescue LoadError
8
+ puts "You need the dm-core gem in order to use the DataMapper moneta store"
9
+ exit
10
+ end
11
+
12
+ class MonetaHash
13
+ include DataMapper::Resource
14
+
15
+ property :the_key, String, :key => true
16
+ property :value, Object, :lazy => false
17
+
18
+ def self.value(key)
19
+ obj = self.get(key)
20
+ obj && obj.value
21
+ end
22
+ end
23
+
24
+ module Moneta
25
+ module Adapters
26
+ class DataMapper
27
+ include Moneta::Defaults
28
+
29
+ def initialize(options = {})
30
+ @repository = options.delete(:repository) || :moneta
31
+ ::DataMapper.setup(@repository, options[:setup])
32
+ MonetaHash.auto_upgrade!(@repository)
33
+ @hash = MonetaHash
34
+ end
35
+
36
+ def key?(key, *)
37
+ repository_context { !!@hash.get(key_for(key)) }
38
+ end
39
+
40
+ def [](key)
41
+ repository_context { @hash.value(key_for(key)) }
42
+ end
43
+
44
+ def store(key, value, *)
45
+ string_key = key_for(key)
46
+ repository_context {
47
+ obj = @hash.get(string_key)
48
+ if obj
49
+ obj.update(string_key, value)
50
+ else
51
+ @hash.create(:the_key => string_key, :value => value)
52
+ end
53
+ }
54
+ end
55
+
56
+ def delete(key, *)
57
+ string_key = key_for(key)
58
+
59
+ repository_context {
60
+ value = self[key]
61
+ @hash.all(:the_key => string_key).destroy!
62
+ value
63
+ }
64
+ end
65
+
66
+ def clear(*)
67
+ repository_context { @hash.all.destroy! }
68
+ end
69
+
70
+ private
71
+ def repository_context
72
+ repository(@repository) { yield }
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,52 @@
1
+ require "fileutils"
2
+
3
+ module Moneta
4
+ module Adapters
5
+ class File
6
+ include Moneta::Defaults
7
+
8
+ def initialize(options = {})
9
+ @directory = options[:path]
10
+ if ::File.file?(@directory)
11
+ raise StandardError, "The path you supplied #{@directory} is a file"
12
+ elsif !::File.exists?(@directory)
13
+ FileUtils.mkdir_p(@directory)
14
+ end
15
+ end
16
+
17
+ def key?(key, *)
18
+ ::File.exist?(path(key))
19
+ end
20
+
21
+ def [](key)
22
+ if ::File.exist?(path(key))
23
+ Marshal.load(::File.read(path(key)))
24
+ end
25
+ end
26
+
27
+ def store(key, value, *)
28
+ ::File.open(path(key), "w") do |file|
29
+ contents = Marshal.dump(value)
30
+ file.puts(contents)
31
+ end
32
+ end
33
+
34
+ def delete(key, *)
35
+ value = self[key]
36
+ FileUtils.rm(path(key))
37
+ value
38
+ rescue Errno::ENOENT
39
+ end
40
+
41
+ def clear(*)
42
+ FileUtils.rm_rf(@directory)
43
+ FileUtils.mkdir(@directory)
44
+ end
45
+
46
+ private
47
+ def path(key)
48
+ ::File.join(@directory, key_for(key))
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,62 @@
1
+ begin
2
+ require "fog"
3
+ rescue LoadError
4
+ puts "You need the Fog gem to use the S3 moneta store"
5
+ exit
6
+ end
7
+
8
+ module Moneta
9
+ module Adapters
10
+ class Fog
11
+ include Moneta::Defaults
12
+
13
+ def initialize(options = {})
14
+ bucket = options.delete(:namespace)
15
+ s3 = options.delete(:cloud).new(options)
16
+ @directory = s3.directories.create(:key => bucket)
17
+ end
18
+
19
+ def key?(key)
20
+ !@directory.files.head(key_for(key)).nil?
21
+ end
22
+
23
+ def [](key)
24
+ if value = get(key)
25
+ deserialize(value.body)
26
+ end
27
+ end
28
+
29
+ def delete(key)
30
+ value = get(key)
31
+ if value
32
+ value.destroy
33
+ deserialize(value.body)
34
+ end
35
+ end
36
+
37
+ def store(key, value, options = {})
38
+ #perms = options[:perms]
39
+ #headers = options[:headers] || {}
40
+ @directory.files.create(:key => key_for(key), :body => serialize(value))
41
+ end
42
+
43
+ # def update_key(key, options = {})
44
+ # debug "update_key(key=#{key}, options=#{options.inspect})"
45
+ # k = s3_key(key, false)
46
+ # k.save_meta(meta_headers_from_options(options)) unless k.nil?
47
+ # end
48
+
49
+ def clear
50
+ @directory.files.all.each do |file|
51
+ file.destroy
52
+ end
53
+ self
54
+ end
55
+
56
+ private
57
+ def get(key)
58
+ @directory.files.get(key_for(key))
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,40 @@
1
+ begin
2
+ require "localmemcache"
3
+ rescue LoadError
4
+ puts "You need the localmemcache gem to use the LMC moneta store"
5
+ exit
6
+ end
7
+
8
+ module Moneta
9
+ module Adapters
10
+ class LMC
11
+ include Defaults
12
+
13
+ def initialize(options = {})
14
+ @hash = LocalMemCache.new(:filename => options[:filename])
15
+ end
16
+
17
+ def [](key)
18
+ deserialize(@hash[key_for(key)])
19
+ end
20
+
21
+ def store(key, value, *)
22
+ @hash[key_for(key)] = serialize(value)
23
+ end
24
+
25
+ def clear(*)
26
+ @hash.clear
27
+ end
28
+
29
+ def key?(key, *)
30
+ @hash.keys.include?(key_for(key))
31
+ end
32
+
33
+ def delete(key, *)
34
+ value = self[key]
35
+ @hash.delete(key_for(key))
36
+ value
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,54 @@
1
+ begin
2
+ require "memcached"
3
+ MemCache = Memcached
4
+ rescue LoadError
5
+ begin
6
+ require "memcache"
7
+ rescue LoadError => e
8
+ puts "You need either the `memcached` or `memcache-client` gem to use the Memcache moneta store"
9
+ exit
10
+ end
11
+ rescue
12
+ puts "You need either the `memcached` or `memcache-client` gem to use the Memcache moneta store"
13
+ exit
14
+ end
15
+
16
+ module Moneta
17
+ module Adapters
18
+ class Memcache
19
+ include Moneta::Defaults
20
+
21
+ def initialize(options = {})
22
+ @cache = ::MemCache.new(options.delete(:server), options)
23
+ end
24
+
25
+ def key?(key, *)
26
+ !self[key].nil?
27
+ end
28
+
29
+ def [](key)
30
+ deserialize(@cache.get(key_for(key)))
31
+ rescue MemCache::NotFound
32
+ end
33
+
34
+ def delete(key, *)
35
+ value = self[key]
36
+ @cache.delete(key_for(key)) if value
37
+ value
38
+ end
39
+
40
+ def store(key, value, *)
41
+ @cache.set(key_for(key), serialize(value))
42
+ end
43
+
44
+ def clear(*)
45
+ @cache.flush
46
+ end
47
+
48
+ private
49
+ def key_for(key)
50
+ [super].pack("m").strip
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,23 @@
1
+ module Moneta
2
+ module Adapters
3
+ class Memory < Hash
4
+ include Moneta::Defaults
5
+
6
+ def [](key)
7
+ deserialize(super(key_for(key)))
8
+ end
9
+
10
+ def key?(key, *)
11
+ super(key_for(key))
12
+ end
13
+
14
+ def store(key, value, *args)
15
+ super(key_for(key), serialize(value), *args)
16
+ end
17
+
18
+ def delete(key, *args)
19
+ deserialize(super(key_for(key), *args))
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,52 @@
1
+ begin
2
+ require "mongo"
3
+ rescue LoadError
4
+ puts "You need the mongo gem to use the MongoDB moneta store"
5
+ exit
6
+ end
7
+
8
+ module Moneta
9
+ module Adapters
10
+ class MongoDB
11
+ include Moneta::Defaults
12
+
13
+ def initialize(options = {})
14
+ options = {
15
+ :host => ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost',
16
+ :port => ENV['MONGO_RUBY_DRIVER_PORT'] || Mongo::Connection::DEFAULT_PORT,
17
+ :db => 'cache',
18
+ :collection => 'cache'
19
+ }.update(options)
20
+ conn = Mongo::Connection.new(options[:host], options[:port])
21
+ @cache = conn.db(options[:db]).collection(options[:collection])
22
+ end
23
+
24
+ def key?(key, *)
25
+ !!self[key]
26
+ end
27
+
28
+ def [](key)
29
+ res = @cache.find_one('_id' => key_for(key))
30
+ res && deserialize(res['data'])
31
+ end
32
+
33
+ def delete(key, *)
34
+ string_key = key_for(key)
35
+
36
+ value = self[key]
37
+ @cache.remove('_id' => string_key) if value
38
+ value
39
+ end
40
+
41
+ def store(key, value, *)
42
+ key = key_for(key)
43
+ @cache.insert({ '_id' => key, 'data' => serialize(value) })
44
+ end
45
+
46
+ def clear(*)
47
+ @cache.remove
48
+ end
49
+ end
50
+ end
51
+ end
52
+
@@ -0,0 +1,14 @@
1
+ require "moneta/adapters/fog"
2
+
3
+ module Moneta
4
+ module Adapters
5
+ class Rackspace < Fog
6
+
7
+ def initialize(options)
8
+ options[:cloud] = ::Fog::Rackspace::Files
9
+ super
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,41 @@
1
+ begin
2
+ require "redis"
3
+ rescue LoadError
4
+ puts "You need the redis gem to use the Redis store"
5
+ exit
6
+ end
7
+
8
+ module Moneta
9
+ module Adapters
10
+ class Redis
11
+ include Defaults
12
+
13
+ def initialize(options = {})
14
+ @cache = ::Redis.new(options)
15
+ end
16
+
17
+ def key?(key, *)
18
+ !@cache[key_for(key)].nil?
19
+ end
20
+
21
+ def [](key)
22
+ deserialize(@cache.get(key_for(key)))
23
+ end
24
+
25
+ def delete(key, *)
26
+ string_key = key_for(key)
27
+ value = self[key]
28
+ @cache.del(string_key) if value
29
+ value
30
+ end
31
+
32
+ def store(key, value, *)
33
+ @cache.set(key_for(key), serialize(value))
34
+ end
35
+
36
+ def clear(*)
37
+ @cache.flushdb
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,14 @@
1
+ require "moneta/adapters/fog"
2
+
3
+ module Moneta
4
+ module Adapters
5
+ class S3 < Fog
6
+
7
+ def initialize(options)
8
+ options[:cloud] = ::Fog::AWS::S3
9
+ super
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,34 @@
1
+ require "sdbm"
2
+
3
+ module Moneta
4
+ module Adapters
5
+ class SDBM < ::SDBM
6
+ include Moneta::Defaults
7
+
8
+ def initialize(options = {})
9
+ raise "No :file options specified" unless file = options[:file]
10
+ super(file)
11
+ end
12
+
13
+ def [](key)
14
+ if val = super(key_for(key))
15
+ deserialize(val)
16
+ end
17
+ end
18
+
19
+ def store(key, value, *)
20
+ super(key_for(key), serialize(value))
21
+ end
22
+
23
+ def key?(key, *)
24
+ super(key_for(key))
25
+ end
26
+
27
+ def delete(key, *)
28
+ if val = super(key_for(key))
29
+ deserialize(val)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,51 @@
1
+ begin
2
+ require "tokyocabinet"
3
+ rescue LoadError
4
+ puts "You need the tokyocabinet gem to use the tokyo cabinet store"
5
+ exit
6
+ end
7
+
8
+ module Moneta
9
+ module Adapters
10
+ class TokyoCabinet
11
+ include Defaults
12
+
13
+ def initialize(options = {})
14
+ file = options[:file]
15
+ @cache = ::TokyoCabinet::HDB.new
16
+ unless @cache.open(file, ::TokyoCabinet::HDB::OWRITER | ::TokyoCabinet::HDB::OCREAT)
17
+ puts @cache.errmsg(@cache.ecode)
18
+ end
19
+ end
20
+
21
+ def [](key)
22
+ deserialize(@cache[key_for(key)])
23
+ end
24
+
25
+ def store(key, value, *)
26
+ @cache[key_for(key)] = serialize(value)
27
+ end
28
+
29
+ def key?(key, *)
30
+ !!self[key]
31
+ end
32
+
33
+ def delete(key, *)
34
+ value = self[key]
35
+
36
+ if value
37
+ @cache.delete(key_for(key))
38
+ value
39
+ end
40
+ end
41
+
42
+ def clear(*)
43
+ @cache.clear
44
+ end
45
+
46
+ def close
47
+ @cache.close
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,45 @@
1
+ begin
2
+ require "tokyotyrant"
3
+ rescue LoadError
4
+ puts "You need the tokyotyrant gem to use the Tyrant moneta store"
5
+ exit
6
+ end
7
+
8
+ module Moneta
9
+ module Adapters
10
+ class Tyrant
11
+ include Defaults
12
+
13
+ def initialize(options = {})
14
+ @hash = ::TokyoTyrant::RDB.new
15
+
16
+ if !@hash.open(options[:host], options[:port])
17
+ puts @hash.errmsg(@hash.ecode)
18
+ end
19
+ end
20
+
21
+ def key?(key, *)
22
+ !!self[key]
23
+ end
24
+
25
+ def [](key)
26
+ deserialize(@hash[key_for(key)])
27
+ end
28
+
29
+ def store(key, value, *)
30
+ @hash.put(key_for(key), serialize(value))
31
+ end
32
+
33
+ def clear(*)
34
+ @hash.clear
35
+ end
36
+
37
+ def delete(key, *)
38
+ if value = self[key]
39
+ @hash.delete(key_for(key))
40
+ value
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,50 @@
1
+ begin
2
+ require "xattr"
3
+ rescue LoadError
4
+ puts "You need the xattr gem to use the Xattr moneta store"
5
+ exit
6
+ end
7
+ require "fileutils"
8
+
9
+ module Moneta
10
+ module Adapters
11
+ class Xattr
12
+ include Defaults
13
+
14
+ def initialize(options = {})
15
+ file = options[:file]
16
+ @hash = ::Xattr.new(file)
17
+ FileUtils.mkdir_p(::File.dirname(file))
18
+ FileUtils.touch(file)
19
+ end
20
+
21
+ def key?(key, *)
22
+ @hash.list.include?(key_for(key))
23
+ end
24
+
25
+ def [](key)
26
+ string_key = key_for(key)
27
+ return nil unless key?(string_key)
28
+ Marshal.load(@hash.get(string_key))
29
+ end
30
+
31
+ def store(key, value, *)
32
+ @hash.set(key_for(key), Marshal.dump(value))
33
+ end
34
+
35
+ def delete(key, *)
36
+ return nil unless key?(key)
37
+ value = self[key]
38
+ @hash.remove(key_for(key))
39
+ value
40
+ end
41
+
42
+ def clear(*)
43
+ @hash.list.each do |item|
44
+ @hash.remove(item)
45
+ end
46
+ end
47
+
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,53 @@
1
+ require "yaml"
2
+ require "fileutils"
3
+
4
+ module Moneta
5
+ module Adapters
6
+ class YAML
7
+ include Moneta::Defaults
8
+
9
+ def initialize(options = {})
10
+ @file = ::File.expand_path(options[:path])
11
+ unless ::File.exists?(@file)
12
+ ::File.open(@file, "w") { |file| file << {}.to_yaml }
13
+ end
14
+ end
15
+
16
+ def key?(key, *)
17
+ yaml.has_key?(key_for(key))
18
+ end
19
+
20
+ def [](key)
21
+ string_key = key_for(key)
22
+ yaml[string_key]['value'] if yaml.key?(string_key)
23
+ end
24
+
25
+ def store(key, value, *)
26
+ hash = yaml
27
+ (hash[key_for(key)] ||= {})['value'] = value
28
+ save(hash)
29
+ end
30
+
31
+ def delete(key, *)
32
+ hash = yaml
33
+ value = self[key_for(key)]
34
+ hash.delete(key_for(key))
35
+ save(hash)
36
+ value
37
+ end
38
+
39
+ def clear(*)
40
+ save
41
+ end
42
+
43
+ private
44
+ def yaml
45
+ ::YAML.load_file(@file)
46
+ end
47
+
48
+ def save(hash = {})
49
+ ::File.open(@file, "w") { |file| file << hash.to_yaml }
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,72 @@
1
+ module Moneta
2
+ module Middleware
3
+ def self.included(klass)
4
+ class << klass
5
+ alias build new
6
+ end
7
+ end
8
+
9
+ def build(adapter)
10
+ @adapter = adapter
11
+ end
12
+
13
+ def [](key)
14
+ @adapter[key]
15
+ end
16
+
17
+ def []=(key, value)
18
+ @adapter[key] = value
19
+ end
20
+
21
+ def fetch(*args, &block)
22
+ @adapter.fetch(*args, &block)
23
+ end
24
+
25
+ def delete(key, *args)
26
+ @adapter.delete(key, *args)
27
+ end
28
+
29
+ def store(key, value, *args)
30
+ @adapter.store(key, value, *args)
31
+ end
32
+
33
+ def update_key(key, options)
34
+ @adapter.update_key(key, options)
35
+ end
36
+
37
+ def key?(key, *args)
38
+ @adapter.key?(key, *args)
39
+ end
40
+
41
+ def clear(*args)
42
+ @adapter.clear(*args)
43
+ end
44
+
45
+ def close
46
+ @adapter.close
47
+ end
48
+ end
49
+
50
+ class Builder
51
+ include Middleware
52
+
53
+ def initialize(&block)
54
+ @middlewares = []
55
+ @adapter = nil
56
+ instance_eval(&block)
57
+ end
58
+
59
+ def use(middleware, *args, &block)
60
+ @middlewares << middleware.build(*args, &block)
61
+ end
62
+
63
+ def run(adapter, *args, &block)
64
+ @adapter = adapter.new(*args, &block)
65
+
66
+ @middlewares.reverse.each do |middleware|
67
+ @adapter = middleware.build(@adapter)
68
+ end
69
+ end
70
+
71
+ end
72
+ end
data/lib/moneta.rb ADDED
@@ -0,0 +1,29 @@
1
+ require "moneta/builder"
2
+
3
+ module Moneta
4
+ module Defaults
5
+ def fetch(key, value = nil, *)
6
+ self[key] || begin
7
+ value ||= block_given? ? yield(key) : default
8
+ self[key] || value
9
+ end
10
+ end
11
+
12
+ def []=(key, value)
13
+ store(key, value)
14
+ end
15
+
16
+ private
17
+ def key_for(key)
18
+ key.is_a?(String) ? key : Marshal.dump(key)
19
+ end
20
+
21
+ def serialize(value)
22
+ Marshal.dump(value)
23
+ end
24
+
25
+ def deserialize(value)
26
+ value && Marshal.load(value)
27
+ end
28
+ end
29
+ end
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: moneta-splattael
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.7.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Yehuda Katz
9
+ autorequire: moneta-splattael
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-11-23 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: A unified interface to key/value stores (modified version!)
15
+ email: wycats@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files:
19
+ - README
20
+ - LICENSE
21
+ - TODO
22
+ files:
23
+ - LICENSE
24
+ - README
25
+ - Rakefile
26
+ - TODO
27
+ - lib/moneta/builder.rb
28
+ - lib/moneta/adapters/memory.rb
29
+ - lib/moneta/adapters/lmc.rb
30
+ - lib/moneta/adapters/file.rb
31
+ - lib/moneta/adapters/yaml.rb
32
+ - lib/moneta/adapters/tyrant.rb
33
+ - lib/moneta/adapters/fog.rb
34
+ - lib/moneta/adapters/couch.rb
35
+ - lib/moneta/adapters/memcache.rb
36
+ - lib/moneta/adapters/xattr.rb
37
+ - lib/moneta/adapters/basic_file.rb
38
+ - lib/moneta/adapters/tokyo_cabinet.rb
39
+ - lib/moneta/adapters/rackspace.rb
40
+ - lib/moneta/adapters/redis.rb
41
+ - lib/moneta/adapters/sdbm.rb
42
+ - lib/moneta/adapters/s3.rb
43
+ - lib/moneta/adapters/datamapper.rb
44
+ - lib/moneta/adapters/mongodb.rb
45
+ - lib/moneta.rb
46
+ homepage: http://www.yehudakatz.com
47
+ licenses: []
48
+ post_install_message:
49
+ rdoc_options: []
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ! '>='
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ! '>='
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ requirements: []
65
+ rubyforge_project:
66
+ rubygems_version: 1.8.10
67
+ signing_key:
68
+ specification_version: 3
69
+ summary: A unified interface to key/value stores (modified version!)
70
+ test_files: []