lawnchair 0.5.1 → 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +33 -13
- data/Rakefile +3 -2
- data/VERSION +1 -1
- data/lawnchair.gemspec +8 -4
- data/lib/lawnchair.rb +11 -10
- data/lib/marshal_extension.rb +19 -0
- data/lib/storage_engine/abstract.rb +5 -5
- data/lib/storage_engine/composite.rb +7 -3
- data/lib/storage_engine/in_process.rb +7 -7
- data/lib/storage_engine/redis.rb +5 -5
- data/lib/view/helper.rb +1 -1
- data/spec/spec_helper.rb +2 -4
- data/spec/speed.rb +6 -6
- data/spec/storage_engine/abstract_spec.rb +10 -10
- data/spec/storage_engine/composite_spec.rb +8 -4
- data/spec/storage_engine/in_process_spec.rb +14 -14
- data/spec/storage_engine/redis_spec.rb +2 -2
- metadata +16 -6
data/README.rdoc
CHANGED
@@ -1,11 +1,8 @@
|
|
1
1
|
= Lawnchair
|
2
2
|
|
3
|
-
|
3
|
+
Fully featured caching mechanism for arbitrary pieces of resource expensive ruby code using Redis while being able to optionally store data in the Ruby process itself for maximum efficiency.
|
4
4
|
|
5
|
-
|
6
|
-
git clone git://github.com/ezmobius/redis-rb.git
|
7
|
-
cd redis-rb
|
8
|
-
rake redis:install
|
5
|
+
Lawnchair includes a Rails view helper that can be used to cache the rendered view code, but other than that everything should work fine in a Merb, Sinatra, or plain old Ruby app.
|
9
6
|
|
10
7
|
== Installation
|
11
8
|
|
@@ -27,7 +24,7 @@ This will connect to a default database on localhost, if you want to connect to
|
|
27
24
|
|
28
25
|
Obligatory example:
|
29
26
|
|
30
|
-
Lawnchair::Cache.me(
|
27
|
+
Lawnchair::Cache.me("cache_key2") do
|
31
28
|
# ideally this would be something a little more computationally expensive, but sleep will have to do
|
32
29
|
(1..3).inject([]) do
|
33
30
|
|set, i| set << Time.now.strftime("%H:%M:%S")
|
@@ -40,32 +37,55 @@ The return value is exactly what you think it should be
|
|
40
37
|
|
41
38
|
["12:26:08", "12:26:09", "12:26:10"]
|
42
39
|
|
43
|
-
Now, since it is cached, any time this block method is called (for the next 60
|
40
|
+
Now, since it is cached, any time this block method is called (for the next 60 minutes) it will return those values. also, you will note it comes back instantly, instead of waiting on those sleeps.
|
44
41
|
|
45
42
|
If an hour is too long, or short for the cache key expiration you can set that to anything you want using the :expires_in hash key and entering a time in seconds
|
46
43
|
|
47
|
-
Lawnchair::Cache.me(
|
44
|
+
Lawnchair::Cache.me("cache_key", :expires_in => 1.day) do
|
48
45
|
# expensive code to be cached for 24 hours
|
49
46
|
end
|
50
47
|
|
48
|
+
Available options:
|
49
|
+
* :expires_in - takes a time in seconds and will be set as the ttl on the key (only works for Redis store)
|
50
|
+
* :raw - tells the cache not to marshall the data, if you are storing a string value, this is the way to go
|
51
|
+
* :in_process - stores the value in memory for as long as the ruby process is running as well as in redis
|
52
|
+
|
51
53
|
== In Process Caching
|
52
54
|
|
53
55
|
If you want to get really fancy you can cache the values in process as well as in Redis. This can be a fairly significant win
|
54
56
|
if you are running the Redis server on a different physical machine as all network latency is taken out of the equation, especially if you are hitting a cache key many times on the same request. Also, it's probably best not to store TONS of keys in there, as your ruby process can bloat fairly quickly if you put everything in there. Also, these will persist as long as the process is running, unless you manually expire it.
|
55
57
|
|
56
|
-
Lawnchair::Cache.me(
|
58
|
+
Lawnchair::Cache.me("cache_key3", :in_process => true) do
|
57
59
|
# expensive code to be cached in process AND in redis
|
58
60
|
end
|
59
61
|
|
60
62
|
This code will get cached in redis as well, so each different process that runs the expensive code in the block will get the value from redis, instead of having to run it to get the value.
|
61
63
|
|
62
|
-
==
|
64
|
+
== Accessing DataStores Directly
|
65
|
+
|
66
|
+
There are currently two different storage engines (Redis and InProcess) that you can use either together or independently, depending on your needs. If you want to just store something in process for example you can do
|
67
|
+
|
68
|
+
Lawnchair::StorageEngine::InProcess.fetch("cache_key4", :raw => true) do
|
69
|
+
# expensive code to be cached in process
|
70
|
+
end
|
71
|
+
|
72
|
+
Also, you can expire a key for a given storage engine directly by calling
|
73
|
+
|
74
|
+
Lawnchair::StorageEngine::InProcess.expire!("cache_key3") # For memory store
|
75
|
+
or
|
76
|
+
Lawnchair::StorageEngine::Redis.expire!("cache_key3") # For redis store
|
63
77
|
|
64
|
-
|
78
|
+
You can also access any of the methods for a given datastore directly, and choose to expire a key in whatever store you want.
|
65
79
|
|
66
|
-
|
80
|
+
Available methods are:
|
81
|
+
* get - get a value for a key
|
82
|
+
* set - set a value for a key regardless of whether or not it exists
|
83
|
+
* fetch - get a value if it exists for a given key, otherwise set it
|
84
|
+
* expire! - forcefully expire a key
|
85
|
+
* exists? - check if a given key exists
|
86
|
+
* data_store - access the datastore's values directly like a hash
|
67
87
|
|
68
|
-
If you need to flush all the values in the database
|
88
|
+
If you need to flush all the values in the Redis database
|
69
89
|
|
70
90
|
Lawnchair.flushdb
|
71
91
|
|
data/Rakefile
CHANGED
@@ -5,11 +5,12 @@ begin
|
|
5
5
|
require 'jeweler'
|
6
6
|
Jeweler::Tasks.new do |gem|
|
7
7
|
gem.name = "lawnchair"
|
8
|
-
gem.summary = "
|
9
|
-
gem.description = "
|
8
|
+
gem.summary = "Speed up your app by caching expensive code in Redis or in the ruby process itself"
|
9
|
+
gem.description = "Fully featured caching mechanism for arbitrary pieces of resource expensive ruby code using Redis while being able to optionally store data in the Ruby process itself for maximum efficiency."
|
10
10
|
gem.email = "shanewolf@gmail.com"
|
11
11
|
gem.homepage = "http://github.com/gizm0duck/lawnchair"
|
12
12
|
gem.authors = ["Shane Wolf"]
|
13
|
+
gem.add_dependency "redis"
|
13
14
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
14
15
|
end
|
15
16
|
Jeweler::GemcutterTasks.new
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.5.
|
1
|
+
0.5.2
|
data/lawnchair.gemspec
CHANGED
@@ -5,12 +5,12 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{lawnchair}
|
8
|
-
s.version = "0.5.
|
8
|
+
s.version = "0.5.2"
|
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-
|
13
|
-
s.description = %q{
|
12
|
+
s.date = %q{2010-02-14}
|
13
|
+
s.description = %q{Fully featured caching mechanism for arbitrary pieces of resource expensive ruby code using Redis while being able to optionally store data in the Ruby process itself for maximum efficiency.}
|
14
14
|
s.email = %q{shanewolf@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
16
16
|
"LICENSE",
|
@@ -24,6 +24,7 @@ Gem::Specification.new do |s|
|
|
24
24
|
"VERSION",
|
25
25
|
"lawnchair.gemspec",
|
26
26
|
"lib/lawnchair.rb",
|
27
|
+
"lib/marshal_extension.rb",
|
27
28
|
"lib/storage_engine/abstract.rb",
|
28
29
|
"lib/storage_engine/composite.rb",
|
29
30
|
"lib/storage_engine/in_process.rb",
|
@@ -43,7 +44,7 @@ Gem::Specification.new do |s|
|
|
43
44
|
s.rdoc_options = ["--charset=UTF-8"]
|
44
45
|
s.require_paths = ["lib"]
|
45
46
|
s.rubygems_version = %q{1.3.5}
|
46
|
-
s.summary = %q{
|
47
|
+
s.summary = %q{Speed up your app by caching expensive code in Redis or in the ruby process itself}
|
47
48
|
s.test_files = [
|
48
49
|
"spec/lawnchair_spec.rb",
|
49
50
|
"spec/spec_helper.rb",
|
@@ -59,9 +60,12 @@ Gem::Specification.new do |s|
|
|
59
60
|
s.specification_version = 3
|
60
61
|
|
61
62
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
63
|
+
s.add_runtime_dependency(%q<redis>, [">= 0"])
|
62
64
|
else
|
65
|
+
s.add_dependency(%q<redis>, [">= 0"])
|
63
66
|
end
|
64
67
|
else
|
68
|
+
s.add_dependency(%q<redis>, [">= 0"])
|
65
69
|
end
|
66
70
|
end
|
67
71
|
|
data/lib/lawnchair.rb
CHANGED
@@ -1,24 +1,25 @@
|
|
1
|
-
|
1
|
+
require 'rubygems'
|
2
2
|
require 'redis'
|
3
|
-
require '
|
3
|
+
require 'storage_engine/abstract'
|
4
|
+
require 'storage_engine/redis'
|
5
|
+
require 'storage_engine/in_process'
|
6
|
+
require 'storage_engine/composite'
|
7
|
+
|
8
|
+
if defined? RAILS_ENV
|
9
|
+
require 'marshal_extension' if RAILS_ENV == "development"
|
10
|
+
require 'view/helper'
|
11
|
+
end
|
4
12
|
|
5
13
|
module Lawnchair
|
6
14
|
class Cache
|
7
15
|
def self.me(key, options={}, &block)
|
8
16
|
if options[:in_process]
|
9
|
-
store =
|
17
|
+
store = Lawnchair::StorageEngine::Composite.new(:in_process, :redis)
|
10
18
|
else
|
11
19
|
store = Lawnchair::StorageEngine::Redis
|
12
20
|
end
|
13
21
|
store.fetch(key, options, &block)
|
14
22
|
end
|
15
|
-
|
16
|
-
def self.initialize_composite_store
|
17
|
-
composite_store = Lawnchair::StorageEngine::Composite.new
|
18
|
-
composite_store.register_storage_engine(Lawnchair::StorageEngine::InProcess)
|
19
|
-
composite_store.register_storage_engine(Lawnchair::StorageEngine::Redis)
|
20
|
-
composite_store
|
21
|
-
end
|
22
23
|
end
|
23
24
|
|
24
25
|
class << self
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Shamelessly swiped from: http://pastie.org/720905
|
2
|
+
# Initial implementation from: http://kballcodes.com/2009/09/05/rails-memcached-a-better-solution-to-the-undefined-classmodule-problem/
|
3
|
+
class << Marshal
|
4
|
+
def load_with_rails_classloader(*args)
|
5
|
+
begin
|
6
|
+
load_without_rails_classloader(*args)
|
7
|
+
rescue ArgumentError, NameError => e
|
8
|
+
if e.message =~ %r(undefined class/module)
|
9
|
+
const = e.message.split(' ').last
|
10
|
+
const.constantize
|
11
|
+
retry
|
12
|
+
else
|
13
|
+
raise(e)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
alias_method_chain :load, :rails_classloader
|
19
|
+
end
|
@@ -2,10 +2,10 @@ module Lawnchair
|
|
2
2
|
module StorageEngine
|
3
3
|
class Abstract
|
4
4
|
class << self
|
5
|
-
attr_reader :
|
5
|
+
attr_reader :data_store
|
6
6
|
|
7
|
-
def
|
8
|
-
@
|
7
|
+
def data_store
|
8
|
+
@data_store ||= {}
|
9
9
|
end
|
10
10
|
|
11
11
|
def fetch(key, options, &block)
|
@@ -20,9 +20,9 @@ module Lawnchair
|
|
20
20
|
|
21
21
|
def get(key, options={})
|
22
22
|
if options[:raw]
|
23
|
-
|
23
|
+
data_store[computed_key(key)]
|
24
24
|
else
|
25
|
-
exists?(key) ? Marshal.load(
|
25
|
+
exists?(key) ? Marshal.load(data_store[computed_key(key)]) : nil
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
@@ -3,12 +3,16 @@ module Lawnchair
|
|
3
3
|
class Composite
|
4
4
|
attr_reader :storage_engines
|
5
5
|
|
6
|
-
def initialize
|
6
|
+
def initialize(*args)
|
7
7
|
@storage_engines = []
|
8
|
+
args.each do |arg|
|
9
|
+
register_storage_engine arg
|
10
|
+
end
|
8
11
|
end
|
9
12
|
|
10
13
|
def register_storage_engine(storage_engine)
|
11
|
-
|
14
|
+
klass = storage_engine == :redis ? "Redis" : "InProcess"
|
15
|
+
storage_engines << Object.module_eval("Lawnchair::StorageEngine::#{klass}")
|
12
16
|
end
|
13
17
|
|
14
18
|
def fetch(key, options, &block)
|
@@ -19,7 +23,7 @@ module Lawnchair
|
|
19
23
|
place_in_storage(key, value, options, index)
|
20
24
|
end
|
21
25
|
|
22
|
-
private
|
26
|
+
private
|
23
27
|
|
24
28
|
def find_in_storage(key, options)
|
25
29
|
value, index = nil, nil
|
@@ -1,27 +1,27 @@
|
|
1
1
|
module Lawnchair
|
2
2
|
module StorageEngine
|
3
3
|
class InProcess < Abstract
|
4
|
-
@@
|
4
|
+
@@data_store = {}
|
5
5
|
class << self
|
6
6
|
|
7
|
-
def
|
8
|
-
@@
|
7
|
+
def data_store
|
8
|
+
@@data_store
|
9
9
|
end
|
10
10
|
|
11
11
|
def set(key, value, options={})
|
12
12
|
if options[:raw]
|
13
|
-
|
13
|
+
data_store[computed_key(key)] = value
|
14
14
|
else
|
15
|
-
|
15
|
+
data_store[computed_key(key)] = Marshal.dump(value)
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
19
|
def exists?(key)
|
20
|
-
|
20
|
+
data_store.has_key?(computed_key(key))
|
21
21
|
end
|
22
22
|
|
23
23
|
def expire!(key)
|
24
|
-
|
24
|
+
data_store.delete(computed_key(key))
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
data/lib/storage_engine/redis.rb
CHANGED
@@ -2,25 +2,25 @@ module Lawnchair
|
|
2
2
|
module StorageEngine
|
3
3
|
class Redis < Abstract
|
4
4
|
class << self
|
5
|
-
def
|
5
|
+
def data_store
|
6
6
|
Lawnchair.redis
|
7
7
|
end
|
8
8
|
|
9
9
|
def set(key, value, options={})
|
10
10
|
ttl = options[:expires_in] || 3600
|
11
11
|
if options[:raw]
|
12
|
-
|
12
|
+
data_store.set(computed_key(key), value, ttl)
|
13
13
|
else
|
14
|
-
|
14
|
+
data_store.set(computed_key(key), Marshal.dump(value), ttl)
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
18
|
def exists?(key)
|
19
|
-
|
19
|
+
data_store.exists(computed_key(key))
|
20
20
|
end
|
21
21
|
|
22
22
|
def expire!(key)
|
23
|
-
|
23
|
+
data_store.del(computed_key(key))
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
data/lib/view/helper.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -1,19 +1,17 @@
|
|
1
1
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
2
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
|
-
require 'rubygems'
|
4
3
|
require 'lawnchair'
|
5
4
|
require 'spec'
|
6
5
|
require 'spec/autorun'
|
7
|
-
require 'redis'
|
8
6
|
|
9
7
|
Spec::Runner.configure do |config|
|
10
8
|
config.before(:all) { Lawnchair.connectdb(Redis.new(:db => 11)) }
|
11
9
|
config.before(:each) do
|
12
10
|
Lawnchair.flushdb
|
13
11
|
abstract_store = Lawnchair::StorageEngine::Abstract
|
14
|
-
abstract_store.
|
12
|
+
abstract_store.data_store.keys.each {|k| abstract_store.data_store.delete(k)}
|
15
13
|
|
16
14
|
in_process = Lawnchair::StorageEngine::InProcess
|
17
|
-
in_process.
|
15
|
+
in_process.data_store.keys.each {|k| in_process.data_store.delete(k)}
|
18
16
|
end
|
19
17
|
end
|
data/spec/speed.rb
CHANGED
@@ -8,10 +8,10 @@ Lawnchair.flushdb
|
|
8
8
|
# reading and marshalling the data isn't obscene
|
9
9
|
|
10
10
|
# *** Performing 1000 iterations ***
|
11
|
-
#
|
12
|
-
# cached:
|
13
|
-
#
|
14
|
-
|
11
|
+
# user system total real
|
12
|
+
# cached: 0.200000 0.050000 0.250000 ( 0.397476)
|
13
|
+
# in process cached: 0.090000 0.010000 0.100000 ( 0.088927)
|
14
|
+
# not cached: 26.710000 0.580000 27.290000 ( 27.331749)
|
15
15
|
n = (ARGV.shift || 1000).to_i
|
16
16
|
|
17
17
|
puts "*** Performing #{n} iterations ***"
|
@@ -26,7 +26,7 @@ end
|
|
26
26
|
Benchmark.bm(7) do |x|
|
27
27
|
x.report("cached:\t\t") do
|
28
28
|
(1..n).each do |i|
|
29
|
-
Lawnchair::Cache.me(
|
29
|
+
Lawnchair::Cache.me("redis_cache") do
|
30
30
|
expensive_stuff
|
31
31
|
end
|
32
32
|
end
|
@@ -34,7 +34,7 @@ Benchmark.bm(7) do |x|
|
|
34
34
|
|
35
35
|
x.report("in process cached:") do
|
36
36
|
(1..n).each do |i|
|
37
|
-
Lawnchair::Cache.me(:
|
37
|
+
Lawnchair::Cache.me("in_process_cache", :in_process => true) do
|
38
38
|
expensive_stuff
|
39
39
|
end
|
40
40
|
end
|
@@ -7,9 +7,9 @@ describe "Lawnchair::StorageEngine::Abstract" do
|
|
7
7
|
@abstract_store = Lawnchair::StorageEngine::Abstract
|
8
8
|
end
|
9
9
|
|
10
|
-
describe ".
|
10
|
+
describe ".data_store" do
|
11
11
|
it "should be an empty hash" do
|
12
|
-
abstract_store.
|
12
|
+
abstract_store.data_store.should == {}
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
@@ -17,7 +17,7 @@ describe "Lawnchair::StorageEngine::Abstract" do
|
|
17
17
|
context "when key exists" do
|
18
18
|
before do
|
19
19
|
abstract_store.stub!(:exists?).and_return(true)
|
20
|
-
abstract_store.
|
20
|
+
abstract_store.data_store["Lawnchair:sim"] = "ba"
|
21
21
|
end
|
22
22
|
|
23
23
|
it "returns the value from the cache" do
|
@@ -29,18 +29,18 @@ describe "Lawnchair::StorageEngine::Abstract" do
|
|
29
29
|
context "when key does not exist" do
|
30
30
|
before do
|
31
31
|
abstract_store.stub!(:exists?).and_return(false)
|
32
|
-
abstract_store.
|
32
|
+
abstract_store.data_store["Lawnchair:sim"].should be_nil
|
33
33
|
|
34
34
|
class Lawnchair::StorageEngine::Abstract
|
35
35
|
def self.set(key, value, options={})
|
36
|
-
|
36
|
+
data_store["Lawnchair:#{key}"] = value
|
37
37
|
end
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
41
|
it "computes the value and saves it to the cache" do
|
42
42
|
value = abstract_store.fetch("sim", :raw => true) { "ba" }
|
43
|
-
abstract_store.
|
43
|
+
abstract_store.data_store["Lawnchair:sim"].should == "ba"
|
44
44
|
end
|
45
45
|
end
|
46
46
|
end
|
@@ -48,12 +48,12 @@ describe "Lawnchair::StorageEngine::Abstract" do
|
|
48
48
|
describe ".get" do
|
49
49
|
context "when raw is true" do
|
50
50
|
it "gets the value in key if it exists" do
|
51
|
-
abstract_store.
|
51
|
+
abstract_store.data_store["Lawnchair:mu"] = "fasa"
|
52
52
|
abstract_store.get("mu", :raw => true).should == "fasa"
|
53
53
|
end
|
54
54
|
|
55
55
|
it "returns nil if the key does not exist" do
|
56
|
-
abstract_store.
|
56
|
+
abstract_store.data_store["mu"].should be_nil
|
57
57
|
abstract_store.get("mu", :raw => true).should be_nil
|
58
58
|
end
|
59
59
|
end
|
@@ -68,7 +68,7 @@ describe "Lawnchair::StorageEngine::Abstract" do
|
|
68
68
|
expected_value = "fasa"
|
69
69
|
value = Marshal.dump(expected_value)
|
70
70
|
|
71
|
-
abstract_store.
|
71
|
+
abstract_store.data_store["Lawnchair:mu"] = value
|
72
72
|
abstract_store.get("mu", :raw => false).should == expected_value
|
73
73
|
end
|
74
74
|
end
|
@@ -79,7 +79,7 @@ describe "Lawnchair::StorageEngine::Abstract" do
|
|
79
79
|
end
|
80
80
|
|
81
81
|
it "returns nil if the key does not exist" do
|
82
|
-
abstract_store.
|
82
|
+
abstract_store.data_store["Lawnchair:mu"].should be_nil
|
83
83
|
abstract_store.get("mu", :raw => false).should be_nil
|
84
84
|
end
|
85
85
|
end
|
@@ -11,6 +11,11 @@ describe "Lawnchair::StorageEngine::Composite" do
|
|
11
11
|
it "has a collection of storage_engines" do
|
12
12
|
composite_store.storage_engines == []
|
13
13
|
end
|
14
|
+
|
15
|
+
it "allows you to specify storage engines" do
|
16
|
+
composite_store = Lawnchair::StorageEngine::Composite.new(:in_process, :redis)
|
17
|
+
composite_store.storage_engines.should == [Lawnchair::StorageEngine::InProcess, Lawnchair::StorageEngine::Redis]
|
18
|
+
end
|
14
19
|
end
|
15
20
|
|
16
21
|
describe "#register_storage_engine" do
|
@@ -19,7 +24,7 @@ describe "Lawnchair::StorageEngine::Composite" do
|
|
19
24
|
end
|
20
25
|
|
21
26
|
it "adds a storage engine to the collection" do
|
22
|
-
composite_store.register_storage_engine
|
27
|
+
composite_store.register_storage_engine :redis
|
23
28
|
composite_store.storage_engines.should == [Lawnchair::StorageEngine::Redis]
|
24
29
|
end
|
25
30
|
end
|
@@ -35,7 +40,7 @@ describe "Lawnchair::StorageEngine::Composite" do
|
|
35
40
|
|
36
41
|
context "when there is only 1 storage engine" do
|
37
42
|
before do
|
38
|
-
composite_store.register_storage_engine
|
43
|
+
composite_store.register_storage_engine :redis
|
39
44
|
end
|
40
45
|
|
41
46
|
context "when the key does not exist" do
|
@@ -60,8 +65,7 @@ describe "Lawnchair::StorageEngine::Composite" do
|
|
60
65
|
|
61
66
|
context "when there are two storage engines" do
|
62
67
|
before do
|
63
|
-
composite_store
|
64
|
-
composite_store.register_storage_engine Lawnchair::StorageEngine::Redis
|
68
|
+
@composite_store = Lawnchair::StorageEngine::Composite.new(:in_process, :redis)
|
65
69
|
end
|
66
70
|
|
67
71
|
context "when the key exists in the first storage engine" do
|
@@ -7,19 +7,19 @@ describe "Lawnchair::StorageEngine::InProcessStore" do
|
|
7
7
|
@in_process_store = Lawnchair::StorageEngine::InProcess
|
8
8
|
end
|
9
9
|
|
10
|
-
describe "#
|
10
|
+
describe "#data_store" do
|
11
11
|
it "returns the redis cache object" do
|
12
|
-
Lawnchair::StorageEngine::InProcess.send(:class_variable_set, "@@
|
13
|
-
in_process_store.
|
12
|
+
Lawnchair::StorageEngine::InProcess.send(:class_variable_set, "@@data_store", {"Lawnchair:mu" => "fasa"})
|
13
|
+
in_process_store.data_store["Lawnchair:mu"].should == "fasa"
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
17
|
describe "#set" do
|
18
18
|
context "when raw is true" do
|
19
19
|
it "sets the value" do
|
20
|
-
in_process_store.
|
20
|
+
in_process_store.data_store["Lawnchair:mu"].should be_nil
|
21
21
|
in_process_store.set("mu", "fasa", :raw => true)
|
22
|
-
in_process_store.
|
22
|
+
in_process_store.data_store["Lawnchair:mu"].should == "fasa"
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
@@ -28,34 +28,34 @@ describe "Lawnchair::StorageEngine::InProcessStore" do
|
|
28
28
|
value = "fasa"
|
29
29
|
expected_value = Marshal.dump(value)
|
30
30
|
|
31
|
-
in_process_store.
|
31
|
+
in_process_store.data_store["Lawnchair:mu"].should be_nil
|
32
32
|
in_process_store.set("mu", value, :raw => false)
|
33
|
-
in_process_store.
|
33
|
+
in_process_store.data_store["Lawnchair:mu"].should == expected_value
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
38
|
describe "exists?" do
|
39
39
|
it "returns false when the key does not exist" do
|
40
|
-
in_process_store.
|
40
|
+
in_process_store.data_store.keys.should_not include("Lawnchair:mu")
|
41
41
|
in_process_store.exists?("mu").should be_false
|
42
42
|
end
|
43
43
|
|
44
44
|
it "returns true when the key exists" do
|
45
|
-
in_process_store.
|
46
|
-
in_process_store.
|
45
|
+
in_process_store.data_store["Lawnchair:mu"] = "fasa"
|
46
|
+
in_process_store.data_store.keys.should include("Lawnchair:mu")
|
47
47
|
in_process_store.exists?("mu").should be_true
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
51
|
describe "#expire!" do
|
52
52
|
it "should only expire the key specified" do
|
53
|
-
in_process_store.
|
54
|
-
in_process_store.
|
53
|
+
in_process_store.data_store["Lawnchair:mu"] = "fasa"
|
54
|
+
in_process_store.data_store["Lawnchair:sim"] = "ba"
|
55
55
|
|
56
56
|
in_process_store.expire!("mu")
|
57
|
-
in_process_store.
|
58
|
-
in_process_store.
|
57
|
+
in_process_store.data_store["Lawnchair:mu"].should be_nil
|
58
|
+
in_process_store.data_store["Lawnchair:sim"].should == "ba"
|
59
59
|
end
|
60
60
|
end
|
61
61
|
end
|
@@ -7,10 +7,10 @@ describe "Lawnchair::StorageEngine::RedisStore" do
|
|
7
7
|
@redis_store = Lawnchair::StorageEngine::Redis
|
8
8
|
end
|
9
9
|
|
10
|
-
describe "#
|
10
|
+
describe "#data_store" do
|
11
11
|
it "returns the redis cache object" do
|
12
12
|
Lawnchair.redis["Lawnchair:mu"] = "fasa"
|
13
|
-
redis_store.
|
13
|
+
redis_store.data_store["Lawnchair:mu"].should == "fasa"
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
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.5.
|
4
|
+
version: 0.5.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shane Wolf
|
@@ -9,11 +9,20 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-02-
|
12
|
+
date: 2010-02-14 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
|
-
dependencies:
|
15
|
-
|
16
|
-
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: redis
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
description: Fully featured caching mechanism for arbitrary pieces of resource expensive ruby code using Redis while being able to optionally store data in the Ruby process itself for maximum efficiency.
|
17
26
|
email: shanewolf@gmail.com
|
18
27
|
executables: []
|
19
28
|
|
@@ -30,6 +39,7 @@ files:
|
|
30
39
|
- VERSION
|
31
40
|
- lawnchair.gemspec
|
32
41
|
- lib/lawnchair.rb
|
42
|
+
- lib/marshal_extension.rb
|
33
43
|
- lib/storage_engine/abstract.rb
|
34
44
|
- lib/storage_engine/composite.rb
|
35
45
|
- lib/storage_engine/in_process.rb
|
@@ -71,7 +81,7 @@ rubyforge_project:
|
|
71
81
|
rubygems_version: 1.3.5
|
72
82
|
signing_key:
|
73
83
|
specification_version: 3
|
74
|
-
summary:
|
84
|
+
summary: Speed up your app by caching expensive code in Redis or in the ruby process itself
|
75
85
|
test_files:
|
76
86
|
- spec/lawnchair_spec.rb
|
77
87
|
- spec/spec_helper.rb
|