lawnchair 0.4.0 → 0.5.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/VERSION +1 -1
- data/lawnchair.gemspec +17 -4
- data/lib/lawnchair.rb +21 -59
- data/lib/storage_engine/abstract.rb +37 -0
- data/lib/storage_engine/composite.rb +45 -0
- data/lib/storage_engine/in_process.rb +29 -0
- data/lib/storage_engine/redis.rb +28 -0
- data/lib/view/helper.rb +15 -0
- data/spec/lawnchair_spec.rb +9 -74
- data/spec/spec_helper.rb +8 -1
- data/spec/storage_engine/abstract_spec.rb +103 -0
- data/spec/storage_engine/composite_spec.rb +108 -0
- data/spec/storage_engine/in_process_spec.rb +61 -0
- data/spec/storage_engine/redis_spec.rb +72 -0
- metadata +15 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.5.0
|
data/lawnchair.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{lawnchair}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.5.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Shane Wolf"]
|
12
|
-
s.date = %q{2010-02-
|
12
|
+
s.date = %q{2010-02-12}
|
13
13
|
s.description = %q{Very simple caching mechanism for arbitrary pieces of resoucre ruby code using Redis as the distributed (or local) cache}
|
14
14
|
s.email = %q{shanewolf@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -24,11 +24,20 @@ Gem::Specification.new do |s|
|
|
24
24
|
"VERSION",
|
25
25
|
"lawnchair.gemspec",
|
26
26
|
"lib/lawnchair.rb",
|
27
|
+
"lib/storage_engine/abstract.rb",
|
28
|
+
"lib/storage_engine/composite.rb",
|
29
|
+
"lib/storage_engine/in_process.rb",
|
30
|
+
"lib/storage_engine/redis.rb",
|
31
|
+
"lib/view/helper.rb",
|
27
32
|
"spec/lawnchair_spec.rb",
|
28
33
|
"spec/spec.opts",
|
29
34
|
"spec/spec_helper.rb",
|
30
35
|
"spec/speed.rb",
|
31
|
-
"spec/speed_results.png"
|
36
|
+
"spec/speed_results.png",
|
37
|
+
"spec/storage_engine/abstract_spec.rb",
|
38
|
+
"spec/storage_engine/composite_spec.rb",
|
39
|
+
"spec/storage_engine/in_process_spec.rb",
|
40
|
+
"spec/storage_engine/redis_spec.rb"
|
32
41
|
]
|
33
42
|
s.homepage = %q{http://github.com/gizm0duck/lawnchair}
|
34
43
|
s.rdoc_options = ["--charset=UTF-8"]
|
@@ -38,7 +47,11 @@ Gem::Specification.new do |s|
|
|
38
47
|
s.test_files = [
|
39
48
|
"spec/lawnchair_spec.rb",
|
40
49
|
"spec/spec_helper.rb",
|
41
|
-
"spec/speed.rb"
|
50
|
+
"spec/speed.rb",
|
51
|
+
"spec/storage_engine/abstract_spec.rb",
|
52
|
+
"spec/storage_engine/composite_spec.rb",
|
53
|
+
"spec/storage_engine/in_process_spec.rb",
|
54
|
+
"spec/storage_engine/redis_spec.rb"
|
42
55
|
]
|
43
56
|
|
44
57
|
if s.respond_to? :specification_version then
|
data/lib/lawnchair.rb
CHANGED
@@ -1,72 +1,34 @@
|
|
1
|
-
|
2
|
-
require '
|
1
|
+
Dir[File.dirname(__FILE__) + '/storage_engine/*.rb'].each {|file| require file }
|
2
|
+
require 'view/helper'
|
3
3
|
|
4
4
|
module Lawnchair
|
5
|
-
|
6
|
-
class << self
|
7
|
-
attr_reader :redis
|
8
|
-
|
9
|
-
def connectdb(redis=nil)
|
10
|
-
@redis ||= Redis.new(:db => 11)
|
11
|
-
end
|
12
|
-
|
13
|
-
def flushdb
|
14
|
-
redis.flushdb
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
5
|
class Cache
|
19
|
-
|
20
|
-
|
21
|
-
def self.in_process_store
|
22
|
-
@@in_process_store
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.me(options = {}, &block)
|
26
|
-
raise "Cache key please!" unless options.has_key?(:key)
|
27
|
-
|
6
|
+
def self.me(key, options={}, &block)
|
28
7
|
if options[:in_process]
|
29
|
-
|
8
|
+
store = initialize_composite_store
|
30
9
|
else
|
31
|
-
|
10
|
+
store = Lawnchair::StorageEngine::Redis
|
32
11
|
end
|
33
|
-
|
34
|
-
if key_exists && !options[:force]
|
35
|
-
if options[:in_process]
|
36
|
-
Marshal.load(@@in_process_store[compute_key(options[:key])])
|
37
|
-
else
|
38
|
-
Marshal.load(Lawnchair.redis[compute_key(options[:key])])
|
39
|
-
end
|
40
|
-
else
|
41
|
-
if options[:in_process] && exists?(options[:key])
|
42
|
-
cached_val = Lawnchair.redis[compute_key(options[:key])]
|
43
|
-
@@in_process_store[compute_key(options[:key])] = cached_val
|
44
|
-
return Marshal.dump(cached_val)
|
45
|
-
end
|
46
|
-
|
47
|
-
val = block.call
|
48
|
-
expires_in = compute_expiry(options[:expires_in])
|
49
|
-
dumped_val = Marshal.dump(val)
|
50
|
-
@@in_process_store[compute_key(options[:key])] = dumped_val if options[:in_process]
|
51
|
-
Lawnchair.redis.set(compute_key(options[:key]), dumped_val, expires_in)
|
52
|
-
return val
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def self.compute_key(key)
|
57
|
-
"Lawnchair:#{key}"
|
12
|
+
store.fetch(key, options, &block)
|
58
13
|
end
|
59
14
|
|
60
|
-
def self.
|
61
|
-
Lawnchair.
|
15
|
+
def self.initialize_composite_store
|
16
|
+
composite_store = Lawnchair::StorageEngine::Composite.new
|
17
|
+
composite_store.register_storage_engine(Lawnchair::StorageEngine::InProcess)
|
18
|
+
composite_store.register_storage_engine(Lawnchair::StorageEngine::Redis)
|
19
|
+
composite_store
|
62
20
|
end
|
63
|
-
|
64
|
-
|
65
|
-
|
21
|
+
end
|
22
|
+
|
23
|
+
class << self
|
24
|
+
attr_reader :redis
|
25
|
+
|
26
|
+
def connectdb(redis=nil)
|
27
|
+
@redis = (redis || Redis.new(:db => 11))
|
66
28
|
end
|
67
|
-
|
68
|
-
def
|
69
|
-
|
29
|
+
|
30
|
+
def flushdb
|
31
|
+
redis.flushdb
|
70
32
|
end
|
71
33
|
end
|
72
34
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Lawnchair
|
2
|
+
module StorageEngine
|
3
|
+
class Abstract
|
4
|
+
class << self
|
5
|
+
attr_reader :cache_container
|
6
|
+
|
7
|
+
def cache_container
|
8
|
+
@cache_container ||= {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def fetch(key, options, &block)
|
12
|
+
if exists?(key)
|
13
|
+
value = get(key, options)
|
14
|
+
else
|
15
|
+
value = block.call
|
16
|
+
set(key, value, options)
|
17
|
+
end
|
18
|
+
value
|
19
|
+
end
|
20
|
+
|
21
|
+
def get(key, options={})
|
22
|
+
if options[:raw]
|
23
|
+
cache_container[computed_key(key)]
|
24
|
+
else
|
25
|
+
exists?(key) ? Marshal.load(cache_container[computed_key(key)]) : nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def computed_key(key)
|
30
|
+
raise "Missiing key" if key.nil? || key.empty?
|
31
|
+
prefix = "Lawnchair"
|
32
|
+
"#{prefix}:#{key}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Lawnchair
|
2
|
+
module StorageEngine
|
3
|
+
class Composite
|
4
|
+
attr_reader :storage_engines
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@storage_engines = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def register_storage_engine(storage_engine)
|
11
|
+
storage_engines << storage_engine
|
12
|
+
end
|
13
|
+
|
14
|
+
def fetch(key, options, &block)
|
15
|
+
raise "No Storage Engines Configured" if storage_engines.empty?
|
16
|
+
|
17
|
+
value, index = find_in_storage(key, options)
|
18
|
+
value ||= yield
|
19
|
+
place_in_storage(key, value, options, index)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def find_in_storage(key, options)
|
25
|
+
value, index = nil, nil
|
26
|
+
storage_engines.each_with_index do |storage_engine, i|
|
27
|
+
if storage_engine.exists?(key)
|
28
|
+
value = storage_engine.get(key, options)
|
29
|
+
index = i
|
30
|
+
break
|
31
|
+
end
|
32
|
+
end
|
33
|
+
return value, index
|
34
|
+
end
|
35
|
+
|
36
|
+
def place_in_storage(key, value, options, index)
|
37
|
+
storage_engines.each_with_index do |storage_engine, i|
|
38
|
+
break if i == index
|
39
|
+
storage_engine.set(key, value, options)
|
40
|
+
end
|
41
|
+
value
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Lawnchair
|
2
|
+
module StorageEngine
|
3
|
+
class InProcess < Abstract
|
4
|
+
@@cache_container = {}
|
5
|
+
class << self
|
6
|
+
|
7
|
+
def cache_container
|
8
|
+
@@cache_container
|
9
|
+
end
|
10
|
+
|
11
|
+
def set(key, value, options={})
|
12
|
+
if options[:raw]
|
13
|
+
cache_container[computed_key(key)] = value
|
14
|
+
else
|
15
|
+
cache_container[computed_key(key)] = Marshal.dump(value)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def exists?(key)
|
20
|
+
cache_container.has_key?(computed_key(key))
|
21
|
+
end
|
22
|
+
|
23
|
+
def expire!(key)
|
24
|
+
cache_container.delete(computed_key(key))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Lawnchair
|
2
|
+
module StorageEngine
|
3
|
+
class Redis < Abstract
|
4
|
+
class << self
|
5
|
+
def cache_container
|
6
|
+
Lawnchair.redis
|
7
|
+
end
|
8
|
+
|
9
|
+
def set(key, value, options={})
|
10
|
+
ttl = options[:expires_in] || 3600
|
11
|
+
if options[:raw]
|
12
|
+
cache_container.set(computed_key(key), value, ttl)
|
13
|
+
else
|
14
|
+
cache_container.set(computed_key(key), Marshal.dump(value), ttl)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def exists?(key)
|
19
|
+
cache_container.exists(computed_key(key))
|
20
|
+
end
|
21
|
+
|
22
|
+
def expire!(key)
|
23
|
+
cache_container.del(computed_key(key))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/view/helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'action_view'
|
2
|
+
module Lawnchair
|
3
|
+
module View
|
4
|
+
module Helper
|
5
|
+
def lawnchair_cache(key, &block)
|
6
|
+
rendered_value = Lawnchair::Cache.me({:key => key, :raw => true}) do
|
7
|
+
capture(&block)
|
8
|
+
end
|
9
|
+
concat(rendered_value)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
ActionView::Base.send(:include, Lawnchair::View::Helper)
|
data/spec/lawnchair_spec.rb
CHANGED
@@ -2,94 +2,29 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
2
2
|
|
3
3
|
describe "Lawnchair::Cache" do
|
4
4
|
describe ".me" do
|
5
|
-
it "raises an exception if no key is given" do
|
6
|
-
lambda do
|
7
|
-
Lawnchair::Cache.me { 1 }
|
8
|
-
end.should raise_error("Cache key please!")
|
9
|
-
end
|
10
|
-
|
11
5
|
it "returns the value if it exists" do
|
12
6
|
expected_object = [1,2,3,4]
|
13
|
-
Lawnchair::Cache.me(
|
7
|
+
Lawnchair::Cache.me("marshalled_array") { expected_object }
|
14
8
|
|
15
|
-
x = Lawnchair::Cache.me(
|
9
|
+
x = Lawnchair::Cache.me("marshalled_array") { "JUNK DATA" }
|
16
10
|
x.should == expected_object
|
17
11
|
end
|
18
12
|
|
19
13
|
it "marshalls the object into redis" do
|
20
14
|
expected_object = [1,2,3,4]
|
21
|
-
Lawnchair::Cache.me(
|
15
|
+
Lawnchair::Cache.me("marshalled_array") { expected_object }
|
22
16
|
|
23
17
|
Marshal.load(Lawnchair.redis["Lawnchair:marshalled_array"]).should == [1,2,3,4]
|
24
18
|
end
|
25
19
|
|
26
|
-
describe "when passed :force => true" do
|
27
|
-
it "expires the key and sets it to the new return value" do
|
28
|
-
initial_expected_object = [1,2,3,4]
|
29
|
-
new_expected_object = [1,2,3]
|
30
|
-
Lawnchair::Cache.me(:key => "marshalled_array") { initial_expected_object }
|
31
|
-
Marshal.load(Lawnchair.redis["Lawnchair:marshalled_array"]).should == [1,2,3,4]
|
32
|
-
|
33
|
-
Lawnchair::Cache.me(:key => "marshalled_array", :force => true) { new_expected_object }
|
34
|
-
Marshal.load(Lawnchair.redis["Lawnchair:marshalled_array"]).should == [1,2,3]
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
20
|
describe "when in_process => true" do
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
describe "when the value exists in redis" do
|
49
|
-
it "takes the value from redis and places it in the in process cache" do
|
50
|
-
Lawnchair::Cache.in_process_store.delete("Lawnchair:marshalled_array")
|
51
|
-
expected_object = [1,2,3,4]
|
52
|
-
unexpected_object = [1,2,3,4,5,6,7,8]
|
53
|
-
Lawnchair::Cache.me(:key => "marshalled_array") { expected_object }
|
54
|
-
Lawnchair::Cache.in_process_store["Lawnchair:marshalled_array"].should be_nil
|
55
|
-
Lawnchair::Cache.me(:key => "marshalled_array", :in_process => true) { unexpected_object }
|
56
|
-
Marshal.load(Lawnchair::Cache.in_process_store["Lawnchair:marshalled_array"]).should == expected_object
|
57
|
-
end
|
21
|
+
it "fetches the value to/from the composite store" do
|
22
|
+
mock_composite_engine = Lawnchair::StorageEngine::Composite.new
|
23
|
+
Lawnchair::StorageEngine::Composite.stub!(:new).and_return(mock_composite_engine)
|
24
|
+
|
25
|
+
mock_composite_engine.should_receive(:fetch)
|
26
|
+
Lawnchair::Cache.me("mu", :in_process => true, :raw => true) { "fasa" }
|
58
27
|
end
|
59
28
|
end
|
60
|
-
|
61
|
-
it "sets a default ttl of 60 minutes" do
|
62
|
-
Lawnchair::Cache.me(:key => "pizza") { "muschroom/onion" }
|
63
|
-
Lawnchair.redis.ttl("Lawnchair:pizza").should == 3600 # seconds
|
64
|
-
end
|
65
|
-
|
66
|
-
it "allows you to override the default ttl" do
|
67
|
-
Lawnchair::Cache.me(:key => "pizza", :expires_in => 1) { "muschroom/onion" }
|
68
|
-
Lawnchair.redis.ttl("Lawnchair:pizza").should == 1 # seconds
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
describe ".exists?" do
|
73
|
-
it "returns false when the key does not exist" do
|
74
|
-
Lawnchair.redis.keys('*').should_not include("Lawnchair:mu")
|
75
|
-
Lawnchair::Cache.exists?("mu").should be_false
|
76
|
-
end
|
77
|
-
|
78
|
-
it "returns true when the key exists" do
|
79
|
-
Lawnchair.redis["Lawnchair:mu"] = "fasa"
|
80
|
-
Lawnchair.redis.keys('*').should include("Lawnchair:mu")
|
81
|
-
Lawnchair::Cache.exists?("mu").should be_true
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
describe ".expire" do
|
86
|
-
it "should only expire the key specified" do
|
87
|
-
Lawnchair.redis["Lawnchair:mu"] = "fasa"
|
88
|
-
Lawnchair.redis["Lawnchair:sim"] = "ba"
|
89
|
-
|
90
|
-
Lawnchair::Cache.expire("mu")
|
91
|
-
Lawnchair.redis["Lawnchair:mu"].should be_nil
|
92
|
-
Lawnchair.redis["Lawnchair:sim"].should == "ba"
|
93
|
-
end
|
94
29
|
end
|
95
30
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -8,5 +8,12 @@ require 'redis'
|
|
8
8
|
|
9
9
|
Spec::Runner.configure do |config|
|
10
10
|
config.before(:all) { Lawnchair.connectdb(Redis.new(:db => 11)) }
|
11
|
-
config.before(:each)
|
11
|
+
config.before(:each) do
|
12
|
+
Lawnchair.flushdb
|
13
|
+
abstract_store = Lawnchair::StorageEngine::Abstract
|
14
|
+
abstract_store.cache_container.keys.each {|k| abstract_store.cache_container.delete(k)}
|
15
|
+
|
16
|
+
in_process = Lawnchair::StorageEngine::InProcess
|
17
|
+
in_process.cache_container.keys.each {|k| in_process.cache_container.delete(k)}
|
18
|
+
end
|
12
19
|
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe "Lawnchair::StorageEngine::Abstract" do
|
4
|
+
attr_reader :abstract_store
|
5
|
+
|
6
|
+
before do
|
7
|
+
@abstract_store = Lawnchair::StorageEngine::Abstract
|
8
|
+
end
|
9
|
+
|
10
|
+
describe ".cache_container" do
|
11
|
+
it "should be an empty hash" do
|
12
|
+
abstract_store.cache_container.should == {}
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe ".fetch" do
|
17
|
+
context "when key exists" do
|
18
|
+
before do
|
19
|
+
abstract_store.stub!(:exists?).and_return(true)
|
20
|
+
abstract_store.cache_container["Lawnchair:sim"] = "ba"
|
21
|
+
end
|
22
|
+
|
23
|
+
it "returns the value from the cache" do
|
24
|
+
value = abstract_store.fetch("sim", :raw => true) { "DOESNT MATTER" }
|
25
|
+
value.should == "ba"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context "when key does not exist" do
|
30
|
+
before do
|
31
|
+
abstract_store.stub!(:exists?).and_return(false)
|
32
|
+
abstract_store.cache_container["Lawnchair:sim"].should be_nil
|
33
|
+
|
34
|
+
class Lawnchair::StorageEngine::Abstract
|
35
|
+
def self.set(key, value, options={})
|
36
|
+
cache_container["Lawnchair:#{key}"] = value
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
it "computes the value and saves it to the cache" do
|
42
|
+
value = abstract_store.fetch("sim", :raw => true) { "ba" }
|
43
|
+
abstract_store.cache_container["Lawnchair:sim"].should == "ba"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe ".get" do
|
49
|
+
context "when raw is true" do
|
50
|
+
it "gets the value in key if it exists" do
|
51
|
+
abstract_store.cache_container["Lawnchair:mu"] = "fasa"
|
52
|
+
abstract_store.get("mu", :raw => true).should == "fasa"
|
53
|
+
end
|
54
|
+
|
55
|
+
it "returns nil if the key does not exist" do
|
56
|
+
abstract_store.cache_container["mu"].should be_nil
|
57
|
+
abstract_store.get("mu", :raw => true).should be_nil
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context "when raw is false" do
|
62
|
+
context "when they key exists" do
|
63
|
+
before do
|
64
|
+
abstract_store.stub!(:exists?).and_return(true)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "gets the value in key if it exists and unmarshalls it" do
|
68
|
+
expected_value = "fasa"
|
69
|
+
value = Marshal.dump(expected_value)
|
70
|
+
|
71
|
+
abstract_store.cache_container["Lawnchair:mu"] = value
|
72
|
+
abstract_store.get("mu", :raw => false).should == expected_value
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context "when the key does not exist" do
|
77
|
+
before do
|
78
|
+
abstract_store.stub!(:exists?).and_return(false)
|
79
|
+
end
|
80
|
+
|
81
|
+
it "returns nil if the key does not exist" do
|
82
|
+
abstract_store.cache_container["Lawnchair:mu"].should be_nil
|
83
|
+
abstract_store.get("mu", :raw => false).should be_nil
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe ".computed_key" do
|
90
|
+
it "should prepend keys with Lawnchair:" do
|
91
|
+
abstract_store.computed_key("hooo").should == "Lawnchair:hooo"
|
92
|
+
end
|
93
|
+
it "raises an exception if no key is given" do
|
94
|
+
lambda do
|
95
|
+
abstract_store.computed_key("") { 1 }
|
96
|
+
end.should raise_error
|
97
|
+
|
98
|
+
lambda do
|
99
|
+
abstract_store.computed_key(nil)
|
100
|
+
end.should raise_error
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe "Lawnchair::StorageEngine::Composite" do
|
4
|
+
attr_reader :composite_store
|
5
|
+
|
6
|
+
before do
|
7
|
+
@composite_store = Lawnchair::StorageEngine::Composite.new
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "initialization" do
|
11
|
+
it "has a collection of storage_engines" do
|
12
|
+
composite_store.storage_engines == []
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#register_storage_engine" do
|
17
|
+
before do
|
18
|
+
composite_store.storage_engines.should be_empty
|
19
|
+
end
|
20
|
+
|
21
|
+
it "adds a storage engine to the collection" do
|
22
|
+
composite_store.register_storage_engine Lawnchair::StorageEngine::Redis
|
23
|
+
composite_store.storage_engines.should == [Lawnchair::StorageEngine::Redis]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#fetch" do
|
28
|
+
context "when no storage engines have been configured" do
|
29
|
+
it "raises an exception" do
|
30
|
+
lambda do
|
31
|
+
composite_store.fetch("key", {}) {x=1}
|
32
|
+
end.should raise_error("No Storage Engines Configured")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context "when there is only 1 storage engine" do
|
37
|
+
before do
|
38
|
+
composite_store.register_storage_engine Lawnchair::StorageEngine::Redis
|
39
|
+
end
|
40
|
+
|
41
|
+
context "when the key does not exist" do
|
42
|
+
it "sets the value on the key in the storage engine specified" do
|
43
|
+
Lawnchair.redis["Lawnchair:mu"].should be_nil
|
44
|
+
composite_store.fetch("mu", {:raw => true}) { "fasa" }
|
45
|
+
Lawnchair.redis["Lawnchair:mu"].should == "fasa"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context "when the key exists" do
|
50
|
+
before do
|
51
|
+
Lawnchair.redis["Lawnchair:sim"] = "ba"
|
52
|
+
end
|
53
|
+
|
54
|
+
it "returns the value in the key from the storage engine specified" do
|
55
|
+
value = composite_store.fetch("sim", {:raw => true}) { "DOESNT MATTER" }
|
56
|
+
value.should == "ba"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context "when there are two storage engines" do
|
62
|
+
before do
|
63
|
+
composite_store.register_storage_engine Lawnchair::StorageEngine::InProcess
|
64
|
+
composite_store.register_storage_engine Lawnchair::StorageEngine::Redis
|
65
|
+
end
|
66
|
+
|
67
|
+
context "when the key exists in the first storage engine" do
|
68
|
+
before do
|
69
|
+
Lawnchair::StorageEngine::InProcess.set("mu", "fasa", :raw => true)
|
70
|
+
Lawnchair::StorageEngine::Redis.get("mu").should be_nil
|
71
|
+
end
|
72
|
+
|
73
|
+
it "returns the value from the first storage engine" do
|
74
|
+
value = composite_store.fetch("mu", {:raw => true}) { "DOESNT MATTER" }
|
75
|
+
value.should == "fasa"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context "when the key exists in the second storage engine but not the first" do
|
80
|
+
before do
|
81
|
+
Lawnchair::StorageEngine::InProcess.get("mu").should be_nil
|
82
|
+
Lawnchair::StorageEngine::Redis.set("mu", "fasa", :raw => true)
|
83
|
+
end
|
84
|
+
|
85
|
+
it "places the value in the first storage engine" do
|
86
|
+
composite_store.fetch("mu", {:raw => true}) { "DOESNT MATTER" }.should == "fasa"
|
87
|
+
Lawnchair::StorageEngine::InProcess.get("mu", :raw => true).should == "fasa"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context "when the key doesnt exist in either storage engine" do
|
92
|
+
before do
|
93
|
+
Lawnchair::StorageEngine::InProcess.get("mu").should be_nil
|
94
|
+
Lawnchair::StorageEngine::Redis.get("mu").should be_nil
|
95
|
+
end
|
96
|
+
|
97
|
+
it "sets the value in both storage engines" do
|
98
|
+
composite_store.fetch("mu", {:raw => true}) { sleep 0.2; "fasa" }
|
99
|
+
Lawnchair::StorageEngine::InProcess.get("mu", :raw => true).should == "fasa"
|
100
|
+
Lawnchair::StorageEngine::Redis.get("mu", :raw => true).should == "fasa"
|
101
|
+
end
|
102
|
+
|
103
|
+
it "only calls the block 1 time for both engines" # spec should take less than .4 seconds to run
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe "Lawnchair::StorageEngine::InProcessStore" do
|
4
|
+
attr_reader :in_process_store
|
5
|
+
|
6
|
+
before do
|
7
|
+
@in_process_store = Lawnchair::StorageEngine::InProcess
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "#cache_container" do
|
11
|
+
it "returns the redis cache object" do
|
12
|
+
Lawnchair::StorageEngine::InProcess.send(:class_variable_set, "@@cache_container", {"Lawnchair:mu" => "fasa"})
|
13
|
+
in_process_store.cache_container["Lawnchair:mu"].should == "fasa"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#set" do
|
18
|
+
context "when raw is true" do
|
19
|
+
it "sets the value" do
|
20
|
+
in_process_store.cache_container["Lawnchair:mu"].should be_nil
|
21
|
+
in_process_store.set("mu", "fasa", :raw => true)
|
22
|
+
in_process_store.cache_container["Lawnchair:mu"].should == "fasa"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "when raw is false" do
|
27
|
+
it "sets the value" do
|
28
|
+
value = "fasa"
|
29
|
+
expected_value = Marshal.dump(value)
|
30
|
+
|
31
|
+
in_process_store.cache_container["Lawnchair:mu"].should be_nil
|
32
|
+
in_process_store.set("mu", value, :raw => false)
|
33
|
+
in_process_store.cache_container["Lawnchair:mu"].should == expected_value
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "exists?" do
|
39
|
+
it "returns false when the key does not exist" do
|
40
|
+
in_process_store.cache_container.keys.should_not include("Lawnchair:mu")
|
41
|
+
in_process_store.exists?("mu").should be_false
|
42
|
+
end
|
43
|
+
|
44
|
+
it "returns true when the key exists" do
|
45
|
+
in_process_store.cache_container["Lawnchair:mu"] = "fasa"
|
46
|
+
in_process_store.cache_container.keys.should include("Lawnchair:mu")
|
47
|
+
in_process_store.exists?("mu").should be_true
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "#expire!" do
|
52
|
+
it "should only expire the key specified" do
|
53
|
+
in_process_store.cache_container["Lawnchair:mu"] = "fasa"
|
54
|
+
in_process_store.cache_container["Lawnchair:sim"] = "ba"
|
55
|
+
|
56
|
+
in_process_store.expire!("mu")
|
57
|
+
in_process_store.cache_container["Lawnchair:mu"].should be_nil
|
58
|
+
in_process_store.cache_container["Lawnchair:sim"].should == "ba"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe "Lawnchair::StorageEngine::RedisStore" do
|
4
|
+
attr_reader :redis_store
|
5
|
+
|
6
|
+
before do
|
7
|
+
@redis_store = Lawnchair::StorageEngine::Redis
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "#cache_container" do
|
11
|
+
it "returns the redis cache object" do
|
12
|
+
Lawnchair.redis["Lawnchair:mu"] = "fasa"
|
13
|
+
redis_store.cache_container["Lawnchair:mu"].should == "fasa"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#set" do
|
18
|
+
it "sets a default ttl of 60 minutes" do
|
19
|
+
redis_store.set("mu", "fasa")
|
20
|
+
Lawnchair.redis.ttl("Lawnchair:mu").should == 3600 # seconds
|
21
|
+
end
|
22
|
+
|
23
|
+
it "allows you to override the default ttl" do
|
24
|
+
redis_store.set("mu", "fasa", :expires_in => 600)
|
25
|
+
|
26
|
+
Lawnchair.redis.ttl("Lawnchair:mu").should == 600 # seconds
|
27
|
+
end
|
28
|
+
|
29
|
+
context "when raw is true" do
|
30
|
+
it "sets the value in redis" do
|
31
|
+
Lawnchair.redis["Lawnchair:mu"].should be_nil
|
32
|
+
redis_store.set("mu", "fasa", :raw => true)
|
33
|
+
Lawnchair.redis["Lawnchair:mu"].should == "fasa"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "when raw is false" do
|
38
|
+
it "sets the value in redis" do
|
39
|
+
value = "fasa"
|
40
|
+
expected_value = Marshal.dump(value)
|
41
|
+
|
42
|
+
Lawnchair.redis["Lawnchair:mu"].should be_nil
|
43
|
+
redis_store.set("mu", value, :raw => false)
|
44
|
+
Lawnchair.redis["Lawnchair:mu"].should == expected_value
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "exists?" do
|
50
|
+
it "returns false when the key does not exist" do
|
51
|
+
Lawnchair.redis.keys('*').should_not include("Lawnchair:mu")
|
52
|
+
redis_store.exists?("mu").should be_false
|
53
|
+
end
|
54
|
+
|
55
|
+
it "returns true when the key exists" do
|
56
|
+
Lawnchair.redis["Lawnchair:mu"] = "fasa"
|
57
|
+
Lawnchair.redis.keys('*').should include("Lawnchair:mu")
|
58
|
+
redis_store.exists?("mu").should be_true
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "#expire!" do
|
63
|
+
it "should only expire the key specified" do
|
64
|
+
Lawnchair.redis["Lawnchair:mu"] = "fasa"
|
65
|
+
Lawnchair.redis["Lawnchair:sim"] = "ba"
|
66
|
+
|
67
|
+
redis_store.expire!("mu")
|
68
|
+
Lawnchair.redis["Lawnchair:mu"].should be_nil
|
69
|
+
Lawnchair.redis["Lawnchair:sim"].should == "ba"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lawnchair
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shane Wolf
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-02-
|
12
|
+
date: 2010-02-12 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -30,11 +30,20 @@ files:
|
|
30
30
|
- VERSION
|
31
31
|
- lawnchair.gemspec
|
32
32
|
- lib/lawnchair.rb
|
33
|
+
- lib/storage_engine/abstract.rb
|
34
|
+
- lib/storage_engine/composite.rb
|
35
|
+
- lib/storage_engine/in_process.rb
|
36
|
+
- lib/storage_engine/redis.rb
|
37
|
+
- lib/view/helper.rb
|
33
38
|
- spec/lawnchair_spec.rb
|
34
39
|
- spec/spec.opts
|
35
40
|
- spec/spec_helper.rb
|
36
41
|
- spec/speed.rb
|
37
42
|
- spec/speed_results.png
|
43
|
+
- spec/storage_engine/abstract_spec.rb
|
44
|
+
- spec/storage_engine/composite_spec.rb
|
45
|
+
- spec/storage_engine/in_process_spec.rb
|
46
|
+
- spec/storage_engine/redis_spec.rb
|
38
47
|
has_rdoc: true
|
39
48
|
homepage: http://github.com/gizm0duck/lawnchair
|
40
49
|
licenses: []
|
@@ -67,3 +76,7 @@ test_files:
|
|
67
76
|
- spec/lawnchair_spec.rb
|
68
77
|
- spec/spec_helper.rb
|
69
78
|
- spec/speed.rb
|
79
|
+
- spec/storage_engine/abstract_spec.rb
|
80
|
+
- spec/storage_engine/composite_spec.rb
|
81
|
+
- spec/storage_engine/in_process_spec.rb
|
82
|
+
- spec/storage_engine/redis_spec.rb
|