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 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,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,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,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,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
+