couch_potato-rails2 0.5.6
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 +7 -0
- data/.travis.yml +5 -0
- data/CHANGES.md +148 -0
- data/CREDITS +6 -0
- data/Gemfile +4 -0
- data/MIT-LICENSE.txt +19 -0
- data/README.md +450 -0
- data/Rakefile +82 -0
- data/couch_potato.gemspec +27 -0
- data/init.rb +3 -0
- data/lib/core_ext/date.rb +14 -0
- data/lib/core_ext/object.rb +5 -0
- data/lib/core_ext/string.rb +12 -0
- data/lib/core_ext/symbol.rb +15 -0
- data/lib/core_ext/time.rb +23 -0
- data/lib/couch_potato.rb +48 -0
- data/lib/couch_potato/database.rb +179 -0
- data/lib/couch_potato/persistence.rb +124 -0
- data/lib/couch_potato/persistence/active_model_compliance.rb +44 -0
- data/lib/couch_potato/persistence/attachments.rb +31 -0
- data/lib/couch_potato/persistence/callbacks.rb +29 -0
- data/lib/couch_potato/persistence/dirty_attributes.rb +56 -0
- data/lib/couch_potato/persistence/ghost_attributes.rb +12 -0
- data/lib/couch_potato/persistence/json.rb +47 -0
- data/lib/couch_potato/persistence/magic_timestamps.rb +23 -0
- data/lib/couch_potato/persistence/properties.rb +79 -0
- data/lib/couch_potato/persistence/simple_property.rb +82 -0
- data/lib/couch_potato/persistence/type_caster.rb +40 -0
- data/lib/couch_potato/railtie.rb +25 -0
- data/lib/couch_potato/rspec.rb +2 -0
- data/lib/couch_potato/rspec/matchers.rb +39 -0
- data/lib/couch_potato/rspec/matchers/json2.js +482 -0
- data/lib/couch_potato/rspec/matchers/list_as_matcher.rb +54 -0
- data/lib/couch_potato/rspec/matchers/map_to_matcher.rb +49 -0
- data/lib/couch_potato/rspec/matchers/print_r.js +60 -0
- data/lib/couch_potato/rspec/matchers/reduce_to_matcher.rb +50 -0
- data/lib/couch_potato/rspec/stub_db.rb +46 -0
- data/lib/couch_potato/validation.rb +16 -0
- data/lib/couch_potato/validation/with_active_model.rb +27 -0
- data/lib/couch_potato/validation/with_validatable.rb +41 -0
- data/lib/couch_potato/version.rb +3 -0
- data/lib/couch_potato/view/base_view_spec.rb +84 -0
- data/lib/couch_potato/view/custom_view_spec.rb +42 -0
- data/lib/couch_potato/view/custom_views.rb +52 -0
- data/lib/couch_potato/view/lists.rb +23 -0
- data/lib/couch_potato/view/model_view_spec.rb +75 -0
- data/lib/couch_potato/view/properties_view_spec.rb +47 -0
- data/lib/couch_potato/view/raw_view_spec.rb +25 -0
- data/lib/couch_potato/view/view_query.rb +82 -0
- data/rails/init.rb +4 -0
- data/rails/reload_classes.rb +47 -0
- data/spec/attachments_spec.rb +23 -0
- data/spec/callbacks_spec.rb +297 -0
- data/spec/create_spec.rb +35 -0
- data/spec/custom_view_spec.rb +239 -0
- data/spec/default_property_spec.rb +38 -0
- data/spec/destroy_spec.rb +29 -0
- data/spec/fixtures/address.rb +10 -0
- data/spec/fixtures/person.rb +6 -0
- data/spec/property_spec.rb +323 -0
- data/spec/rails_spec.rb +50 -0
- data/spec/railtie_spec.rb +65 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +44 -0
- data/spec/unit/active_model_compliance_spec.rb +98 -0
- data/spec/unit/attributes_spec.rb +135 -0
- data/spec/unit/base_view_spec_spec.rb +106 -0
- data/spec/unit/callbacks_spec.rb +46 -0
- data/spec/unit/couch_potato_spec.rb +39 -0
- data/spec/unit/create_spec.rb +69 -0
- data/spec/unit/custom_views_spec.rb +15 -0
- data/spec/unit/database_spec.rb +317 -0
- data/spec/unit/date_spec.rb +22 -0
- data/spec/unit/dirty_attributes_spec.rb +136 -0
- data/spec/unit/initialize_spec.rb +38 -0
- data/spec/unit/json_spec.rb +30 -0
- data/spec/unit/lists_spec.rb +20 -0
- data/spec/unit/model_view_spec_spec.rb +13 -0
- data/spec/unit/properties_view_spec_spec.rb +31 -0
- data/spec/unit/rspec_matchers_spec.rb +124 -0
- data/spec/unit/rspec_stub_db_spec.rb +35 -0
- data/spec/unit/string_spec.rb +7 -0
- data/spec/unit/time_spec.rb +15 -0
- data/spec/unit/validation_spec.rb +67 -0
- data/spec/unit/view_query_spec.rb +86 -0
- data/spec/update_spec.rb +40 -0
- data/spec/view_updates_spec.rb +28 -0
- metadata +243 -0
data/spec/create_spec.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "create" do
|
4
|
+
before(:each) do
|
5
|
+
recreate_db
|
6
|
+
end
|
7
|
+
describe "succeeds" do
|
8
|
+
it "should store the class" do
|
9
|
+
@comment = Comment.new :title => 'my_title'
|
10
|
+
CouchPotato.database.save_document! @comment
|
11
|
+
CouchPotato.couchrest_database.get(@comment.id).send(JSON.create_id).should == 'Comment'
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should persist a given created_at" do
|
15
|
+
@comment = Comment.new :created_at => Time.parse('2010-01-02 12:34:48 +0000'), :title => '-'
|
16
|
+
CouchPotato.database.save_document! @comment
|
17
|
+
CouchPotato.couchrest_database.get(@comment.id).created_at.should == Time.parse('2010-01-02 12:34:48 +0000')
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should persist a given updated_at" do
|
21
|
+
@comment = Comment.new :updated_at => Time.parse('2010-01-02 12:34:48 +0000'), :title => '-'
|
22
|
+
CouchPotato.database.save_document! @comment
|
23
|
+
CouchPotato.couchrest_database.get(@comment.id).updated_at.should == Time.parse('2010-01-02 12:34:48 +0000')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "fails" do
|
28
|
+
it "should not store anything" do
|
29
|
+
@comment = Comment.new
|
30
|
+
CouchPotato.database.save_document @comment
|
31
|
+
CouchPotato.couchrest_database.documents['rows'].should be_empty
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
@@ -0,0 +1,239 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class Build
|
4
|
+
include CouchPotato::Persistence
|
5
|
+
|
6
|
+
property :state
|
7
|
+
property :time
|
8
|
+
|
9
|
+
view :timeline, :key => :time
|
10
|
+
view :count, :key => :time, :reduce => true
|
11
|
+
view :minimal_timeline, :key => :time, :properties => [:state], :type => :properties
|
12
|
+
view :key_array_timeline, :key => [:time, :state]
|
13
|
+
view :custom_timeline, :map => "function(doc) { emit(doc._id, {state: 'custom_' + doc.state}); }", :type => :custom
|
14
|
+
view :custom_timeline_returns_docs, :map => "function(doc) { emit(doc._id, null); }", :include_docs => true, :type => :custom
|
15
|
+
view :custom_with_reduce, :map => "function(doc) {if(doc.foreign_key) {emit(doc.foreign_key, 1);} else {emit(doc._id, 1)}}", :reduce => "function(key, values) {return({\"count\": sum(values)});}", :group => true, :type => :custom
|
16
|
+
view :custom_count_with_reduce, :map => "function(doc) {if(doc.foreign_key) {emit(doc.foreign_key, 1);} else {emit(doc._id, 1)}}", :reduce => "function(key, values) {return(sum(values));}", :group => true, :type => :custom
|
17
|
+
view :raw, :type => :raw, :map => "function(doc) {emit(doc._id, doc.state)}"
|
18
|
+
view :filtered_raw, :type => :raw, :map => "function(doc) {emit(doc._id, doc.state)}", :results_filter => lambda{|res| res['rows'].map{|row| row['value']}}
|
19
|
+
view :with_view_options, :group => true, :key => :time
|
20
|
+
end
|
21
|
+
|
22
|
+
class CustomBuild < Build
|
23
|
+
end
|
24
|
+
|
25
|
+
describe 'view' do
|
26
|
+
before(:each) do
|
27
|
+
recreate_db
|
28
|
+
@db = CouchPotato.database
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should return instances of the class" do
|
32
|
+
@db.save_document Build.new(:state => 'success', :time => '2008-01-01')
|
33
|
+
results = @db.view(Build.timeline)
|
34
|
+
results.map(&:class).should == [Build]
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should return the ids if there document was not included" do
|
38
|
+
build = Build.new(:state => 'success', :time => '2008-01-01')
|
39
|
+
@db.save_document build
|
40
|
+
results = @db.view(Build.timeline(:include_docs => false))
|
41
|
+
results.should == [build.id]
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should pass the view options to the view query" do
|
45
|
+
query = mock 'query'
|
46
|
+
CouchPotato::View::ViewQuery.stub!(:new).and_return(query)
|
47
|
+
query.should_receive(:query_view!).with(hash_including(:key => 1)).and_return('rows' => [])
|
48
|
+
@db.view Build.timeline(:key => 1)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should not return documents that don't have a matching JSON.create_id" do
|
52
|
+
CouchPotato.couchrest_database.save_doc({:time => 'x'})
|
53
|
+
@db.view(Build.timeline).should == []
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should count documents" do
|
57
|
+
@db.save_document! Build.new(:state => 'success', :time => '2008-01-01')
|
58
|
+
@db.view(Build.count(:reduce => true)).should == 1
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should count zero documents" do
|
62
|
+
@db.view(Build.count(:reduce => true)).should == 0
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should return the total_rows" do
|
66
|
+
@db.save_document! Build.new(:state => 'success', :time => '2008-01-01')
|
67
|
+
@db.view(Build.count(:reduce => false)).total_rows.should == 1
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "with multiple keys" do
|
71
|
+
it "should return the documents with matching keys" do
|
72
|
+
build = Build.new(:state => 'success', :time => '2008-01-01')
|
73
|
+
@db.save! build
|
74
|
+
@db.view(Build.timeline(:keys => ['2008-01-01'])).should == [build]
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should not return documents with non-matching keys" do
|
78
|
+
build = Build.new(:state => 'success', :time => '2008-01-01')
|
79
|
+
@db.save! build
|
80
|
+
@db.view(Build.timeline(:keys => ['2008-01-02'])).should be_empty
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "properties defined" do
|
85
|
+
it "should assign the configured properties" do
|
86
|
+
CouchPotato.couchrest_database.save_doc(:state => 'success', :time => '2008-01-01', JSON.create_id.to_sym => 'Build')
|
87
|
+
@db.view(Build.minimal_timeline).first.state.should == 'success'
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should not assign the properties not configured" do
|
91
|
+
CouchPotato.couchrest_database.save_doc(:state => 'success', :time => '2008-01-01', JSON.create_id.to_sym => 'Build')
|
92
|
+
@db.view(Build.minimal_timeline).first.time.should be_nil
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should assign the id even if it is not configured" do
|
96
|
+
id = CouchPotato.couchrest_database.save_doc(:state => 'success', :time => '2008-01-01', JSON.create_id.to_sym => 'Build')['id']
|
97
|
+
@db.view(Build.minimal_timeline).first._id.should == id
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe "no properties defined" do
|
102
|
+
it "should assign all properties to the objects by default" do
|
103
|
+
id = CouchPotato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01', JSON.create_id.to_sym => 'Build'})['id']
|
104
|
+
result = @db.view(Build.timeline).first
|
105
|
+
result.state.should == 'success'
|
106
|
+
result.time.should == '2008-01-01'
|
107
|
+
result._id.should == id
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe "map function given" do
|
112
|
+
it "should still return instances of the class" do
|
113
|
+
CouchPotato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01'})
|
114
|
+
@db.view(Build.custom_timeline).map(&:class).should == [Build]
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should assign the properties from the value" do
|
118
|
+
CouchPotato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01'})
|
119
|
+
@db.view(Build.custom_timeline).map(&:state).should == ['custom_success']
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should assign the id" do
|
123
|
+
doc = CouchPotato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01'})
|
124
|
+
@db.view(Build.custom_timeline).map(&:_id).should == [doc['id']]
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should leave the other properties blank" do
|
128
|
+
CouchPotato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01'})
|
129
|
+
@db.view(Build.custom_timeline).map(&:time).should == [nil]
|
130
|
+
end
|
131
|
+
|
132
|
+
describe "that returns null documents" do
|
133
|
+
it "should return instances of the class" do
|
134
|
+
CouchPotato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01'})
|
135
|
+
@db.view(Build.custom_timeline_returns_docs).map(&:class).should == [Build]
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should assign the properties from the value" do
|
139
|
+
CouchPotato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01'})
|
140
|
+
@db.view(Build.custom_timeline_returns_docs).map(&:state).should == ['success']
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should still return instance of class if document included JSON.create_id" do
|
144
|
+
CouchPotato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01', JSON.create_id.to_sym => "Build"})
|
145
|
+
view_data = @db.view(Build.custom_timeline_returns_docs)
|
146
|
+
view_data.map(&:class).should == [Build]
|
147
|
+
view_data.map(&:state).should == ['success']
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
describe "additional reduce function given" do
|
152
|
+
it "should still assign the id" do
|
153
|
+
doc = CouchPotato.couchrest_database.save_doc({})
|
154
|
+
CouchPotato.couchrest_database.save_doc({:foreign_key => doc['id']})
|
155
|
+
@db.view(Build.custom_with_reduce).map(&:_id).should == [doc['id']]
|
156
|
+
end
|
157
|
+
|
158
|
+
describe "when the additional reduce function is a typical count" do
|
159
|
+
it "should parse the reduce count" do
|
160
|
+
doc = CouchPotato.couchrest_database.save_doc({})
|
161
|
+
CouchPotato.couchrest_database.save_doc({:foreign_key => doc['id']})
|
162
|
+
@db.view(Build.custom_count_with_reduce(:reduce => true)).should == 2
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
describe "with array as key" do
|
169
|
+
it "should create a map function with the composite key" do
|
170
|
+
CouchPotato::View::ViewQuery.should_receive(:new) do |db, design_name, view, list|
|
171
|
+
view['key_array_timeline'][:map].should match(/emit\(\[doc\['time'\], doc\['state'\]\]/)
|
172
|
+
|
173
|
+
stub('view query', :query_view! => {'rows' => []})
|
174
|
+
end
|
175
|
+
@db.view Build.key_array_timeline
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
describe "raw view" do
|
180
|
+
it "should return the raw data" do
|
181
|
+
@db.save_document Build.new(:state => 'success', :time => '2008-01-01')
|
182
|
+
@db.view(Build.raw)['rows'][0]['value'].should == 'success'
|
183
|
+
end
|
184
|
+
|
185
|
+
it "should return filtred raw data" do
|
186
|
+
@db.save_document Build.new(:state => 'success', :time => '2008-01-01')
|
187
|
+
@db.view(Build.filtered_raw).should == ['success']
|
188
|
+
end
|
189
|
+
|
190
|
+
it "should pass view options declared in the view declaration to the query" do
|
191
|
+
view_query = mock 'view_query'
|
192
|
+
CouchPotato::View::ViewQuery.stub!(:new).and_return(view_query)
|
193
|
+
view_query.should_receive(:query_view!).with(hash_including(:group => true)).and_return({'rows' => []})
|
194
|
+
@db.view(Build.with_view_options)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
describe "inherited views" do
|
199
|
+
it "should support parent views for objects of the subclass" do
|
200
|
+
@db.save_document CustomBuild.new(:state => 'success', :time => '2008-01-01')
|
201
|
+
@db.view(CustomBuild.timeline).size.should == 1
|
202
|
+
@db.view(CustomBuild.timeline).first.should be_kind_of(CustomBuild)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
describe "list functions" do
|
207
|
+
class Coworker
|
208
|
+
include CouchPotato::Persistence
|
209
|
+
|
210
|
+
property :name
|
211
|
+
|
212
|
+
view :all_with_list, :key => :name, :list => :append_doe
|
213
|
+
view :all, :key => :name
|
214
|
+
|
215
|
+
list :append_doe, <<-JS
|
216
|
+
function(head, req) {
|
217
|
+
var row;
|
218
|
+
send('{"rows": [');
|
219
|
+
while(row = getRow()) {
|
220
|
+
row.doc.name = row.doc.name + ' doe';
|
221
|
+
send(JSON.stringify(row));
|
222
|
+
};
|
223
|
+
send(']}');
|
224
|
+
}
|
225
|
+
JS
|
226
|
+
end
|
227
|
+
|
228
|
+
it "should use the list function declared at class level" do
|
229
|
+
@db.save! Coworker.new(:name => 'joe')
|
230
|
+
@db.view(Coworker.all_with_list).first.name.should == 'joe doe'
|
231
|
+
end
|
232
|
+
|
233
|
+
it "should use the list function passed at runtime" do
|
234
|
+
@db.save! Coworker.new(:name => 'joe')
|
235
|
+
@db.view(Coworker.all(:list => :append_doe)).first.name.should == 'joe doe'
|
236
|
+
end
|
237
|
+
|
238
|
+
end
|
239
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class Test
|
4
|
+
include CouchPotato::Persistence
|
5
|
+
|
6
|
+
property :test, :default => 'Test value'
|
7
|
+
property :complex, :default => [1, 2, 3]
|
8
|
+
end
|
9
|
+
|
10
|
+
describe 'default properties' do
|
11
|
+
before(:all) do
|
12
|
+
recreate_db
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should use the default value if nothing is supplied" do
|
16
|
+
t = Test.new
|
17
|
+
|
18
|
+
t.test.should == 'Test value'
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should persist the default value if nothing is supplied" do
|
22
|
+
t = Test.new
|
23
|
+
CouchPotato.database.save_document! t
|
24
|
+
|
25
|
+
t = CouchPotato.database.load_document t.id
|
26
|
+
t.test.should == 'Test value'
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should not have the same default for two instances of the object" do
|
30
|
+
t = Test.new
|
31
|
+
t2 = Test.new
|
32
|
+
t.complex.object_id.should_not == t2.complex.object_id
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should not return the default value when the actual value is empty" do
|
36
|
+
t = Test.new(:complex => []).complex.should == []
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'destroy' do
|
4
|
+
before(:all) do
|
5
|
+
recreate_db
|
6
|
+
end
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
@comment = Comment.new :title => 'title'
|
10
|
+
CouchPotato.database.save_document! @comment
|
11
|
+
@comment_id = @comment.id
|
12
|
+
CouchPotato.database.destroy_document @comment
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should unset the id" do
|
16
|
+
@comment._id.should be_nil
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should unset the revision" do
|
20
|
+
@comment._rev.should be_nil
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should remove the document from the database" do
|
24
|
+
lambda {
|
25
|
+
CouchPotato.couchrest_database.get(@comment_id).should
|
26
|
+
}.should raise_error(RestClient::ResourceNotFound)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,323 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fixtures/address'
|
3
|
+
require 'fixtures/person'
|
4
|
+
|
5
|
+
class Watch
|
6
|
+
include CouchPotato::Persistence
|
7
|
+
|
8
|
+
property :time, :type => Time
|
9
|
+
property :date, :type => Date
|
10
|
+
property :overwritten_read
|
11
|
+
property :overwritten_write
|
12
|
+
|
13
|
+
def overwritten_read
|
14
|
+
super.to_s
|
15
|
+
end
|
16
|
+
|
17
|
+
def overwritten_write=(value)
|
18
|
+
super value.to_s
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class CuckooClock < Watch
|
23
|
+
property :cuckoo
|
24
|
+
end
|
25
|
+
|
26
|
+
describe 'properties' do
|
27
|
+
before(:all) do
|
28
|
+
recreate_db
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should allow me to overwrite read accessor and call super" do
|
32
|
+
Watch.new(:overwritten_read => 1).overwritten_read.should == '1'
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should allow me to overwrite write accessor and call super" do
|
36
|
+
Watch.new(:overwritten_write => 1).overwritten_write.should == '1'
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should return the property names" do
|
40
|
+
Comment.property_names.should == [:created_at, :updated_at, :title]
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should persist a string" do
|
44
|
+
c = Comment.new :title => 'my title'
|
45
|
+
CouchPotato.database.save_document! c
|
46
|
+
c = CouchPotato.database.load_document c.id
|
47
|
+
c.title.should == 'my title'
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should persist a number" do
|
51
|
+
c = Comment.new :title => 3
|
52
|
+
CouchPotato.database.save_document! c
|
53
|
+
c = CouchPotato.database.load_document c.id
|
54
|
+
c.title.should == 3
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should persist a hash" do
|
58
|
+
c = Comment.new :title => {'key' => 'value'}
|
59
|
+
CouchPotato.database.save_document! c
|
60
|
+
c = CouchPotato.database.load_document c.id
|
61
|
+
c.title.should == {'key' => 'value'}
|
62
|
+
end
|
63
|
+
|
64
|
+
def it_should_persist value
|
65
|
+
c = Comment.new :title => value
|
66
|
+
CouchPotato.database.save_document! c
|
67
|
+
c = CouchPotato.database.load_document c.id
|
68
|
+
c.title.should == value
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should persist a child class" do
|
72
|
+
it_should_persist Child.new('text' => 'some text')
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should persist a hash with a child class" do
|
76
|
+
it_should_persist 'child' => Child.new('text' => 'some text')
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should persist an array with a child class" do
|
80
|
+
it_should_persist [Child.new('text' => 'some text')]
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should persist something very complex" do
|
84
|
+
something_very_complex = [
|
85
|
+
[
|
86
|
+
[
|
87
|
+
{
|
88
|
+
'what' => [
|
89
|
+
{
|
90
|
+
'ever' => Child.new('text' => 'some text')
|
91
|
+
}
|
92
|
+
],
|
93
|
+
'number' => 3
|
94
|
+
},
|
95
|
+
"string"
|
96
|
+
],
|
97
|
+
Child.new('text' => 'nothing')
|
98
|
+
]
|
99
|
+
]
|
100
|
+
it_should_persist something_very_complex
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should persist an object" do
|
104
|
+
p = Person.new
|
105
|
+
a = Address.new :city => 'Denver'
|
106
|
+
p.ship_address = a
|
107
|
+
CouchPotato.database.save_document! p
|
108
|
+
p = CouchPotato.database.load_document p.id
|
109
|
+
p.ship_address.should === a
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should persist null for a null " do
|
113
|
+
p = Person.new
|
114
|
+
p.ship_address = nil
|
115
|
+
CouchPotato.database.save_document! p
|
116
|
+
p = CouchPotato.database.load_document p.id
|
117
|
+
p.ship_address.should be_nil
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should actually pass the null value down in the JSON document " do
|
121
|
+
p = Person.new
|
122
|
+
p.ship_address = nil
|
123
|
+
db = mock(:database)
|
124
|
+
db.should_receive(:save_doc).with do |attributes|
|
125
|
+
attributes.has_key?(:ship_address).should == true
|
126
|
+
end.and_return({})
|
127
|
+
CouchPotato.database.stub(:couchrest_database).and_return(db)
|
128
|
+
CouchPotato.database.save_document! p
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should persist false for a false" do
|
132
|
+
p = Person.new
|
133
|
+
p.ship_address = false
|
134
|
+
CouchPotato.database.save_document! p
|
135
|
+
p = CouchPotato.database.load_document p.id
|
136
|
+
p.ship_address.should be_false
|
137
|
+
end
|
138
|
+
|
139
|
+
describe "time properties" do
|
140
|
+
it "should persist a Time as utc" do
|
141
|
+
time = Time.now
|
142
|
+
w = Watch.new :time => time
|
143
|
+
CouchPotato.database.save_document! w
|
144
|
+
w = CouchPotato.database.load_document w.id
|
145
|
+
w.time.to_s.should == time.utc.to_s
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should parse a string and persist it as utc time" do
|
149
|
+
w = Watch.new :time => '2009-01-01 13:25 +0100'
|
150
|
+
CouchPotato.database.save_document! w
|
151
|
+
w = CouchPotato.database.load_document w.id
|
152
|
+
w.time.should be_a(Time)
|
153
|
+
w.time.should == Time.parse('2009-01-01 12:25 +0000')
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should store nil" do
|
157
|
+
w = Watch.new :time => nil
|
158
|
+
CouchPotato.database.save_document! w
|
159
|
+
w = CouchPotato.database.load_document w.id
|
160
|
+
w.time.should be_nil
|
161
|
+
end
|
162
|
+
|
163
|
+
it "should store an empty string as nil" do
|
164
|
+
w = Watch.new :time => ''
|
165
|
+
CouchPotato.database.save_document! w
|
166
|
+
w = CouchPotato.database.load_document w.id
|
167
|
+
w.time.should be_nil
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
describe "date properties" do
|
172
|
+
it "should persist a date" do
|
173
|
+
date = Date.today
|
174
|
+
w = Watch.new :date => date
|
175
|
+
CouchPotato.database.save_document! w
|
176
|
+
w = CouchPotato.database.load_document w.id
|
177
|
+
w.date.should == date
|
178
|
+
end
|
179
|
+
|
180
|
+
it "should parse a string and persist it as a date" do
|
181
|
+
w = Watch.new :date => '2009-01-10'
|
182
|
+
CouchPotato.database.save_document! w
|
183
|
+
w = CouchPotato.database.load_document w.id
|
184
|
+
w.date.should == Date.parse('2009-01-10')
|
185
|
+
end
|
186
|
+
|
187
|
+
it "should store nil" do
|
188
|
+
w = Watch.new :date => nil
|
189
|
+
CouchPotato.database.save_document! w
|
190
|
+
w = CouchPotato.database.load_document w.id
|
191
|
+
w.date.should be_nil
|
192
|
+
end
|
193
|
+
|
194
|
+
it "should store an empty string as nil" do
|
195
|
+
w = Watch.new :date => ''
|
196
|
+
CouchPotato.database.save_document! w
|
197
|
+
w = CouchPotato.database.load_document w.id
|
198
|
+
w.date.should be_nil
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
describe "boolean properties" do
|
203
|
+
it "should persist '0' as false" do
|
204
|
+
a = Address.new
|
205
|
+
a.verified = '0'
|
206
|
+
CouchPotato.database.save_document! a
|
207
|
+
a = CouchPotato.database.load_document a.id
|
208
|
+
a.verified.should be_false
|
209
|
+
end
|
210
|
+
|
211
|
+
it "should persist 0 as false" do
|
212
|
+
a = Address.new
|
213
|
+
a.verified = 0
|
214
|
+
CouchPotato.database.save_document! a
|
215
|
+
a = CouchPotato.database.load_document a.id
|
216
|
+
a.verified.should be_false
|
217
|
+
end
|
218
|
+
|
219
|
+
it "should persist 'false' as false" do
|
220
|
+
a = Address.new
|
221
|
+
a.verified = 'false'
|
222
|
+
CouchPotato.database.save_document! a
|
223
|
+
a = CouchPotato.database.load_document a.id
|
224
|
+
a.verified.should be_false
|
225
|
+
end
|
226
|
+
|
227
|
+
it "should persist '1' as true" do
|
228
|
+
a = Address.new
|
229
|
+
a.verified = '1'
|
230
|
+
CouchPotato.database.save_document! a
|
231
|
+
a = CouchPotato.database.load_document a.id
|
232
|
+
a.verified.should be_true
|
233
|
+
end
|
234
|
+
|
235
|
+
it "should persist 1 as true" do
|
236
|
+
a = Address.new
|
237
|
+
a.verified = 1
|
238
|
+
CouchPotato.database.save_document! a
|
239
|
+
a = CouchPotato.database.load_document a.id
|
240
|
+
a.verified.should be_true
|
241
|
+
end
|
242
|
+
|
243
|
+
it "should leave nil as nil" do
|
244
|
+
a = Address.new
|
245
|
+
a.verified = nil
|
246
|
+
CouchPotato.database.save_document! a
|
247
|
+
a = CouchPotato.database.load_document a.id
|
248
|
+
a.verified.should be_nil
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
describe "predicate" do
|
253
|
+
it "should return true if property set" do
|
254
|
+
Comment.new(:title => 'title').title?.should be_true
|
255
|
+
end
|
256
|
+
|
257
|
+
it "should return false if property nil" do
|
258
|
+
Comment.new.title?.should be_false
|
259
|
+
end
|
260
|
+
|
261
|
+
it "should return false if property false" do
|
262
|
+
Comment.new(:title => false).title?.should be_false
|
263
|
+
end
|
264
|
+
|
265
|
+
it "should return false if property blank" do
|
266
|
+
Comment.new(:title => '').title?.should be_false
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
describe "with subclasses" do
|
271
|
+
it "should include properties of superclasses" do
|
272
|
+
CuckooClock.properties.map(&:name).should include(:time)
|
273
|
+
CuckooClock.properties.map(&:name).should include(:cuckoo)
|
274
|
+
end
|
275
|
+
|
276
|
+
it "should return attributes of superclasses" do
|
277
|
+
clock = CuckooClock.new(:time => Time.now, :cuckoo => 'bavarian')
|
278
|
+
clock.attributes[:time].should_not == nil
|
279
|
+
clock.attributes[:cuckoo].should == 'bavarian'
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
describe "inspecting an object" do
|
284
|
+
let(:comment) do
|
285
|
+
comment = Comment.new(:title => 'title')
|
286
|
+
comment.instance_eval do
|
287
|
+
@_id = "123456abcdef"
|
288
|
+
@_rev = "1-654321fedcba"
|
289
|
+
end
|
290
|
+
comment
|
291
|
+
end
|
292
|
+
|
293
|
+
it "should not include change-tracking variables" do
|
294
|
+
comment.inspect.should_not include('title_was')
|
295
|
+
end
|
296
|
+
|
297
|
+
it "should include the normal persistent variables" do
|
298
|
+
comment.inspect.should include('title: "title"')
|
299
|
+
end
|
300
|
+
|
301
|
+
it "should include the id" do
|
302
|
+
comment.inspect.should include(%Q{_id: "123456abcdef",})
|
303
|
+
end
|
304
|
+
|
305
|
+
it "should include the revision" do
|
306
|
+
comment.inspect.should include(%Q{_rev: "1-654321fedcba",})
|
307
|
+
end
|
308
|
+
|
309
|
+
it "should return a complete string" do
|
310
|
+
# stub to work around (un)sorted hash on different rubies
|
311
|
+
comment.stub!(:attributes).and_return([['created_at', ''], ['updated_at', ''], ['title', 'title']])
|
312
|
+
comment.inspect.should == %Q{#<Comment _id: "123456abcdef", _rev: "1-654321fedcba", created_at: "", updated_at: "", title: "title">}
|
313
|
+
end
|
314
|
+
|
315
|
+
it "should include complex datatypes fully inspected" do
|
316
|
+
comment.title = {'en' => 'Blog post'}
|
317
|
+
comment.inspect.should include('title: {"en"=>"Blog post"}')
|
318
|
+
|
319
|
+
comment.title = nil
|
320
|
+
comment.inspect.should include('title: nil')
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|