kvom 6.8.0.beta.200.681.7c84f4a → 6.8.0.beta.200.713.e5c3150
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/.gitignore +3 -2
- data/kvom.gemspec +2 -0
- data/lib/kvom/storage.rb +5 -0
- data/lib/kvom/storage/base.rb +88 -0
- data/lib/kvom/storage/cache_with_prefix.rb +24 -0
- data/lib/kvom/storage/file_system_storage.rb +27 -0
- data/lib/kvom/storage/not_found.rb +6 -0
- data/lib/kvom/storage/s3_storage.rb +73 -0
- data/spec/{base_spec.rb → adaptor/base_spec.rb} +0 -0
- data/spec/{counter_spec.rb → adaptor/counter_spec.rb} +0 -0
- data/spec/{model_identity_spec.rb → adaptor/model_identity_spec.rb} +0 -0
- data/spec/cache_with_prefix_spec.rb +20 -0
- data/spec/storage/file_system_spec.rb +37 -0
- data/spec/storage/s3_spec.rb +178 -0
- metadata +53 -15
data/.gitignore
CHANGED
data/kvom.gemspec
CHANGED
@@ -23,4 +23,6 @@ Gem::Specification.new do |s|
|
|
23
23
|
s.add_runtime_dependency "couchrest"
|
24
24
|
s.add_runtime_dependency "activemodel"
|
25
25
|
s.add_runtime_dependency "aws-sdk"
|
26
|
+
s.add_runtime_dependency "multi_json"
|
27
|
+
s.add_runtime_dependency "rack" # rack/utils by active_support/cache/file_store
|
26
28
|
end
|
data/lib/kvom/storage.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
require 'multi_json'
|
3
|
+
require 'active_support/core_ext/hash/keys'
|
4
|
+
|
5
|
+
module Kvom
|
6
|
+
module Storage
|
7
|
+
if MultiJson.respond_to?(:dump)
|
8
|
+
module MultiJsonCoder
|
9
|
+
def encode(value)
|
10
|
+
MultiJson.dump(value)
|
11
|
+
end
|
12
|
+
|
13
|
+
def decode(value)
|
14
|
+
MultiJson.load(value)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
else
|
18
|
+
module MultiJsonCoder
|
19
|
+
def encode(value)
|
20
|
+
MultiJson.encode(value)
|
21
|
+
end
|
22
|
+
|
23
|
+
def decode(value)
|
24
|
+
MultiJson.decode(value)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class Base
|
30
|
+
|
31
|
+
include MultiJsonCoder
|
32
|
+
|
33
|
+
attr_reader :config
|
34
|
+
|
35
|
+
def initialize(config = nil)
|
36
|
+
@config =
|
37
|
+
if config
|
38
|
+
config.symbolize_keys
|
39
|
+
else
|
40
|
+
{}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def put(data)
|
45
|
+
id = generate_id
|
46
|
+
json_string = encode(data)
|
47
|
+
normalized = decode(json_string)
|
48
|
+
write(id, normalized, json_string)
|
49
|
+
{"id" => id}
|
50
|
+
end
|
51
|
+
|
52
|
+
def get(spec)
|
53
|
+
raise "Invalid key spec (not a hash): #{spec.inspect}" unless Hash === spec
|
54
|
+
id =
|
55
|
+
case
|
56
|
+
when spec.key?("id")
|
57
|
+
spec["id"]
|
58
|
+
when spec.key?(:id)
|
59
|
+
spec[:id]
|
60
|
+
else
|
61
|
+
raise "Invalid key spec (no id): #{spec.inspect}"
|
62
|
+
end
|
63
|
+
read(id)
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def write(id, data, json_data)
|
69
|
+
raise "implement me in subclass!"
|
70
|
+
end
|
71
|
+
|
72
|
+
def read(id)
|
73
|
+
raise "implement me in subclass!"
|
74
|
+
end
|
75
|
+
|
76
|
+
if RUBY_VERSION < "1.9.2"
|
77
|
+
def generate_id
|
78
|
+
SecureRandom.base64(15).tr("+/", "-_")
|
79
|
+
end
|
80
|
+
else
|
81
|
+
def generate_id
|
82
|
+
SecureRandom.urlsafe_base64(15)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class Kvom::Storage::CacheWithPrefix
|
2
|
+
|
3
|
+
def initialize(cache, prefix)
|
4
|
+
@prefix = prefix
|
5
|
+
@cache = cache
|
6
|
+
end
|
7
|
+
|
8
|
+
def read(id)
|
9
|
+
cache.read(cache_id(id))
|
10
|
+
end
|
11
|
+
|
12
|
+
def write(id, value)
|
13
|
+
cache.write(cache_id(id), value)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
attr_reader :cache, :prefix
|
19
|
+
|
20
|
+
def cache_id(id)
|
21
|
+
"#{prefix}#{id}"
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# require 'active_support/cache/file_store' # fails to autoload Cache::Store (no separate file)
|
2
|
+
require 'active_support/cache'
|
3
|
+
|
4
|
+
module Kvom
|
5
|
+
module Storage
|
6
|
+
class FileSystemStorage < Base
|
7
|
+
def initialize(options)
|
8
|
+
super
|
9
|
+
path = config[:path] or raise "No path specified"
|
10
|
+
@storage = ActiveSupport::Cache::FileStore.new(path, options)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
attr_reader :storage
|
16
|
+
|
17
|
+
def read(id)
|
18
|
+
storage.read(id)
|
19
|
+
end
|
20
|
+
|
21
|
+
def write(id, value, ignored_json_string)
|
22
|
+
storage.write(id, value)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'multi_json'
|
2
|
+
require 'aws-sdk'
|
3
|
+
|
4
|
+
module ::Kvom::Storage
|
5
|
+
class S3Storage < Base
|
6
|
+
|
7
|
+
def initialize(options)
|
8
|
+
super
|
9
|
+
@bucket = config[:bucket] or raise "No bucket specified"
|
10
|
+
if "" != (bucket_prefix = config[:bucket_prefix].to_s)
|
11
|
+
@bucket_prefix = bucket_prefix
|
12
|
+
end
|
13
|
+
|
14
|
+
if (cache = config[:cache])
|
15
|
+
cache_prefix = config[:cache_prefix].to_s
|
16
|
+
@cache =
|
17
|
+
if "" != cache_prefix
|
18
|
+
CacheWithPrefix.new(cache, cache_prefix)
|
19
|
+
else
|
20
|
+
cache
|
21
|
+
end
|
22
|
+
extend CacheAware
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
attr_reader :bucket, :bucket_prefix, :cache
|
29
|
+
|
30
|
+
def read(id)
|
31
|
+
decode(s3_read(id))
|
32
|
+
end
|
33
|
+
|
34
|
+
def write(id, object, json_string)
|
35
|
+
s3_object(id).write(json_string)
|
36
|
+
end
|
37
|
+
|
38
|
+
def s3_read(id)
|
39
|
+
s3_object(id).read
|
40
|
+
rescue AWS::S3::Errors::NoSuchKey => e
|
41
|
+
e.extend NotFound
|
42
|
+
raise e
|
43
|
+
end
|
44
|
+
|
45
|
+
def s3_object(id)
|
46
|
+
@s3_objects ||= bucket.objects
|
47
|
+
s3_id = bucket_prefix ? "#{bucket_prefix}/#{id}" : id
|
48
|
+
@s3_objects[s3_id]
|
49
|
+
end
|
50
|
+
|
51
|
+
module CacheAware
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def read(id)
|
56
|
+
object = cache.read(id)
|
57
|
+
if nil == object
|
58
|
+
object = super
|
59
|
+
cache.write(id, object)
|
60
|
+
end
|
61
|
+
object
|
62
|
+
end
|
63
|
+
|
64
|
+
def write(id, object, json_string)
|
65
|
+
super
|
66
|
+
cache.write(id, object)
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Kvom::Storage::CacheWithPrefix do
|
4
|
+
let(:wrapped_cache) {mock("cache", :read => nil, :write => nil)}
|
5
|
+
let(:cache_with_prefix) {Kvom::Storage::CacheWithPrefix.new(wrapped_cache, "some_prefix&")}
|
6
|
+
|
7
|
+
describe "#read" do
|
8
|
+
it "delegates to the wrapped cache with a prefixed cache id" do
|
9
|
+
wrapped_cache.should_receive(:read).with("some_prefix&x_id").and_return("cached_value")
|
10
|
+
cache_with_prefix.read("x_id").should == "cached_value"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#write" do
|
15
|
+
it "delegates to the wrapped cache with a prefixed cache id" do
|
16
|
+
wrapped_cache.should_receive(:write).with("some_prefix&x_id", "the value")
|
17
|
+
cache_with_prefix.write("x_id", "the value")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
describe Kvom::Storage::FileSystemStorage do
|
5
|
+
STORAGE_TEST_DIR = "/tmp/kvom_fs_storage"
|
6
|
+
|
7
|
+
before(:all) do
|
8
|
+
FileUtils.rm_rf(STORAGE_TEST_DIR)
|
9
|
+
end
|
10
|
+
|
11
|
+
after(:all) do
|
12
|
+
FileUtils.rm_rf(STORAGE_TEST_DIR)
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:storage) {Kvom::Storage::FileSystemStorage.new(:path => "/tmp/kvom_fs_storage")}
|
16
|
+
|
17
|
+
it "persists data at the given file system path" do
|
18
|
+
expect {
|
19
|
+
storage.put({"some" => "data"})
|
20
|
+
}.to change {
|
21
|
+
Dir.glob("#{STORAGE_TEST_DIR}/**").count
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
it "returns persisted data" do
|
26
|
+
(reference = storage.put({"more" => "data"})).should have_key("id")
|
27
|
+
storage.get(reference).should == {"more" => "data"}
|
28
|
+
end
|
29
|
+
|
30
|
+
context "when instantiated without a path" do
|
31
|
+
it "raises an error" do
|
32
|
+
expect {
|
33
|
+
Kvom::Storage::FileSystemStorage.new(nil)
|
34
|
+
}.to raise_error(/\bpath\b/)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Kvom::Storage::S3Storage do
|
4
|
+
|
5
|
+
let(:bucket) { mock(:objects => s3_objects) }
|
6
|
+
let(:s3_objects) { mock("s3_objects", :[] => s3_object) }
|
7
|
+
let(:s3_object) { mock("s3_object", :read => "{}", :write => nil) }
|
8
|
+
let(:different_s3_object) { mock("another_s3_object", :read => "{}", :write => nil) }
|
9
|
+
|
10
|
+
let(:storage) { Kvom::Storage::S3Storage.new(:bucket => bucket) }
|
11
|
+
let(:value) {[{:foo => :bar}, {'baz' => 123}]}
|
12
|
+
let(:desymbolized_value) {[{"foo" => "bar"}, {'baz' => 123}]}
|
13
|
+
let(:json_value) {'[{"foo":"bar"},{"baz":123}]'}
|
14
|
+
let(:secure_random_method) {RUBY_VERSION < "1.9.2" ? :base64 : :urlsafe_base64}
|
15
|
+
|
16
|
+
|
17
|
+
before do
|
18
|
+
SecureRandom.stub(secure_random_method).and_return('random_id')
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
describe '#put' do
|
23
|
+
it 'stores the value as JSON to S3 with a new random id and returns the id' do
|
24
|
+
SecureRandom.should_receive(secure_random_method).and_return('random_id')
|
25
|
+
bucket.objects.should_receive(:[]).with('random_id').and_return(s3_object)
|
26
|
+
s3_object.should_receive(:write).with(json_value)
|
27
|
+
storage.put(value)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'returns the random id' do
|
31
|
+
SecureRandom.should_receive(secure_random_method).and_return('unique_id')
|
32
|
+
storage.put([{:foo => :bar}, {'baz' => 123}]).should == {"id" => 'unique_id'}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#get' do
|
37
|
+
context "when the lookup with the id in the bucket is successful" do
|
38
|
+
before do
|
39
|
+
bucket.objects.should_receive(:[]).with('the_id').and_return(s3_object)
|
40
|
+
s3_object.should_receive(:read).and_return(json_value)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "returns the value" do
|
44
|
+
storage.get({"id" => "the_id"}).should == desymbolized_value
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "when the id does not exist in the bucket" do
|
49
|
+
before do
|
50
|
+
bucket.objects.should_receive(:[]).with('the_id').and_return(different_s3_object)
|
51
|
+
different_s3_object.should_receive(:read).and_raise(AWS::S3::Errors::NoSuchKey.new(nil, nil))
|
52
|
+
end
|
53
|
+
|
54
|
+
it "raise a Kvom::Storage::NotFound" do
|
55
|
+
expect {
|
56
|
+
storage.get({"id" => "the_id"})
|
57
|
+
}.to raise_error(Kvom::Storage::NotFound)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context "when the storage has been configured with a bucket prefix" do
|
63
|
+
let(:storage) { Kvom::Storage::S3Storage.new(:bucket => bucket, :bucket_prefix => "bp") }
|
64
|
+
|
65
|
+
describe '#put' do
|
66
|
+
it "stores with a random id within the s3 folder with the given prefix" do
|
67
|
+
bucket.objects.should_receive(:[]).with('bp/random_id').and_return(different_s3_object)
|
68
|
+
different_s3_object.should_receive(:write)
|
69
|
+
storage.put(value)
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'returns the random id without a prefix' do
|
73
|
+
SecureRandom.should_receive(secure_random_method).and_return('unique_id')
|
74
|
+
storage.put(value).should == {"id" => "unique_id"}
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe '#get' do
|
79
|
+
it "does the s3 lookup with the bucket prefix" do
|
80
|
+
bucket.objects.should_receive(:[]).with('bp/the_id').and_return(different_s3_object)
|
81
|
+
different_s3_object.should_receive(:read).and_return('{"some":"data"}')
|
82
|
+
storage.get({"id" => "the_id"}).should == {"some" => "data"}
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context "with an additional cache" do
|
88
|
+
let(:cache) { mock("cache", :read => {}, :write => nil) }
|
89
|
+
let(:storage) { Kvom::Storage::S3Storage.new(:bucket => bucket, :cache => cache) }
|
90
|
+
|
91
|
+
describe "#put" do
|
92
|
+
|
93
|
+
it 'writes the stored value to the cache with the same random id' do
|
94
|
+
cache.should_receive(:write).with('random_id', anything).ordered
|
95
|
+
storage.put(value)
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'writes the value desymbolized to the cache in order to have'\
|
99
|
+
' a cache hit return the value identical the one returned by S3 in case of a cache miss' do
|
100
|
+
value.first.should have_key(:foo)
|
101
|
+
value.first.should_not have_key("foo")
|
102
|
+
desymbolized_value.first.should_not have_key(:foo)
|
103
|
+
desymbolized_value.first.should have_key("foo")
|
104
|
+
|
105
|
+
cache.should_receive(:write).with('random_id', desymbolized_value)
|
106
|
+
storage.put(value)
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'writes the stored value to the cache after it has been stored to S3' do
|
110
|
+
s3_object.should_receive(:write).ordered
|
111
|
+
cache.should_receive(:write).with('random_id', anything).ordered
|
112
|
+
|
113
|
+
storage.put(value)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
describe "#get" do
|
118
|
+
context "on cache hit" do
|
119
|
+
before do
|
120
|
+
cache.should_receive(:read).with('the_id').and_return("the cached value")
|
121
|
+
end
|
122
|
+
|
123
|
+
it "returns the cached value without ever accessing s3" do
|
124
|
+
s3_object.should_not_receive(:read)
|
125
|
+
storage.get({"id" => 'the_id'}).should == "the cached value"
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
context "on cache miss" do
|
130
|
+
before do
|
131
|
+
cache.should_receive(:read).and_return(nil)
|
132
|
+
end
|
133
|
+
|
134
|
+
it "returns the S3 value" do
|
135
|
+
s3_object.should_receive(:read).and_return('{"s3":"value"}')
|
136
|
+
storage.get({"id" => 'the_id'}).should == {"s3" => "value"}
|
137
|
+
end
|
138
|
+
|
139
|
+
it "remembers the returned value in the cache" do
|
140
|
+
s3_object.should_receive(:read).and_return('{"s3":"value"}')
|
141
|
+
cache.should_receive(:write).with("the_id", {"s3" => "value"})
|
142
|
+
|
143
|
+
storage.get({"id" => 'the_id'})
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
context "with an additional cache with a cache prefix" do
|
150
|
+
|
151
|
+
let(:cache) { mock("cache", :read => nil, :write => nil) }
|
152
|
+
let(:storage) { Kvom::Storage::S3Storage.new(:bucket => bucket, :cache => cache, :cache_prefix => "cp-") }
|
153
|
+
|
154
|
+
it "reads from cache with the given prefix" do
|
155
|
+
cache.should_receive(:read).with("cp-an id")
|
156
|
+
storage.get({"id" => "an id"})
|
157
|
+
end
|
158
|
+
|
159
|
+
it "copies to cache with the given prefix" do
|
160
|
+
cache.should_receive(:write).with("cp-an id", anything)
|
161
|
+
|
162
|
+
storage.get({"id" => "an id"})
|
163
|
+
end
|
164
|
+
|
165
|
+
it "writes to cache with the given prefix" do
|
166
|
+
cache.should_receive(:write).with("cp-random_id", ["the value"])
|
167
|
+
storage.put(["the value"])
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
context "when instantiated without a bucket" do
|
172
|
+
it "raises an error" do
|
173
|
+
expect {
|
174
|
+
Kvom::Storage::S3Storage.new(nil)
|
175
|
+
}.to raise_error(/\bbucket\b/)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kvom
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 27133439521
|
5
5
|
prerelease: 6
|
6
6
|
segments:
|
7
7
|
- 6
|
@@ -9,14 +9,12 @@ version: !ruby/object:Gem::Version
|
|
9
9
|
- 0
|
10
10
|
- beta
|
11
11
|
- 200
|
12
|
-
-
|
13
|
-
-
|
12
|
+
- 713
|
13
|
+
- e
|
14
|
+
- 5
|
14
15
|
- c
|
15
|
-
-
|
16
|
-
|
17
|
-
- 4
|
18
|
-
- a
|
19
|
-
version: 6.8.0.beta.200.681.7c84f4a
|
16
|
+
- 3150
|
17
|
+
version: 6.8.0.beta.200.713.e5c3150
|
20
18
|
platform: ruby
|
21
19
|
authors:
|
22
20
|
- Kristian Hanekamp, Infopark AG
|
@@ -24,7 +22,7 @@ autorequire:
|
|
24
22
|
bindir: bin
|
25
23
|
cert_chain: []
|
26
24
|
|
27
|
-
date: 2012-06-
|
25
|
+
date: 2012-06-29 00:00:00 +02:00
|
28
26
|
default_executable:
|
29
27
|
dependencies:
|
30
28
|
- !ruby/object:Gem::Dependency
|
@@ -97,6 +95,34 @@ dependencies:
|
|
97
95
|
name: aws-sdk
|
98
96
|
prerelease: false
|
99
97
|
type: :runtime
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
100
|
+
none: false
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
hash: 3
|
105
|
+
segments:
|
106
|
+
- 0
|
107
|
+
version: "0"
|
108
|
+
version_requirements: *id006
|
109
|
+
name: multi_json
|
110
|
+
prerelease: false
|
111
|
+
type: :runtime
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
114
|
+
none: false
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
hash: 3
|
119
|
+
segments:
|
120
|
+
- 0
|
121
|
+
version: "0"
|
122
|
+
version_requirements: *id007
|
123
|
+
name: rack
|
124
|
+
prerelease: false
|
125
|
+
type: :runtime
|
100
126
|
description: Use it to build object models in ruby on top of a key value store.
|
101
127
|
email:
|
102
128
|
- kristian.hanekamp@infopark.de
|
@@ -122,10 +148,19 @@ files:
|
|
122
148
|
- lib/kvom/document.rb
|
123
149
|
- lib/kvom/model_identity.rb
|
124
150
|
- lib/kvom/not_found.rb
|
125
|
-
-
|
126
|
-
-
|
127
|
-
-
|
151
|
+
- lib/kvom/storage.rb
|
152
|
+
- lib/kvom/storage/base.rb
|
153
|
+
- lib/kvom/storage/cache_with_prefix.rb
|
154
|
+
- lib/kvom/storage/file_system_storage.rb
|
155
|
+
- lib/kvom/storage/not_found.rb
|
156
|
+
- lib/kvom/storage/s3_storage.rb
|
157
|
+
- spec/adaptor/base_spec.rb
|
158
|
+
- spec/adaptor/counter_spec.rb
|
159
|
+
- spec/adaptor/model_identity_spec.rb
|
160
|
+
- spec/cache_with_prefix_spec.rb
|
128
161
|
- spec/spec_helper.rb
|
162
|
+
- spec/storage/file_system_spec.rb
|
163
|
+
- spec/storage/s3_spec.rb
|
129
164
|
has_rdoc: true
|
130
165
|
homepage: ""
|
131
166
|
licenses: []
|
@@ -163,7 +198,10 @@ signing_key:
|
|
163
198
|
specification_version: 3
|
164
199
|
summary: Key Value Object Mapper
|
165
200
|
test_files:
|
166
|
-
- spec/base_spec.rb
|
167
|
-
- spec/counter_spec.rb
|
168
|
-
- spec/model_identity_spec.rb
|
201
|
+
- spec/adaptor/base_spec.rb
|
202
|
+
- spec/adaptor/counter_spec.rb
|
203
|
+
- spec/adaptor/model_identity_spec.rb
|
204
|
+
- spec/cache_with_prefix_spec.rb
|
169
205
|
- spec/spec_helper.rb
|
206
|
+
- spec/storage/file_system_spec.rb
|
207
|
+
- spec/storage/s3_spec.rb
|