modis 1.4.1-java
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.
- 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
|