aqua 0.1.6 → 0.2.0

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.
Files changed (37) hide show
  1. data/.gitignore +2 -1
  2. data/Aqua.gemspec +14 -11
  3. data/Rakefile +1 -1
  4. data/VERSION +1 -1
  5. data/lib/aqua.rb +5 -7
  6. data/lib/aqua/object/config.rb +2 -3
  7. data/lib/aqua/object/initializers.rb +309 -0
  8. data/lib/aqua/object/pack.rb +56 -132
  9. data/lib/aqua/object/query.rb +30 -2
  10. data/lib/aqua/object/stub.rb +60 -95
  11. data/lib/aqua/object/tank.rb +1 -0
  12. data/lib/aqua/object/translator.rb +313 -0
  13. data/lib/aqua/object/unpack.rb +26 -227
  14. data/lib/aqua/store/couch_db/couch_db.rb +1 -0
  15. data/lib/aqua/store/couch_db/database.rb +1 -1
  16. data/lib/aqua/store/couch_db/design_document.rb +126 -2
  17. data/lib/aqua/store/couch_db/result_set.rb +36 -0
  18. data/lib/aqua/store/couch_db/storage_methods.rb +182 -17
  19. data/lib/aqua/store/storage.rb +4 -48
  20. data/lib/aqua/support/mash.rb +2 -3
  21. data/lib/aqua/support/set.rb +4 -16
  22. data/spec/object/object_fixtures/array_udder.rb +1 -1
  23. data/spec/object/object_fixtures/persistent.rb +0 -2
  24. data/spec/object/pack_spec.rb +137 -517
  25. data/spec/object/query_spec.rb +36 -6
  26. data/spec/object/stub_spec.rb +10 -9
  27. data/spec/object/translator_packing_spec.rb +402 -0
  28. data/spec/object/translator_unpacking_spec.rb +262 -0
  29. data/spec/object/unpack_spec.rb +162 -320
  30. data/spec/spec_helper.rb +18 -0
  31. data/spec/store/couchdb/design_document_spec.rb +148 -7
  32. data/spec/store/couchdb/result_set_spec.rb +95 -0
  33. data/spec/store/couchdb/storage_methods_spec.rb +150 -10
  34. metadata +13 -9
  35. data/lib/aqua/support/initializers.rb +0 -216
  36. data/spec/object/object_fixtures/grounded.rb +0 -13
  37. data/spec/object/object_fixtures/sugar.rb +0 -4
@@ -137,8 +137,7 @@ unless defined?(HashWithIndifferentAccess)
137
137
  end
138
138
  end
139
139
  end
140
-
141
- Mash = HashWithIndifferentAccess unless defined?( Mash ) # because Mash is easier to write, thanks Merb!
142
-
143
140
  end
141
+
142
+ Mash = HashWithIndifferentAccess unless defined?( Mash ) # because Mash is easier to write, thanks Merb!
144
143
 
@@ -2,22 +2,10 @@
2
2
  require 'set'
3
3
 
4
4
  class Set
5
- include Aqua::Initializers
5
+ include Aqua::Initializers
6
+ hide_attributes :hash
6
7
 
7
- def to_aqua( base_object )
8
- hash = {
9
- 'class' => self.class.to_s,
10
- 'init' => to_aqua_init( base_object )
11
- }
12
- if (instance_variables - ['@hash']).size > 0
13
- hash.merge!({ 'ivars' => base_object._pack_ivars( self ) })
14
- end
15
- hash
16
- end
17
-
18
- def to_aqua_init( base_object )
19
- # keys returns an array
20
- # to_aqua_init will ensure that each of the objects is unpacked to aqua
21
- instance_variable_get("@hash").keys.to_aqua_init( base_object )
8
+ def to_aqua_init( path='' )
9
+ Aqua::Translator.pack_object( instance_variable_get("@hash").keys )
22
10
  end
23
11
  end
@@ -1,5 +1,5 @@
1
1
  class ArrayUdder < Array
2
2
  def udder
3
3
  @udder ||= 'Squeeze out some array milk'
4
- end
4
+ end
5
5
  end
@@ -6,7 +6,5 @@ class Persistent
6
6
  _aqua_opts
7
7
  end
8
8
 
9
-
10
-
11
9
  end
12
10
 
@@ -5,129 +5,22 @@ Aqua.set_storage_engine('CouchDB') # to initialize CouchDB
5
5
  CouchDB = Aqua::Store::CouchDB unless defined?( CouchDB )
6
6
 
7
7
  describe Aqua::Pack do
8
- before(:each) do
9
- @time = Time.now
10
- @date = Date.parse('12/23/1969')
11
- @log = Log.new( :message => "Hello World! This is a log entry", :created_at => Time.now )
12
- @user = User.new(
13
- :username => 'kane',
14
- :name => ['Kane', 'Baccigalupi'],
15
- :dob => @date,
16
- :created_at => @time,
17
- :log => @log,
18
- :password => 'my secret!'
19
- )
20
-
21
- def pack_grab_bag( value )
22
- @user.grab_bag = value
23
- @user._pack[:ivars][:@grab_bag]
24
- end
25
- end
26
8
 
27
- describe 'packing classes' do
28
- it 'should pack class variables'
29
- it 'should pack class level instance variables'
30
- it 'should pack class definition'
31
- it 'should save all the class details to the design document'
32
- it 'should package views/finds in the class and save them to the design document\'s view attribute'
33
- it 'should be saved into the design document'
34
- end
9
+ def pack_grab_bag( value )
10
+ @user.grab_bag = value
11
+ @user._pack[:ivars][:@grab_bag]
12
+ end
13
+
14
+ describe 'translator' do
15
+ # the translator packs the object
16
+ # then the translator passes back the attachments and the externals back to the pack/storage document
17
+ end
35
18
 
36
- describe 'external saves and stubs' do
19
+ describe 'hiding attributes' do
37
20
  before(:each) do
38
- User::Storage.database.delete_all
39
- @graeme = User.new(:username => 'graeme', :name => ['Graeme', 'Nelson'])
40
- @user.other_user = @graeme
41
- @pack = @user._pack
42
- end
43
-
44
- describe 'packing' do
45
- it 'should pack a stubbed object representation under __pack[:stubs]' do
46
- @pack[:stubs].size.should == 1
47
- other_user_pack = @pack[:stubs].first
48
- other_user_pack[:class].should == "User"
49
- other_user_pack[:id].should == @graeme
50
- end
51
-
52
- it 'should pack the values of a stubbed methods' do
53
- other_user_pack = @pack[:stubs].first
54
- other_user_pack[:methods].size.should == 1
55
- other_user_pack[:methods][:username].should == 'graeme'
56
- end
57
-
58
- it "should pack a stub of an object with embed=>false" do
59
- sugar = Sugar.new
60
- sugar.sweetness = Sugar.new
61
- lambda {sugar._pack}.should_not raise_error
62
- end
63
-
64
- it 'should pack an array of stubbed methods' do
65
- User.configure_aqua( :embed => {:stub => [:username, :name] } )
66
- @user = User.new(
67
- :username => 'kane',
68
- :name => ['Kane', 'Baccigalupi'],
69
- :dob => @date,
70
- :created_at => @time,
71
- :log => @log,
72
- :password => 'my secret!',
73
- :other_user => @graeme
74
- )
75
-
76
- @pack = @user._pack
77
- other_user_pack = @pack[:stubs].first
78
- other_user_pack[:methods].size.should == 2
79
- other_user_pack[:methods][:username].should == 'graeme'
80
- other_user_pack[:methods][:name].should == ['Graeme', 'Nelson']
81
-
82
- # reseting the User model, and @user instance
83
- User.configure_aqua( :embed => {:stub => :username } )
84
- end
85
-
86
- it 'should pack the object itself with the class "Aqua::Stub"' do
87
- @pack[:ivars][:@other_user][:class].should == "Aqua::Stub"
88
- end
89
-
90
- it 'should pack the object itself with a reference to the __pack[:stubs] object' do
91
- @pack[:ivars][:@other_user][:init].should == "/STUB_0"
92
- end
93
- end
94
-
95
- describe 'commiting' do
96
- it 'should commit external objects' do
97
- @user.commit!
98
- db_docs = CouchDB::Database.new.documents
99
- db_docs['total_rows'].should == 2
100
- end
101
-
102
- it 'should save the id to the stub after commiting' do
103
- @user.commit!
104
- doc = CouchDB.get( "http://127.0.0.1:5984/aqua/#{@user.id}" )
105
- doc["stubs"].first["id"].class.should == String
106
- end
107
-
108
- it 'should log a warning if an external object doesn\'t commit' do
109
- @graeme.should_receive(:commit).and_return(false)
110
- @user.commit!
111
- @user._warnings.size.should == 1
112
- @user._warnings.first.should match(/unable to save/i)
113
- end
21
+ build_user_ivars
22
+ end
114
23
 
115
- it 'should log a warning and save the id if an object has an id' do
116
- @graeme.commit!
117
- @graeme.should_receive(:commit).and_return(false)
118
- @user.commit!
119
- @user._warnings.size.should == 1
120
- @user._warnings.first.should match(/unable to save latest/i)
121
- doc = CouchDB.get( "http://127.0.0.1:5984/aqua/#{@user.id}" )
122
- doc["stubs"].first["id"].class.should == String
123
- end
124
-
125
- it 'should rollback external commits if the parent object doesn\'t save'
126
- end
127
-
128
- end
129
-
130
- describe 'hiding attributes' do
131
24
  it 'should add a class method for designating hidden instance variables' do
132
25
  User.should respond_to( :hide_attributes )
133
26
  end
@@ -148,417 +41,140 @@ describe Aqua::Pack do
148
41
  end
149
42
 
150
43
  it 'should not pack hidden variables' do
151
- @pack = @user._pack
152
- @pack[:ivars].keys.should_not include("@password")
44
+ pack = @user._pack
45
+ pack[:ivars].keys.should_not include("@password")
153
46
  end
154
- end
47
+ end
155
48
 
156
- describe 'packing up object instances:' do
157
- before(:each) do
158
- @pack = @user._pack
159
- end
160
-
161
- it 'should save its class name as an attribute on the pack document' do
162
- @pack[:class].should == 'User'
49
+ describe 'embed/stub reporting' do
50
+ before(:each) do
51
+ build_user_ivars
163
52
  end
164
-
165
- it 'should add an :id accessor if :id is not already an instance method' do
166
- @user.should respond_to(:id=)
53
+
54
+ describe '_embedded?' do
55
+ it 'should be true for embedded objects' do
56
+ @log._embedded?.should == true
57
+ end
58
+ it 'should be false for stubbed object with methods' do
59
+ @user._embedded?.should == false
60
+ end
61
+
62
+ it 'should be false without stubbed methods, where :embed configuration is false' do
63
+ p = Persistent.new
64
+ p._embedded?.should == false
65
+ end
167
66
  end
168
67
 
169
- it 'should pack an id if an id is present' # TODO
170
-
171
- it 'should not pack an id if an id is not present' do
172
- @pack.id.should be_nil
68
+ describe '_stubbed_methods' do
69
+ it 'should be an empty for embedded objects (with no possible stubbed methods)' do
70
+ @log._stubbed_methods.should == []
71
+ end
72
+
73
+ it 'should be an array the stub string or symbol method passed into configuration' do
74
+ @user._stubbed_methods.should == [:username]
75
+ end
76
+
77
+ it 'should be the array of the stub methods passed into configuration' do
78
+ User.configure_aqua :embed => { :stub => [:username, :name] }
79
+ @user._stubbed_methods.should == [:username, :name]
80
+ User.configure_aqua :embed => { :stub => :username } # resetting user model
81
+ end
173
82
  end
83
+
84
+ end
85
+
86
+ # Most of the serious packing tests are in packer_spec
87
+ # This is just to test/double-check that everything is working right withing an aquatic object
88
+ describe "nesting" do
89
+ before(:each) do
90
+ build_user_ivars
91
+ end
92
+
93
+ describe 'embedded aquatics' do
94
+ it 'should pack an embedded object internally' do
95
+ @pack[:ivars]['@log'].should == {
96
+ 'class' => 'Log',
97
+ 'ivars' => {'@message' => @message, '@created_at' => Aqua::Translator.pack_object( @time ).pack }
98
+ }
99
+ end
100
+ end
174
101
 
175
- it 'should pack the _rev if it is present' do
176
- @user.instance_variable_set("@_rev", '1-2222222')
177
- pack = @user._pack
178
- pack[:_rev].should == '1-2222222'
179
- end
180
-
181
- describe 'instance variables, ' do
182
- describe 'hashes'
183
- it 'should be in a hash-like object with the key :ivars' do
184
- @pack[:ivars].should_not be_nil
185
- @pack[:ivars].should respond_to(:keys)
186
- end
187
-
188
- it 'should save symbol keys differently that string keys' do
189
- @user.name = {:first => 'Kane', 'last' => 'Baccigalupi'}
190
- pack = @user._pack
191
- pack[:ivars][:@name][:init].keys.sort.should == [':first', 'last']
192
- end
102
+ describe 'externals' do
103
+ before(:each) do
104
+ User::Storage.database.delete_all
105
+ end
193
106
 
194
- describe 'basic ivars types' do
195
- it 'should pack strings as strings' do
196
- @pack[:ivars][:@username].should == 'kane'
197
- end
198
-
199
- it 'should pack an array of strings as a hash with the :class "Array" and :init as the original array' do
200
- @pack[:ivars][:@name].should == {'class' => 'Array', 'init' => ['Kane', 'Baccigalupi']}
201
- end
107
+ it 'should stub an external object' do
108
+ @pack[:ivars]['@other_user'].should == {
109
+ 'class' => 'Aqua::Stub',
110
+ 'init' => {'methods' => {'username' => 'strictnine' }, "class"=>"User", "id"=>""}
111
+ }
202
112
  end
203
-
204
- describe 'objects: ' do
205
- # TODO: http://www.ruby-doc.org/core/
206
- # make sure all the basic types work
207
113
 
208
- describe 'Time' do
209
- it 'should save as a hash with the class and to_s as the value' do
210
- time_hash = @pack[:ivars][:@created_at]
211
- time_hash['class'].should == 'Time'
212
- time_hash['init'].class.should == String
213
- end
214
-
215
- it 'the value should be reconstitutable with Time.parse' do
216
- # comparing times directly never works for me. It is probably a micro second issue or something
217
- @time.to_s.should == Time.parse( @pack[:ivars][:@created_at]['init'] ).to_s
218
- end
219
- end
220
-
221
- describe 'true and false' do
222
- it 'should save as self' do
223
- @user.grab_bag = true
224
- pack = @user._pack
225
- pack[:ivars][:@grab_bag].should == true
226
-
227
- @user.grab_bag = false
228
- pack = @user._pack
229
- pack[:ivars][:@grab_bag].should == false
230
- end
231
- end
232
-
233
- describe 'Date' do
234
- it 'should save as a hash with the class and to_s as the value' do
235
- time_hash = @pack[:ivars][:@dob]
236
- time_hash['class'].should == 'Date'
237
- time_hash['init'].class.should == String
238
- end
239
-
240
- it 'the value should be reconstitutable with Date.parse' do
241
- @date.should == Date.parse( @pack[:ivars][:@dob]['init'] )
242
- end
243
-
244
- it 'should not pack internally used ivars as specified by the class' do
245
- @pack[:ivars][:@dob][:ivars].keys.should_not include('@sg', '@of', '@ajd')
246
- end
247
- end
248
-
249
- describe 'Numbers' do
250
- it 'should pack Fixnums with correct class and value' do
251
- pack = pack_grab_bag( 42 )
252
- pack[:class].should == 'Fixnum'
253
- pack[:init].should == '42'
254
- end
255
-
256
- it 'should pack Bignums with correct class and value' do
257
- pack = pack_grab_bag( 123456789123456789 )
258
- pack[:class].should == 'Bignum'
259
- pack[:init].should == '123456789123456789'
260
- end
261
-
262
- it 'should pack Floats with correct class and value' do
263
- pack = pack_grab_bag( 3.2 )
264
- pack[:class].should == 'Float'
265
- pack[:init].should == '3.2'
266
- end
267
-
268
- it 'should pack Rationals with the correct class and values' do
269
- pack = pack_grab_bag( Rational( 1, 17 ) )
270
- pack[:class].should == 'Rational'
271
- pack[:init].should == ['1', '17']
272
- end
273
-
274
- end
275
-
276
- describe 'hashes with object as keys' do
277
- it 'should pack an hash containing only strings/symbols for keys and values, with an init value that is that hash and a class key' do
278
- @user.name = {'first' => 'Kane', 'last' => 'Baccigalupi'}
279
- pack = @user._pack
280
- pack[:ivars][:@name].should == {'class' => 'Hash', 'init' => {'first' => 'Kane', 'last' => 'Baccigalupi'} }
281
- end
282
-
283
- it 'should pack a numeric object key' do
284
- pack = pack_grab_bag( {1 => 'first', 2 => 'second'} )
285
- keys = pack[:init].keys
286
- keys.should include( '/OBJECT_0', '/OBJECT_1' )
287
- user_pack = @user.instance_variable_get("@__pack")
288
- user_pack[:keys].size.should == 2
289
- user_pack[:keys].first['class'].should == 'Fixnum'
290
- end
291
-
292
- it 'should pack a more complex object as a key' do
293
- struct = OpenStruct.new( :gerbil => true )
294
- pack = pack_grab_bag( { struct => 'first'} )
295
- keys = pack[:init].keys
296
- keys.should include( '/OBJECT_0' )
297
- user_pack = @user.instance_variable_get("@__pack")
298
- user_pack[:keys].size.should == 1
299
- user_pack[:keys].first['class'].should == 'OpenStruct'
300
- end
301
- end
302
-
303
- describe 'embeddable aquatic' do
304
- it 'aquatic objects should have packing instructions in the form of #_embed_me' do
305
- @user._embed_me.should == {'stub' => :username }
306
- Log.new._embed_me.should == true
307
- User.configure_aqua( :embed => {:stub => [:username, :name] } )
308
- @user._embed_me.should == { 'stub' => [:username, :name] }
309
- # reset for future tests
310
- User.configure_aqua( :embed => {:stub => :username } )
311
- end
312
-
313
- it 'should save their ivars correctly' do
314
- @pack[:ivars][:@log].keys.should include('ivars')
315
- @pack[:ivars][:@log]['ivars'].keys.should == ['@created_at', '@message']
316
- @pack[:ivars][:@log]['ivars']['@message'].should == "Hello World! This is a log entry"
317
- end
318
-
319
- it 'should correctly pack Array derivatives' do
320
- class Arrayed < Array
321
- aquatic
322
- attr_accessor :my_accessor
323
- end
324
- arrayish = Arrayed['a', 'b', 'c', 'd']
325
- arrayish.my_accessor = 'Newt'
326
- pack = arrayish._pack
327
- pack.keys.should include('class', 'init', 'ivars')
328
- pack['init'].class.should == Array
329
- pack['init'].should == ['a', 'b', 'c', 'd']
330
- pack['ivars']['@my_accessor'].should == 'Newt'
331
- end
332
-
333
- it 'should correctly pack Hash derivative' do
334
- class Hashed < Hash
335
- aquatic
336
- attr_accessor :my_accessor
337
- end
338
- hashish = Hashed.new
339
- hashish['1'] = '2'
340
- hashish.my_accessor = 'Newt'
341
- pack = hashish._pack
342
- pack.keys.should include('class', 'init', 'ivars')
343
- pack['init'].class.should == HashWithIndifferentAccess
344
- pack['init'].should == {'1' => '2'}
345
- pack['ivars']['@my_accessor'].should == 'Newt'
346
- end
347
-
348
- end
349
-
350
- describe 'non-aquatic' do
351
- before(:each) do
352
- @struct = OpenStruct.new(
353
- :gerbil => true,
354
- :cat => 'yup, that too!',
355
- :disaster => ['pow', 'blame', 'chase', 'spew']
356
- )
357
- @grounded = Grounded.new(
358
- :openly_structured => @struct,
359
- :hash_up => {:this => 'that'},
360
- :arraynged => ['swimming', 'should', 'be easy', 'if you float']
361
- )
362
-
363
- end
364
-
365
- describe 'OpenStructs' do
366
- before(:each) do
367
- @user.grab_bag = @struct
368
- pack = @user._pack
369
- @grab_bag = pack[:ivars][:@grab_bag]
370
- end
371
-
372
- it 'the key "class" should map to "OpenStruct"' do
373
- @grab_bag['class'].should == 'OpenStruct'
374
- end
375
-
376
- it 'the key "ivars" should have the key "@table", a private variable' do
377
- @grab_bag['ivars'].keys.should_not == ['@table']
378
- end
379
-
380
- it 'should initialize with the @table instance variable' do
381
- init_keys = @grab_bag['init'].keys
382
- init_keys.should include(':cat')
383
- init_keys.should include(':disaster')
384
- init_keys.should include(':gerbil')
385
- @grab_bag['init'][':gerbil'].should == true
386
- @grab_bag['init'][':cat'].should == 'yup, that too!'
387
- @grab_bag['init'][':disaster'].should == {'class' => 'Array', 'init' => ['pow', 'blame', 'chase', 'spew']}
388
- end
389
- end
390
-
391
- describe 'Uninherited classes with deep nesting' do
392
- before(:each) do
393
- @user.grab_bag = @grounded
394
- pack = @user._pack
395
- @grab_bag = pack[:ivars][:@grab_bag]
396
- end
397
-
398
- it 'the key "class" should map correctly to the class name' do
399
- @grab_bag['class'].should == 'Grounded'
400
- end
401
-
402
- it 'should have ivars keys for all the ivars' do
403
- keys = @grab_bag[:ivars].keys
404
- keys.should include('@openly_structured')
405
- keys.should include('@hash_up')
406
- keys.should include('@arraynged')
407
- end
408
-
409
- it 'should correctly display the nested OpenStruct' do
410
- user_2 = User.new(:grab_bag => @struct) # this has already been tested in the set above
411
- user_2._pack[:ivars][:@grab_bag].should == @grab_bag[:ivars][:@openly_structured]
412
- end
413
- end
414
-
415
- describe 'Classes inherited from Array' do
416
- before(:each) do
417
- @struct = OpenStruct.new(
418
- :gerbil => true,
419
- :cat => 'yup, that too!',
420
- :disaster => ['pow', 'blame', 'chase', 'spew'],
421
- :nipples => 'yes'
422
- )
423
- @strange_array = ArrayUdder['cat', 'octopus', @struct ]
424
- @strange_array.udder # sets an instance variable
425
- @user.grab_bag = @strange_array
426
- pack = @user._pack
427
- @grab_bag = pack[:ivars][:@grab_bag]
428
- end
429
-
430
- it 'should correctly map the class name' do
431
- @grab_bag[:class].should == 'ArrayUdder'
432
- end
433
-
434
- it 'should store the instance variables' do
435
- @grab_bag[:ivars].keys.should == ['@udder']
436
- end
437
-
438
- it 'should store the simple array values' do
439
- @grab_bag[:init].should_not be_nil
440
- @grab_bag[:init].class.should == Array
441
- @grab_bag[:init].should include('cat')
442
- @grab_bag[:init].should include('octopus')
443
- end
444
-
445
- it 'should store the more complex array values correctly' do
446
- user_2 = User.new(:grab_bag => @struct) # this has already been tested in the set above
447
- user_2._pack[:ivars][:@grab_bag].should == @grab_bag[:init].last
448
- end
449
- end
450
-
451
- describe 'Classes inherited from Hash' do
452
- before(:each) do
453
- @struct = OpenStruct.new(
454
- :gerbil => true,
455
- :cat => 'yup, that too!',
456
- :disaster => ['pow', 'blame', 'chase', 'spew'],
457
- :nipples => 'yes'
458
- )
459
- @hash_derivative = CannedHash.new(
460
- :ingredients => ['Corned Beef', 'Potatoes', 'Tin Can'],
461
- :healthometer => false,
462
- :random_struct => @struct
463
- )
464
- @hash_derivative.yum # sets an instance variable
465
- @user.grab_bag = @hash_derivative
466
- pack = @user._pack
467
- @grab_bag = pack[:ivars][:@grab_bag]
468
- end
469
-
470
- it 'should correctly map the class name' do
471
- @grab_bag[:class].should == 'CannedHash'
472
- end
473
-
474
- it 'should store the instance variables' do
475
- @grab_bag[:ivars].keys.should == ['@yum']
476
- end
477
-
478
- it 'should store the simple hash values' do
479
- @grab_bag[:init].should_not be_nil
480
- @grab_bag[:init].class.should == HashWithIndifferentAccess
481
-
482
- @grab_bag[:init].keys.should include('ingredients')
483
- @grab_bag[:init].keys.should include('healthometer')
484
- @grab_bag[:init].keys.should include('random_struct')
485
- end
486
-
487
- it 'should store the more complex hash values correctly' do
488
- user_2 = User.new(:grab_bag => @struct) # this has already been tested in the set above
489
- user_2._pack[:ivars][:@grab_bag].should == @grab_bag[:init][:random_struct]
490
- end
491
- end
492
-
493
- describe 'Embedded IO:' do
494
- before(:each) do
495
- @file = File.new(File.dirname(__FILE__) + '/../store/couchdb/fixtures_and_data/image_attach.png')
496
- @tempfile = Tempfile.new('temp.txt')
497
- @tempfile.write('I am a tempfile!')
498
- @tempfile.rewind
499
- end
500
-
501
- describe "File" do
502
- it 'should have pack its class name as Aqua::FileStub' do
503
- @user.grab_bag = @file
504
- @user._pack
505
- @user._pack[:ivars][:@grab_bag][:class].should == 'Aqua::FileStub'
506
- end
507
-
508
- it 'should have pack with an initialization key' do
509
- @user.grab_bag = @file
510
- pack = @user._pack
511
- pack[:ivars][:@grab_bag][:init].should == '/FILE_image_attach.png'
512
- end
513
-
514
- it 'should add an attachment to the pack' do
515
- @user.grab_bag = @file
516
- pack = @user._pack
517
- pack.attachments.size.should == 1
518
- pack.attachments.get('image_attach.png').should == @file
519
- end
520
-
521
- it 'should stub content type and length' do
522
- @user.grab_bag = @file
523
- pack = @user._pack
524
- pack[:ivars][:@grab_bag][:methods].should include('content_type', 'content_length')
525
- pack[:ivars][:@grab_bag][:methods]['content_type'].should == 'image/png'
526
- pack[:ivars][:@grab_bag][:methods]['content_length'].should == 26551
527
- end
528
- end
529
-
530
- describe 'Tempfile' do
531
- it 'should have pack its class name as Aqua::FileStub' do
532
- @user.grab_bag = @tempfile
533
- @user._pack
534
- @user._pack[:ivars][:@grab_bag][:class].should == 'Aqua::FileStub'
535
- end
536
-
537
- it 'should have pack with an initialization key' do
538
- @user.grab_bag = @tempfile
539
- pack = @user._pack
540
- pack[:ivars][:@grab_bag][:init].should == '/FILE_temp.txt'
541
- end
542
-
543
- it 'should add an attachment to the pack' do
544
- @user.grab_bag = @tempfile
545
- pack = @user._pack
546
- pack.attachments.size.should == 1
547
- pack.attachments.get('temp.txt').path.should == @tempfile.path
548
- end
549
- end
550
- end
551
- end
114
+ it 'should commit the external when saving the base object' do
115
+ @user.commit!
116
+ @other_user.id.should_not be_nil
117
+ @other_user.id.should_not == @other_user.object_id
118
+ end
119
+
120
+ it 'should commit external objects' do
121
+ @user.should_receive(:_commit_externals)
122
+ @user.commit!
552
123
  end
124
+
125
+ it 'should update the stubbed object id correctly' do
126
+ @user.instance_eval "_commit_externals"
127
+ @other_user.id.should_not be_empty
128
+ pack = @user._pack
129
+ pack[:ivars]['@other_user']['init']['id'].should == @other_user.id
130
+ end
131
+
132
+ it 'should save the document with the correct external ids' do
133
+ @user.commit!
134
+ document = User._get_store( @user.id )
135
+ document[:ivars]['@other_user']['init']['id'].should_not be_empty
136
+ end
137
+
138
+ describe 'transactions' do
139
+ it 'should rollback all externals if an one external fails to commit'
140
+ it 'should rollback all externals if the base object fails to commit'
141
+ end
142
+ end
143
+ end
144
+
145
+ describe 'pack ids and revs' do
146
+ before(:each) do
147
+ build_user_ivars
148
+ end
149
+
150
+ it 'should have a _rev if it is present in the base object' do
151
+ @user.instance_variable_set("@_rev", '1-2222222')
152
+ pack = @user._pack
153
+ pack[:_rev].should == '1-2222222'
553
154
  end
554
- end
155
+
156
+ it 'should not have a _rev of nil if _rev is not provided in the base' do
157
+ @pack[:_rev].should == nil
158
+ end
159
+
160
+ it 'should initially have an id of nil' do
161
+ @pack[:_rev].should == nil
162
+ end
163
+
164
+ it 'should pack the id if it exists in the base' do
165
+ @user.id = 'my_id'
166
+ pack = @user._pack
167
+ pack[:_id].should == 'my_id'
168
+ end
169
+ end
555
170
 
556
- describe 'committing packed objects to the store' do
557
- before(:each) do
171
+ describe 'commit' do
172
+ before(:each) do
173
+ build_user_ivars
558
174
  User::Storage.database.delete_all
559
175
  end
560
176
 
561
- it 'commit! should not raise errors on successful save' do
177
+ it 'commit! should not raise errors on successful save' do
562
178
  lambda{ @user.commit! }.should_not raise_error
563
179
  end
564
180
 
@@ -578,7 +194,7 @@ describe Aqua::Pack do
578
194
  @user.instance_variable_get('@_rev').should_not be_nil
579
195
  end
580
196
 
581
- it 'commit! should save the record to CouchDB' do
197
+ it 'commit! should save the record to CouchDB' do
582
198
  @user.commit!
583
199
  lambda{ CouchDB.get( "http://127.0.0.1:5984/aqua/#{@user.id}") }.should_not raise_error
584
200
  end
@@ -597,11 +213,15 @@ describe Aqua::Pack do
597
213
  @user.commit.should == false
598
214
  end
599
215
 
600
- it 'should be able to update and commit again' do
216
+ it 'should be able to update and commit again without conflict' do
601
217
  @user.commit!
602
218
  @user.grab_bag = {'1' => '2'}
603
219
  lambda{ @user.commit! }.should_not raise_error
604
220
  end
605
221
  end
606
-
222
+
223
+ describe 'classes' do
224
+ it 'should have a separate database'
225
+ end
226
+
607
227
  end