Permalink
Browse files

Initial commit.

Files copied from working project.
  • Loading branch information...
0 parents commit 30f20fda1f35aee02f2f8a9bbaf8629344f88780 @jnunemaker committed Jan 26, 2011
Showing with 311 additions and 0 deletions.
  1. +3 −0 .gitignore
  2. +13 −0 Gemfile
  3. +40 −0 Gemfile.lock
  4. +19 −0 LICENSE
  5. +13 −0 README.rdoc
  6. +7 −0 Rakefile
  7. +22 −0 adapter-redis.gemspec
  8. +25 −0 examples/redis.rb
  9. +68 −0 lib/adapter/redis.rb
  10. +5 −0 lib/adapter/redis/version.rb
  11. +1 −0 log/test.log
  12. +26 −0 spec/helper.rb
  13. +69 −0 spec/redis_spec.rb
@@ -0,0 +1,3 @@
+pkg/*
+*.gem
+.bundle
13 Gemfile
@@ -0,0 +1,13 @@
+source "http://rubygems.org"
+
+# Specify your gem's dependencies in adapter-redis.gemspec
+gemspec
+
+group(:development) do
+ gem 'rspec', '~> 2.3'
+ gem 'log_buddy', '~> 0.5.0'
+ gem 'timecop', '~> 0.3.5'
+ gem 'SystemTimer', '~> 1.2.1'
+ gem 'i18n', '0.5.0'
+ gem 'activesupport', '~> 3', :require => 'active_support'
+end
@@ -0,0 +1,40 @@
+PATH
+ remote: .
+ specs:
+ adapter-redis (0.5)
+ adapter (~> 0.5)
+ redis
+
+GEM
+ remote: http://rubygems.org/
+ specs:
+ SystemTimer (1.2.1)
+ activesupport (3.0.3)
+ adapter (0.5.1)
+ diff-lcs (1.1.2)
+ i18n (0.5.0)
+ log_buddy (0.5.0)
+ redis (2.1.1)
+ rspec (2.4.0)
+ rspec-core (~> 2.4.0)
+ rspec-expectations (~> 2.4.0)
+ rspec-mocks (~> 2.4.0)
+ rspec-core (2.4.0)
+ rspec-expectations (2.4.0)
+ diff-lcs (~> 1.1.2)
+ rspec-mocks (2.4.0)
+ timecop (0.3.5)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ SystemTimer (~> 1.2.1)
+ activesupport (~> 3)
+ adapter (~> 0.5)
+ adapter-redis!
+ i18n (= 0.5.0)
+ log_buddy (~> 0.5.0)
+ redis
+ rspec (~> 2.3)
+ timecop (~> 0.3.5)
19 LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2010 Newtoy, Inc.
+
+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,13 @@
+= adapter-redis
+
+Redis adapter for adapter gem.
+
+See examples/ or specs/ for usage.
+
+== Note on Patches/Pull Requests
+
+* Fork the project.
+* Make your feature addition or bug fix.
+* Add tests for it. This is important so we don't break it in a future version unintentionally.
+* Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine, but bump version in a commit by itself so we can ignore when we pull)
+* Send us a pull request. Bonus points for topic branches.
@@ -0,0 +1,7 @@
+require 'bundler'
+Bundler::GemHelper.install_tasks
+
+require 'rspec/core/rake_task'
+RSpec::Core::RakeTask.new
+
+task :default => :spec
@@ -0,0 +1,22 @@
+# -*- encoding: utf-8 -*-
+$:.push File.expand_path("../lib", __FILE__)
+require "adapter/redis/version"
+
+Gem::Specification.new do |s|
+ s.name = "adapter-redis"
+ s.version = Adapter::Redis::VERSION
+ s.platform = Gem::Platform::RUBY
+ s.authors = ["John Nunemaker"]
+ s.email = ["nunemaker@gmail.com"]
+ s.homepage = ""
+ s.summary = %q{Adapter for redis}
+ s.description = %q{Adapter for redis}
+
+ s.files = `git ls-files`.split("\n")
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
+ s.require_paths = ["lib"]
+
+ s.add_dependency 'adapter', '~> 0.5'
+ s.add_dependency 'redis'
+end
@@ -0,0 +1,25 @@
+require 'rubygems'
+require 'pathname'
+
+root_path = Pathname(__FILE__).dirname.join('..').expand_path
+lib_path = root_path.join('lib')
+$:.unshift(lib_path)
+
+require 'adapter/redis'
+
+client = Redis.new
+adapter = Adapter[:redis].new(client)
+adapter.clear
+
+adapter.write('foo', 'bar')
+puts 'Should be bar: ' + adapter.read('foo').inspect
+
+adapter.delete('foo')
+puts 'Should be nil: ' + adapter.read('foo').inspect
+
+adapter.write('foo', 'bar')
+adapter.clear
+puts 'Should be nil: ' + adapter.read('foo').inspect
+
+puts 'Should be bar: ' + adapter.fetch('foo', 'bar')
+puts 'Should be bar: ' + adapter.read('foo')
@@ -0,0 +1,68 @@
+require 'adapter'
+require 'redis'
+
+module Adapter
+ module Redis
+ def read(key)
+ decode(client.get(key_for(key)))
+ end
+
+ def write(key, value)
+ client.set(key_for(key), encode(value))
+ end
+
+ def delete(key)
+ read(key).tap { client.del(key_for(key)) }
+ end
+
+ def clear
+ client.flushdb
+ end
+
+ # Pretty much stolen from redis objects
+ # http://github.com/nateware/redis-objects/blob/master/lib/redis/lock.rb
+ def lock(name, options={}, &block)
+ key = name.to_s
+ start = Time.now
+ acquired_lock = false
+ expiration = nil
+ expires_in = options.fetch(:expiration, 1)
+ timeout = options.fetch(:timeout, 5)
+
+ while (Time.now - start) < timeout
+ expiration = generate_expiration(expires_in)
+ acquired_lock = client.setnx(key, expiration)
+ break if acquired_lock
+
+ old_expiration = client.get(key).to_f
+
+ if old_expiration < Time.now.to_f
+ expiration = generate_expiration(expires_in)
+ old_expiration = client.getset(key, expiration).to_f
+
+ if old_expiration < Time.now.to_f
+ acquired_lock = true
+ break
+ end
+ end
+
+ sleep 0.1
+ end
+
+ raise(LockTimeout.new(name, timeout)) unless acquired_lock
+
+ begin
+ yield
+ ensure
+ client.del(key) if expiration > Time.now.to_f
+ end
+ end
+
+ # Defaults expiration to 1
+ def generate_expiration(expiration)
+ (Time.now + (expiration || 1).to_f).to_f
+ end
+ end
+end
+
+Adapter.define(:redis, Adapter::Redis)
@@ -0,0 +1,5 @@
+module Adapter
+ module Redis
+ VERSION = "0.5"
+ end
+end
@@ -0,0 +1 @@
+# Logfile created on Tue Jan 25 22:18:39 -0500 2011 by logger.rb
@@ -0,0 +1,26 @@
+$:.unshift(File.expand_path('../../lib', __FILE__))
+
+require 'rubygems'
+require 'bundler'
+
+Bundler.require(:default, :development)
+
+require 'pathname'
+require 'logger'
+
+root_path = Pathname(__FILE__).dirname.join('..').expand_path
+lib_path = root_path.join('lib')
+log_path = root_path.join('log')
+log_path.mkpath
+
+require 'adapter/spec/an_adapter'
+require 'adapter/spec/marshal_adapter'
+require 'adapter/spec/json_adapter'
+require 'adapter/spec/types'
+
+logger = Logger.new(log_path.join('test.log'))
+LogBuddy.init(:logger => logger)
+
+Rspec.configure do |c|
+
+end
@@ -0,0 +1,69 @@
+require 'helper'
+require 'adapter/redis'
+
+describe "Redis adapter" do
+ before do
+ @client = Redis.new
+ @adapter = Adapter[:redis].new(@client)
+ @adapter.clear
+ end
+
+ let(:adapter) { @adapter }
+ let(:client) { @client }
+
+ it_should_behave_like 'a marshaled adapter'
+
+ describe "#lock" do
+ let(:lock_key) { :add_game }
+
+ it "defaults expiration to 1" do
+ now = Time.mktime(2010, 10, 10, 5, 5, 5)
+ Timecop.freeze(now) do
+ expiration = now.to_i + 1
+ client.should_receive(:setnx).with(lock_key.to_s, expiration).and_return(true)
+ adapter.lock(lock_key) { }
+ end
+ end
+
+ it "allows setting expiration" do
+ now = Time.mktime(2010, 10, 10, 5, 5, 5)
+ Timecop.freeze(now) do
+ expiration = now.to_i + 5
+ client.should_receive(:setnx).with(lock_key.to_s, expiration).and_return(true)
+ adapter.lock(lock_key, :expiration => 5) { }
+ end
+ end
+
+ describe "with no existing lock" do
+ it "acquires lock, performs block, and clears lock" do
+ result = false
+ adapter.lock(lock_key) { result = true }
+
+ result.should be_true
+ adapter.read(lock_key).should be_nil
+ end
+ end
+
+ describe "with lock set" do
+ it "waits for unlock, performs block, and clears lock" do
+ result = false
+ client.set(lock_key.to_s, adapter.generate_expiration(1))
+ adapter.lock(lock_key, :timeout => 2) { result = true }
+
+ result.should be_true
+ adapter.read(lock_key).should be_nil
+ end
+ end
+
+ describe "with lock set that does not expire before timeout" do
+ it "raises lock timeout error" do
+ result = false
+ client.set(lock_key.to_s, adapter.generate_expiration(2))
+
+ lambda do
+ adapter.lock(lock_key, :timeout => 1) { result = true }
+ end.should raise_error(Adapter::LockTimeout, 'Timeout on lock add_game exceeded 1 sec')
+ end
+ end
+ end
+end

0 comments on commit 30f20fd

Please sign in to comment.