modis 1.4.1-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.rubocop.yml +31 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +13 -0
- data/Gemfile +17 -0
- data/Gemfile.lock +89 -0
- data/LICENSE.txt +22 -0
- data/README.md +45 -0
- data/Rakefile +17 -0
- data/benchmark/bench.rb +65 -0
- data/benchmark/find.rb +62 -0
- data/benchmark/persistence.rb +82 -0
- data/benchmark/redis/connection/fakedis.rb +90 -0
- data/lib/modis.rb +41 -0
- data/lib/modis/attribute.rb +103 -0
- data/lib/modis/configuration.rb +14 -0
- data/lib/modis/errors.rb +16 -0
- data/lib/modis/finder.rb +76 -0
- data/lib/modis/index.rb +84 -0
- data/lib/modis/model.rb +47 -0
- data/lib/modis/persistence.rb +233 -0
- data/lib/modis/transaction.rb +13 -0
- data/lib/modis/version.rb +3 -0
- data/lib/tasks/quality.rake +41 -0
- data/modis.gemspec +32 -0
- data/spec/attribute_spec.rb +172 -0
- data/spec/errors_spec.rb +18 -0
- data/spec/finder_spec.rb +109 -0
- data/spec/index_spec.rb +84 -0
- data/spec/persistence_spec.rb +319 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/support/simplecov_helper.rb +23 -0
- data/spec/support/simplecov_quality_formatter.rb +12 -0
- data/spec/transaction_spec.rb +16 -0
- data/spec/validations_spec.rb +49 -0
- metadata +173 -0
data/spec/errors_spec.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module ErrorsSpec
|
4
|
+
class MockModel
|
5
|
+
include Modis::Model
|
6
|
+
|
7
|
+
attribute :name, :string
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe Modis::Errors do
|
12
|
+
let(:model) { ErrorsSpec::MockModel.new }
|
13
|
+
|
14
|
+
it 'adds errors' do
|
15
|
+
model.errors.add(:name, 'is not valid')
|
16
|
+
expect(model.errors[:name]).to eq(['is not valid'])
|
17
|
+
end
|
18
|
+
end
|
data/spec/finder_spec.rb
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module FindersSpec
|
4
|
+
class User
|
5
|
+
include Modis::Model
|
6
|
+
self.namespace = 'users'
|
7
|
+
|
8
|
+
attribute :name, :string
|
9
|
+
attribute :age, :integer
|
10
|
+
attribute :parent_default, :string, default: 'omg'
|
11
|
+
end
|
12
|
+
|
13
|
+
class Consumer < User
|
14
|
+
attribute :consumed, :boolean
|
15
|
+
end
|
16
|
+
|
17
|
+
class Producer < User
|
18
|
+
attribute :child_default, :string, default: 'derp'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe Modis::Finder do
|
23
|
+
let!(:model) { FindersSpec::User.create!(name: 'Ian', age: 28) }
|
24
|
+
let(:found) { FindersSpec::User.find(model.id) }
|
25
|
+
|
26
|
+
it 'finds by ID' do
|
27
|
+
expect(found.id).to eq(model.id)
|
28
|
+
expect(found.name).to eq(model.name)
|
29
|
+
expect(found.age).to eq(model.age)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'finds multiple by ID' do
|
33
|
+
model1 = FindersSpec::User.create!(name: 'Ian', age: 28)
|
34
|
+
model2 = FindersSpec::User.create!(name: 'Tanya', age: 32)
|
35
|
+
model3 = FindersSpec::User.create!(name: 'Kyle', age: 35)
|
36
|
+
models = FindersSpec::User.find(model1.id, model2.id, model3.id)
|
37
|
+
expect(models).to eq([model1, model2, model3])
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'raises an error a record could not be found' do
|
41
|
+
expect do
|
42
|
+
FindersSpec::User.find(model.id + 1)
|
43
|
+
end.to raise_error(Modis::RecordNotFound, "Couldn't find FindersSpec::User with id=#{model.id + 1}")
|
44
|
+
|
45
|
+
expect do
|
46
|
+
FindersSpec::User.find(model.id, model.id + 1)
|
47
|
+
end.to raise_error(Modis::RecordNotFound, "Couldn't find FindersSpec::User with id=#{model.id + 1}")
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'does not flag an attribute as dirty on a found instance' do
|
51
|
+
expect(found.id_changed?).to be false
|
52
|
+
end
|
53
|
+
|
54
|
+
describe 'all' do
|
55
|
+
it 'returns all records' do
|
56
|
+
m2 = FindersSpec::User.create!(name: 'Tanya', age: 30)
|
57
|
+
m3 = FindersSpec::User.create!(name: 'Kyle', age: 32)
|
58
|
+
expect(FindersSpec::User.all).to eq([model, m2, m3])
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'does not return a destroyed record' do
|
62
|
+
model.destroy
|
63
|
+
expect(FindersSpec::User.all).to eq([])
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'identifies a found record as not being new' do
|
68
|
+
expect(found.new_record?).to be false
|
69
|
+
end
|
70
|
+
|
71
|
+
describe 'Single Table Inheritance' do
|
72
|
+
it 'returns the correct namespace' do
|
73
|
+
expect(FindersSpec::Consumer.namespace).to eq('users')
|
74
|
+
expect(FindersSpec::Consumer.absolute_namespace).to eq('modis:users')
|
75
|
+
expect(FindersSpec::Producer.namespace).to eq('users')
|
76
|
+
expect(FindersSpec::Producer.absolute_namespace).to eq('modis:users')
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'returns instances of the correct class' do
|
80
|
+
FindersSpec::Consumer.create!(name: 'Kyle')
|
81
|
+
FindersSpec::Producer.create!(name: 'Tanya')
|
82
|
+
|
83
|
+
models = FindersSpec::User.all
|
84
|
+
|
85
|
+
ian = models.find { |model| model.name == 'Ian' }
|
86
|
+
kyle = models.find { |model| model.name == 'Kyle' }
|
87
|
+
tanya = models.find { |model| model.name == 'Tanya' }
|
88
|
+
|
89
|
+
expect(ian).to be_kind_of(FindersSpec::User)
|
90
|
+
expect(kyle).to be_kind_of(FindersSpec::Consumer)
|
91
|
+
expect(tanya).to be_kind_of(FindersSpec::Producer)
|
92
|
+
|
93
|
+
expect(FindersSpec::User.find(ian.id)).to be_kind_of(FindersSpec::User)
|
94
|
+
expect(FindersSpec::User.find(kyle.id)).to be_kind_of(FindersSpec::Consumer)
|
95
|
+
expect(FindersSpec::User.find(tanya.id)).to be_kind_of(FindersSpec::Producer)
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'inherits attributes from the parent' do
|
99
|
+
consumer = FindersSpec::Consumer.create!(name: 'Kyle', consumed: true)
|
100
|
+
expect(consumer.attributes.keys.sort).to eq(%w(age consumed id name parent_default type))
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'inherits default attribute values from the parent' do
|
104
|
+
producer = FindersSpec::Producer.create!(name: 'Kyle')
|
105
|
+
expect(producer.parent_default).to eq('omg')
|
106
|
+
expect(producer.child_default).to eq('derp')
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
data/spec/index_spec.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module IndexSpec
|
4
|
+
class MockModel
|
5
|
+
include Modis::Model
|
6
|
+
|
7
|
+
attribute :name, :string
|
8
|
+
index :name
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe Modis::Index do
|
13
|
+
let!(:model) { IndexSpec::MockModel.create!(name: 'Ian') }
|
14
|
+
|
15
|
+
describe 'create' do
|
16
|
+
it 'adds a new model to the index' do
|
17
|
+
index = IndexSpec::MockModel.index_for(:name, 'Ian')
|
18
|
+
expect(index).to include(model.id)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe 'update' do
|
23
|
+
before do
|
24
|
+
model.name = 'Kyle'
|
25
|
+
model.save!
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'adds the model to the new index' do
|
29
|
+
index = IndexSpec::MockModel.index_for(:name, 'Kyle')
|
30
|
+
expect(index).to include(model.id)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'removes the model from the old index' do
|
34
|
+
index = IndexSpec::MockModel.index_for(:name, 'Ian')
|
35
|
+
expect(index).to_not include(model.id)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe 'destroy' do
|
40
|
+
it 'removes a destroyed model id from the index' do
|
41
|
+
model.destroy
|
42
|
+
index = IndexSpec::MockModel.index_for(:name, 'Ian')
|
43
|
+
expect(index).to_not include(model.id)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'does not find a destroyed model' do
|
47
|
+
model.destroy
|
48
|
+
models = IndexSpec::MockModel.where(name: 'Ian')
|
49
|
+
expect(models).to be_empty
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'finds by index' do
|
54
|
+
models = IndexSpec::MockModel.where(name: 'Ian')
|
55
|
+
expect(models.first.name).to eq('Ian')
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'finds multiple matches' do
|
59
|
+
IndexSpec::MockModel.create!(name: 'Ian')
|
60
|
+
models = IndexSpec::MockModel.where(name: 'Ian')
|
61
|
+
expect(models.count).to eq(2)
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'returns an empty array if there are no results' do
|
65
|
+
expect(IndexSpec::MockModel.where(name: 'Foo')).to be_empty
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'raises an error when trying to query against multiple indexes' do
|
69
|
+
expect { IndexSpec::MockModel.where(name: 'Ian', age: 29) }.to raise_error(Modis::IndexError, 'Queries using multiple indexes is not currently supported.')
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'indexes a nil value' do
|
73
|
+
model.name = nil
|
74
|
+
model.save!
|
75
|
+
expect(IndexSpec::MockModel.where(name: nil)).to include(model)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'distinguishes between nil and blank string values' do
|
79
|
+
model1 = IndexSpec::MockModel.create!(name: nil)
|
80
|
+
model2 = IndexSpec::MockModel.create!(name: "")
|
81
|
+
expect(IndexSpec::MockModel.where(name: nil)).to eq([model1])
|
82
|
+
expect(IndexSpec::MockModel.where(name: "")).to eq([model2])
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,319 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module PersistenceSpec
|
4
|
+
class MockModel
|
5
|
+
include Modis::Model
|
6
|
+
|
7
|
+
attribute :name, :string, default: 'Ian'
|
8
|
+
attribute :age, :integer
|
9
|
+
validates :name, presence: true
|
10
|
+
|
11
|
+
before_create :test_before_create
|
12
|
+
after_create :test_after_create
|
13
|
+
|
14
|
+
before_update :test_before_update
|
15
|
+
after_update :test_after_update
|
16
|
+
|
17
|
+
before_save :test_before_save
|
18
|
+
after_save :test_after_save
|
19
|
+
|
20
|
+
def called_callbacks
|
21
|
+
@called_callbacks ||= []
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_after_create
|
25
|
+
called_callbacks << :test_after_create
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_before_create
|
29
|
+
called_callbacks << :test_before_create
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_after_update
|
33
|
+
called_callbacks << :test_after_update
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_before_update
|
37
|
+
called_callbacks << :test_before_update
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_after_save
|
41
|
+
called_callbacks << :test_after_save
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_before_save
|
45
|
+
called_callbacks << :test_before_save
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe Modis::Persistence do
|
51
|
+
let(:model) { PersistenceSpec::MockModel.new }
|
52
|
+
|
53
|
+
describe 'namespaces' do
|
54
|
+
it 'returns the namespace' do
|
55
|
+
expect(PersistenceSpec::MockModel.namespace).to eq('persistence_spec:mock_model')
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'returns the absolute namespace' do
|
59
|
+
expect(PersistenceSpec::MockModel.absolute_namespace).to eq('modis:persistence_spec:mock_model')
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'allows the namespace to be set explicitly' do
|
63
|
+
PersistenceSpec::MockModel.namespace = 'other'
|
64
|
+
expect(PersistenceSpec::MockModel.absolute_namespace).to eq('modis:other')
|
65
|
+
end
|
66
|
+
|
67
|
+
after { PersistenceSpec::MockModel.namespace = nil }
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'returns a key' do
|
71
|
+
model.save!
|
72
|
+
expect(model.key).to eq('modis:persistence_spec:mock_model:1')
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'returns a nil key if not saved' do
|
76
|
+
expect(model.key).to be_nil
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'works with ActiveModel dirty tracking' do
|
80
|
+
expect { model.name = 'Kyle' }.to change(model, :changed).to(['name'])
|
81
|
+
expect(model.name_changed?).to be true
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'resets dirty tracking when saved' do
|
85
|
+
model.name = 'Kyle'
|
86
|
+
expect(model.name_changed?).to be true
|
87
|
+
model.save!
|
88
|
+
expect(model.name_changed?).to be false
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'resets dirty tracking when created' do
|
92
|
+
model = PersistenceSpec::MockModel.create!(name: 'Ian')
|
93
|
+
expect(model.name_changed?).to be false
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'does not identify an attribute as changed if the value is the default' do
|
97
|
+
expect(model.class.attributes_with_defaults['name']).to eq('Ian')
|
98
|
+
expect(model.name).to eq('Ian')
|
99
|
+
expect(model.name_changed?).to be false
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'is persisted' do
|
103
|
+
expect(model.persisted?).to be true
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'does not track the ID if the underlying Redis command failed' do
|
107
|
+
redis = double(hmset: double(value: nil), sadd: nil)
|
108
|
+
expect(model.class).to receive(:transaction).and_yield(redis)
|
109
|
+
expect(redis).to receive(:pipelined).and_yield
|
110
|
+
model.save
|
111
|
+
expect { model.class.find(model.id) }.to raise_error(Modis::RecordNotFound)
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'does not perform validation if validate: false' do
|
115
|
+
model.name = nil
|
116
|
+
expect(model.valid?).to be false
|
117
|
+
expect { model.save!(validate: false) }.to_not raise_error
|
118
|
+
model.reload
|
119
|
+
expect(model.name).to be_nil
|
120
|
+
|
121
|
+
expect(model.save(validate: false)).to be true
|
122
|
+
end
|
123
|
+
|
124
|
+
describe 'an existing record' do
|
125
|
+
it 'only updates dirty attributes' do
|
126
|
+
model.name = 'Ian'
|
127
|
+
model.age = 10
|
128
|
+
model.save!
|
129
|
+
model.age = 11
|
130
|
+
redis = double
|
131
|
+
expect(redis).to receive(:hmset).with("modis:persistence_spec:mock_model:1", ["age", "\v"]).and_return(double(value: 'OK'))
|
132
|
+
expect(model.class).to receive(:transaction).and_yield(redis)
|
133
|
+
expect(redis).to receive(:pipelined).and_yield
|
134
|
+
model.save!
|
135
|
+
expect(model.age).to eq(11)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe 'reload' do
|
140
|
+
it 'reloads attributes' do
|
141
|
+
model.save!
|
142
|
+
model2 = model.class.find(model.id)
|
143
|
+
model2.name = 'Changed'
|
144
|
+
model2.save!
|
145
|
+
expect { model.reload }.to change(model, :name).to('Changed')
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'resets dirty tracking' do
|
149
|
+
model.save!
|
150
|
+
model.name = 'Foo'
|
151
|
+
expect(model.name_changed?).to be true
|
152
|
+
model.reload
|
153
|
+
expect(model.name_changed?).to be false
|
154
|
+
end
|
155
|
+
|
156
|
+
it 'raises an error if the record has not been saved' do
|
157
|
+
expect { model.reload }.to raise_error(Modis::RecordNotFound, "Couldn't find PersistenceSpec::MockModel without an ID")
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
describe 'callbacks' do
|
162
|
+
it 'preserves dirty state for the duration of the callback life cycle'
|
163
|
+
it 'halts the chain if a callback returns false'
|
164
|
+
|
165
|
+
describe 'a new record' do
|
166
|
+
it 'calls the before_create callback' do
|
167
|
+
model.save!
|
168
|
+
expect(model.called_callbacks).to include(:test_before_create)
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'calls the after create callback' do
|
172
|
+
model.save!
|
173
|
+
expect(model.called_callbacks).to include(:test_after_create)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
describe 'an existing record' do
|
178
|
+
before { model.save! }
|
179
|
+
|
180
|
+
it 'calls the before_update callback' do
|
181
|
+
model.save!
|
182
|
+
expect(model.called_callbacks).to include(:test_before_update)
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'calls the after update callback' do
|
186
|
+
model.save!
|
187
|
+
expect(model.called_callbacks).to include(:test_after_update)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'calls the before_save callback' do
|
192
|
+
model.save!
|
193
|
+
expect(model.called_callbacks).to include(:test_before_save)
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'calls the after save callback' do
|
197
|
+
model.save!
|
198
|
+
expect(model.called_callbacks).to include(:test_after_save)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
describe 'create' do
|
203
|
+
it 'resets dirty tracking' do
|
204
|
+
model = PersistenceSpec::MockModel.create(name: 'Ian')
|
205
|
+
expect(model.name_changed?).to be false
|
206
|
+
end
|
207
|
+
|
208
|
+
describe 'a valid model' do
|
209
|
+
it 'returns the created model' do
|
210
|
+
model = PersistenceSpec::MockModel.create(name: 'Ian')
|
211
|
+
expect(model.valid?).to be true
|
212
|
+
expect(model.new_record?).to be false
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
describe 'an invalid model' do
|
217
|
+
it 'returns the unsaved model' do
|
218
|
+
model = PersistenceSpec::MockModel.create(name: nil)
|
219
|
+
expect(model.valid?).to be false
|
220
|
+
expect(model.new_record?).to be true
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
describe 'update_attribute' do
|
226
|
+
it 'does not perform validation' do
|
227
|
+
model.name = nil
|
228
|
+
expect(model.valid?).to be false
|
229
|
+
model.name = 'Test'
|
230
|
+
model.update_attribute(:name, nil)
|
231
|
+
end
|
232
|
+
|
233
|
+
it 'invokes callbacks' do
|
234
|
+
model.update_attribute(:name, 'Derp')
|
235
|
+
expect(model.called_callbacks).to_not be_empty
|
236
|
+
end
|
237
|
+
|
238
|
+
it 'updates all dirty attributes' do
|
239
|
+
model.age = 29
|
240
|
+
model.update_attribute(:name, 'Derp')
|
241
|
+
model.reload
|
242
|
+
expect(model.age).to eq 29
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
describe 'update_attributes!' do
|
247
|
+
it 'updates the given attributes' do
|
248
|
+
model.update_attributes!(name: 'Derp', age: 29)
|
249
|
+
model.reload
|
250
|
+
expect(model.name).to eq 'Derp'
|
251
|
+
expect(model.age).to eq 29
|
252
|
+
end
|
253
|
+
|
254
|
+
it 'invokes callbacks' do
|
255
|
+
model.update_attributes!(name: 'Derp')
|
256
|
+
expect(model.called_callbacks).to_not be_empty
|
257
|
+
end
|
258
|
+
|
259
|
+
it 'updates all dirty attributes' do
|
260
|
+
model.age = 29
|
261
|
+
model.update_attributes!(name: 'Derp')
|
262
|
+
model.reload
|
263
|
+
expect(model.age).to eq 29
|
264
|
+
end
|
265
|
+
|
266
|
+
it 'raises an error if the model is invalid' do
|
267
|
+
expect do
|
268
|
+
model.update_attributes!(name: nil).to be false
|
269
|
+
end.to raise_error(Modis::RecordInvalid)
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
describe 'update_attributes' do
|
274
|
+
it 'updates the given attributes' do
|
275
|
+
model.update_attributes(name: 'Derp', age: 29)
|
276
|
+
model.reload
|
277
|
+
expect(model.name).to eq('Derp')
|
278
|
+
expect(model.age).to eq(29)
|
279
|
+
end
|
280
|
+
|
281
|
+
it 'invokes callbacks' do
|
282
|
+
model.update_attributes(name: 'Derp')
|
283
|
+
expect(model.called_callbacks).to_not be_empty
|
284
|
+
end
|
285
|
+
|
286
|
+
it 'updates all dirty attributes' do
|
287
|
+
model.age = 29
|
288
|
+
model.update_attributes(name: 'Derp')
|
289
|
+
model.reload
|
290
|
+
expect(model.age).to eq(29)
|
291
|
+
end
|
292
|
+
|
293
|
+
it 'returns false if the model is invalid' do
|
294
|
+
expect(model.update_attributes(name: nil)).to be false
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
describe 'YAML backward compatability' do
|
299
|
+
it 'loads a YAML serialized value' do
|
300
|
+
Modis.with_connection do |redis|
|
301
|
+
model.save!
|
302
|
+
key = model.class.key_for(model.id)
|
303
|
+
record = redis.hgetall(key)
|
304
|
+
record['age'] = YAML.dump(30)
|
305
|
+
redis.hmset(key, *record.to_a)
|
306
|
+
record = redis.hgetall(key)
|
307
|
+
|
308
|
+
expect(record['age']).to eq("--- 30\n...\n")
|
309
|
+
|
310
|
+
model.reload
|
311
|
+
expect(model.age).to eq(30)
|
312
|
+
|
313
|
+
model.save!(yaml_sucks: true)
|
314
|
+
record = redis.hgetall(key)
|
315
|
+
expect(record['age']).to eq("\x1E")
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|