Permalink
Browse files

Initial commit

  • Loading branch information...
0 parents commit 3cbb15dbe3ea92e53366339b521dbdc7cb08f074 @wycats committed Feb 12, 2009
Showing with 692 additions and 0 deletions.
  1. +20 −0 LICENSE
  2. +4 −0 README
  3. +60 −0 Rakefile
  4. +4 −0 TODO
  5. +50 −0 lib/moneta.rb
  6. +107 −0 lib/moneta/datamapper.rb
  7. +100 −0 lib/moneta/file.rb
  8. +52 −0 lib/moneta/memcache.rb
  9. +11 −0 lib/moneta/memory.rb
  10. +67 −0 lib/moneta/xattr.rb
  11. +14 −0 script/destroy
  12. +14 −0 script/generate
  13. +59 −0 spec/moneta_spec.rb
  14. +118 −0 spec/shared.rb
  15. +12 −0 spec/spec_helper.rb
@@ -0,0 +1,20 @@
+Copyright (c) 2009 Yehuda Katz
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,4 @@
+moneta
+======
+
+A gem that provides...
@@ -0,0 +1,60 @@
+require 'rubygems'
+require 'rake/gempackagetask'
+require 'rubygems/specification'
+require 'spec/rake/spectask'
+require 'date'
+
+GEM = "moneta"
+GEM_VERSION = "0.5.0"
+AUTHOR = "Yehuda Katz"
+EMAIL = "wycats@gmail.com"
+HOMEPAGE = "http://www.yehudakatz.com"
+SUMMARY = "A unified interface to key/value stores"
+
+spec = Gem::Specification.new do |s|
+ s.name = GEM
+ s.version = GEM_VERSION
+ s.platform = Gem::Platform::RUBY
+ s.has_rdoc = true
+ s.extra_rdoc_files = ["README", "LICENSE", 'TODO']
+ s.summary = SUMMARY
+ s.description = s.summary
+ s.author = AUTHOR
+ s.email = EMAIL
+ s.homepage = HOMEPAGE
+
+ # Uncomment this to add a dependency
+ # s.add_dependency "foo"
+
+ s.require_path = 'lib'
+ s.autorequire = GEM
+ s.files = %w(LICENSE README Rakefile TODO) + Dir.glob("{lib,specs}/**/*")
+end
+
+Rake::GemPackageTask.new(spec) do |pkg|
+ pkg.gem_spec = spec
+end
+
+desc "install the gem locally"
+task :install => [:package] do
+ sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION}}
+end
+
+desc "create a gemspec file"
+task :make_spec do
+ File.open("#{GEM}.gemspec", "w") do |file|
+ file.puts spec.to_ruby
+ end
+end
+
+desc "Run all examples (or a specific spec with TASK=xxxx)"
+Spec::Rake::SpecTask.new('spec') do |t|
+ t.spec_opts = ["-cfs"]
+ t.spec_files = begin
+ if ENV["TASK"]
+ ENV["TASK"].split(',').map { |task| "spec/**/#{task}_spec.rb" }
+ else
+ FileList['spec/**/*_spec.rb']
+ end
+ end
+end
@@ -0,0 +1,4 @@
+TODO:
+Fix LICENSE with your name
+Fix Rakefile with your name and contact info
+Add your code to lib/<%= name %>.rb
@@ -0,0 +1,50 @@
+module Moneta
+ module Expires
+ def check_expired(key)
+ if @expiration[key] && Time.now > @expiration[key]
+ @expiration.delete(key)
+ self.delete(key)
+ end
+ end
+
+ def has_key?(key)
+ check_expired(key)
+ super
+ end
+
+ def key?(key)
+ has_key?(key)
+ end
+
+ def [](key)
+ check_expired(key)
+ super
+ end
+
+ def fetch(key, default)
+ check_expired(key)
+ super
+ end
+
+ def delete(key)
+ check_expired(key)
+ super
+ end
+
+ def update_key(key, options)
+ update_options(key, options)
+ end
+
+ def store(key, value, options = {})
+ super(key, value)
+ update_options(key, options)
+ end
+
+ private
+ def update_options(key, options)
+ if options[:expires_in]
+ @expiration[key] = (Time.now + options[:expires_in])
+ end
+ end
+ end
+end
@@ -0,0 +1,107 @@
+begin
+ gem "dm-core", "0.9.10"
+ require "dm-core"
+rescue LoadError
+ puts "You need the dm-core gem in order to use the DataMapper moneta store"
+ exit
+end
+
+class MonetaHash
+ include DataMapper::Resource
+
+ def self.default_repository_name
+ :moneta
+ end
+
+ property :the_key, String, :key => true
+ property :value, Object, :lazy => false
+ property :expires, Time
+
+ def self.value(key)
+ obj = self.get(key)
+ obj && obj.value
+ end
+end
+
+module Moneta
+ class DataMapper
+ class Expiration
+ def initialize(klass)
+ @klass = klass
+ end
+
+ def [](key)
+ if obj = get(key)
+ obj.expires
+ end
+ end
+
+ def []=(key, value)
+ obj = get(key)
+ obj.expires = value
+ obj.save
+ end
+
+ def delete(key)
+ obj = get(key)
+ obj.expires = nil
+ obj.save
+ end
+
+ private
+ def get(key)
+ @klass.get(key)
+ end
+ end
+
+ def initialize(options = {})
+ ::DataMapper.setup(:moneta, options[:setup])
+ MonetaHash.auto_upgrade!
+ @hash = MonetaHash
+ @expiration = Expiration.new(MonetaHash)
+ end
+
+ module Implementation
+ def key?(key)
+ !!@hash.get(key)
+ end
+
+ def has_key?(key)
+ !!@hash.get(key)
+ end
+
+ def [](key)
+ @hash.value(key)
+ end
+
+ def []=(key, value)
+ obj = @hash.get(key)
+ if obj
+ obj.update(key, value)
+ else
+ @hash.create(:the_key => key, :value => value)
+ end
+ end
+
+ def fetch(key, default)
+ self[key] || default
+ end
+
+ def delete(key)
+ value = self[key]
+ @hash.all(:the_key => key).destroy!
+ value
+ end
+
+ def store(key, value, options = {})
+ self[key] = value
+ end
+
+ def clear
+ @hash.all.destroy!
+ end
+ end
+ include Implementation
+ include Expires
+ end
+end
@@ -0,0 +1,100 @@
+begin
+ require "fileutils"
+ require "xattr"
+rescue LoadError
+ puts "You need the xattr gem to use the File moneta store"
+ exit
+end
+
+module Moneta
+ class File
+ class Expiration
+ def initialize(directory)
+ @directory = directory
+ end
+
+ def [](key)
+ attrs = xattr(key)
+ ret = Marshal.load(attrs.get("moneta_expires"))
+ rescue Errno::ENOENT, SystemCallError
+ end
+
+ def []=(key, value)
+ attrs = xattr(key)
+ attrs.set("moneta_expires", Marshal.dump(value))
+ end
+
+ def delete(key)
+ attrs = xattr(key)
+ attrs.remove("moneta_expires")
+ end
+
+ private
+ def xattr(key)
+ ::Xattr.new(::File.join(@directory, key))
+ end
+ end
+
+ def initialize(options = {})
+ @directory = options[:path]
+ if ::File.file?(@directory)
+ raise StandardError, "The path you supplied #{@directory} is a file"
+ elsif !::File.exists?(@directory)
+ FileUtils.mkdir(@directory)
+ end
+
+ @expiration = Expiration.new(@directory)
+ end
+
+ module Implementation
+ def key?(key)
+ ::File.exist?(path(key))
+ end
+
+ def has_key?(key)
+ ::File.exist?(path(key))
+ end
+
+ def [](key)
+ if ::File.exist?(path(key))
+ Marshal.load(::File.read(path(key)))
+ end
+ end
+
+ def []=(key, value)
+ ::File.open(path(key), "w") do |file|
+ contents = Marshal.dump(value)
+ file.puts(contents)
+ end
+ end
+
+ def fetch(key, default)
+ self[key] || default
+ end
+
+ def delete(key)
+ value = self[key]
+ FileUtils.rm(path(key))
+ value
+ rescue Errno::ENOENT
+ end
+
+ def store(key, value, options = {})
+ self[key] = value
+ end
+
+ def clear
+ FileUtils.rm_rf(@directory)
+ FileUtils.mkdir(@directory)
+ end
+
+ private
+ def path(key)
+ ::File.join(@directory, key)
+ end
+ end
+ include Implementation
+ include Expires
+
+ end
+end
Oops, something went wrong.

0 comments on commit 3cbb15d

Please sign in to comment.