dkastner-moneta 0.7.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/LICENSE +20 -0
- data/README +56 -0
- data/Rakefile +60 -0
- data/TODO +4 -0
- data/lib/moneta/adapters/basic_file.rb +84 -0
- data/lib/moneta/adapters/couch.rb +51 -0
- data/lib/moneta/adapters/datamapper.rb +76 -0
- data/lib/moneta/adapters/file.rb +52 -0
- data/lib/moneta/adapters/fog.rb +62 -0
- data/lib/moneta/adapters/lmc.rb +40 -0
- data/lib/moneta/adapters/memcache.rb +49 -0
- data/lib/moneta/adapters/memory.rb +23 -0
- data/lib/moneta/adapters/mongodb.rb +64 -0
- data/lib/moneta/adapters/pstore.rb +58 -0
- data/lib/moneta/adapters/rackspace.rb +14 -0
- data/lib/moneta/adapters/redis.rb +41 -0
- data/lib/moneta/adapters/s3.rb +14 -0
- data/lib/moneta/adapters/sdbm.rb +34 -0
- data/lib/moneta/adapters/tokyo_cabinet.rb +51 -0
- data/lib/moneta/adapters/tyrant.rb +45 -0
- data/lib/moneta/adapters/xattr.rb +50 -0
- data/lib/moneta/adapters/yaml.rb +53 -0
- data/lib/moneta/builder.rb +72 -0
- data/lib/moneta.rb +29 -0
- metadata +90 -0
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 'rake/gempackagetask'
|
|
3
|
+
require 'rubygems/specification'
|
|
4
|
+
require 'spec/rake/spectask'
|
|
5
|
+
require 'date'
|
|
6
|
+
|
|
7
|
+
GEM = "moneta"
|
|
8
|
+
GEM_VERSION = "0.5.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"
|
|
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
|
+
Rake::GemPackageTask.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
|
+
Spec::Rake::SpecTask.new('spec') do |t|
|
|
52
|
+
t.spec_opts = ["-cfs"]
|
|
53
|
+
t.spec_files = 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,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,49 @@
|
|
|
1
|
+
begin
|
|
2
|
+
require "memcached"
|
|
3
|
+
MemCache = Memcached
|
|
4
|
+
rescue LoadError
|
|
5
|
+
require "memcache"
|
|
6
|
+
rescue
|
|
7
|
+
puts "You need either the `memcached` or `memcache-client` gem to use the Memcache moneta store"
|
|
8
|
+
exit
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
module Moneta
|
|
12
|
+
module Adapters
|
|
13
|
+
class Memcache
|
|
14
|
+
include Moneta::Defaults
|
|
15
|
+
|
|
16
|
+
def initialize(options = {})
|
|
17
|
+
@cache = ::MemCache.new(options.delete(:server), options)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def key?(key, *)
|
|
21
|
+
!self[key].nil?
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def [](key)
|
|
25
|
+
deserialize(@cache.get(key_for(key)))
|
|
26
|
+
rescue MemCache::NotFound
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def delete(key, *)
|
|
30
|
+
value = self[key]
|
|
31
|
+
@cache.delete(key_for(key)) if value
|
|
32
|
+
value
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def store(key, value, *)
|
|
36
|
+
@cache.set(key_for(key), serialize(value))
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def clear(*)
|
|
40
|
+
@cache.flush
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
def key_for(key)
|
|
45
|
+
[super].pack("m").strip
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
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,64 @@
|
|
|
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
|
+
require 'uri'
|
|
8
|
+
|
|
9
|
+
module Moneta
|
|
10
|
+
module Adapters
|
|
11
|
+
class MongoDB
|
|
12
|
+
include Moneta::Defaults
|
|
13
|
+
|
|
14
|
+
def initialize(options = {})
|
|
15
|
+
if options[:uri]
|
|
16
|
+
conn = Mongo::Connection.from_uri options[:uri]
|
|
17
|
+
db_name = URI.parse(options[:uri]).path.sub('/','')
|
|
18
|
+
db_name ||= options[:db]
|
|
19
|
+
else
|
|
20
|
+
options = {
|
|
21
|
+
:host => ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost',
|
|
22
|
+
:port => ENV['MONGO_RUBY_DRIVER_PORT'] || Mongo::Connection::DEFAULT_PORT,
|
|
23
|
+
:db => 'cache',
|
|
24
|
+
:collection => 'cache'
|
|
25
|
+
}.update(options)
|
|
26
|
+
conn = Mongo::Connection.new(options[:host], options[:port])
|
|
27
|
+
db_name = options[:db]
|
|
28
|
+
end
|
|
29
|
+
db = conn.db(db_name)
|
|
30
|
+
@cache = db.collection(options[:collection])
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def key?(key, *)
|
|
34
|
+
!!self[key]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def [](key)
|
|
38
|
+
res = @cache.find_one('_id' => key_for(key))
|
|
39
|
+
res && deserialize(res['data'].to_s)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def delete(key, *)
|
|
43
|
+
string_key = key_for(key)
|
|
44
|
+
|
|
45
|
+
value = self[key]
|
|
46
|
+
@cache.remove('_id' => string_key) if value
|
|
47
|
+
value
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def store(key, value, *)
|
|
51
|
+
key = key_for(key)
|
|
52
|
+
serialized_value = BSON::ByteBuffer.new serialize(value)
|
|
53
|
+
@cache.update({ '_id' => key },
|
|
54
|
+
{ '_id' => key, 'data' => serialized_value },
|
|
55
|
+
{ :upsert => true })
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def clear(*)
|
|
59
|
+
@cache.remove
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
require 'pstore'
|
|
2
|
+
|
|
3
|
+
module Moneta
|
|
4
|
+
module Adapters
|
|
5
|
+
class PStore < ::PStore
|
|
6
|
+
include Moneta::Defaults
|
|
7
|
+
|
|
8
|
+
def initialize(options = {})
|
|
9
|
+
options[:path] ||= File.join Dir.pwd, 'data.pstore'
|
|
10
|
+
super options[:path]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def key?(key)
|
|
14
|
+
transaction do
|
|
15
|
+
root? key_for(key)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def keys
|
|
20
|
+
transaction true do
|
|
21
|
+
roots
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def [](key)
|
|
26
|
+
transaction true do
|
|
27
|
+
struct = super key_for(key)
|
|
28
|
+
struct ? struct['value'] : nil
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def delete(key)
|
|
33
|
+
struct = if @transaction
|
|
34
|
+
super key_for(key)
|
|
35
|
+
else
|
|
36
|
+
transaction do
|
|
37
|
+
super key_for(key)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
struct ? struct['value'] : nil
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def store(key, value, *)
|
|
44
|
+
transaction do
|
|
45
|
+
(@table[key_for(key)] ||= {})['value'] = value
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def clear(*)
|
|
50
|
+
transaction do
|
|
51
|
+
@table.keys.each do |key|
|
|
52
|
+
delete key
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
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,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,90 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: dkastner-moneta
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
prerelease: false
|
|
5
|
+
segments:
|
|
6
|
+
- 0
|
|
7
|
+
- 7
|
|
8
|
+
- 0
|
|
9
|
+
version: 0.7.0
|
|
10
|
+
platform: ruby
|
|
11
|
+
authors:
|
|
12
|
+
- Yehuda Katz
|
|
13
|
+
- Derek Kastner
|
|
14
|
+
autorequire: moneta
|
|
15
|
+
bindir: bin
|
|
16
|
+
cert_chain: []
|
|
17
|
+
|
|
18
|
+
date: 2011-01-26 00:00:00 -05:00
|
|
19
|
+
default_executable:
|
|
20
|
+
dependencies: []
|
|
21
|
+
|
|
22
|
+
description: A unified interface to key/value stores
|
|
23
|
+
email: dkastner@gmail.com
|
|
24
|
+
executables: []
|
|
25
|
+
|
|
26
|
+
extensions: []
|
|
27
|
+
|
|
28
|
+
extra_rdoc_files:
|
|
29
|
+
- README
|
|
30
|
+
- LICENSE
|
|
31
|
+
- TODO
|
|
32
|
+
files:
|
|
33
|
+
- lib/moneta/builder.rb
|
|
34
|
+
- lib/moneta/adapters/tyrant.rb
|
|
35
|
+
- lib/moneta/adapters/basic_file.rb
|
|
36
|
+
- lib/moneta/adapters/pstore.rb
|
|
37
|
+
- lib/moneta/adapters/rackspace.rb
|
|
38
|
+
- lib/moneta/adapters/xattr.rb
|
|
39
|
+
- lib/moneta/adapters/sdbm.rb
|
|
40
|
+
- lib/moneta/adapters/redis.rb
|
|
41
|
+
- lib/moneta/adapters/fog.rb
|
|
42
|
+
- lib/moneta/adapters/datamapper.rb
|
|
43
|
+
- lib/moneta/adapters/memcache.rb
|
|
44
|
+
- lib/moneta/adapters/mongodb.rb
|
|
45
|
+
- lib/moneta/adapters/couch.rb
|
|
46
|
+
- lib/moneta/adapters/s3.rb
|
|
47
|
+
- lib/moneta/adapters/lmc.rb
|
|
48
|
+
- lib/moneta/adapters/memory.rb
|
|
49
|
+
- lib/moneta/adapters/file.rb
|
|
50
|
+
- lib/moneta/adapters/yaml.rb
|
|
51
|
+
- lib/moneta/adapters/tokyo_cabinet.rb
|
|
52
|
+
- lib/moneta.rb
|
|
53
|
+
- LICENSE
|
|
54
|
+
- README
|
|
55
|
+
- Rakefile
|
|
56
|
+
- TODO
|
|
57
|
+
has_rdoc: true
|
|
58
|
+
homepage: http://www.yehudakatz.com
|
|
59
|
+
licenses: []
|
|
60
|
+
|
|
61
|
+
post_install_message:
|
|
62
|
+
rdoc_options: []
|
|
63
|
+
|
|
64
|
+
require_paths:
|
|
65
|
+
- lib
|
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
67
|
+
none: false
|
|
68
|
+
requirements:
|
|
69
|
+
- - ">="
|
|
70
|
+
- !ruby/object:Gem::Version
|
|
71
|
+
segments:
|
|
72
|
+
- 0
|
|
73
|
+
version: "0"
|
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
75
|
+
none: false
|
|
76
|
+
requirements:
|
|
77
|
+
- - ">="
|
|
78
|
+
- !ruby/object:Gem::Version
|
|
79
|
+
segments:
|
|
80
|
+
- 0
|
|
81
|
+
version: "0"
|
|
82
|
+
requirements: []
|
|
83
|
+
|
|
84
|
+
rubyforge_project:
|
|
85
|
+
rubygems_version: 1.3.7
|
|
86
|
+
signing_key:
|
|
87
|
+
specification_version: 3
|
|
88
|
+
summary: A unified interface to key/value stores
|
|
89
|
+
test_files: []
|
|
90
|
+
|