persistence 0.0.1.alpha → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (138) hide show
  1. data/CHANGELOG.md +4 -0
  2. data/README.md +260 -17
  3. data/lib/namespaces.rb +55 -0
  4. data/lib/persistence.rb +38 -3
  5. data/lib/persistence/adapter/abstract.rb +22 -0
  6. data/lib/persistence/adapter/abstract/enable_disable.rb +107 -0
  7. data/lib/persistence/adapter/abstract/primary_key/id_property_string.rb +33 -0
  8. data/lib/persistence/adapter/abstract/primary_key/simple.rb +29 -0
  9. data/lib/persistence/adapter/mock.rb +9 -0
  10. data/lib/persistence/adapter/mock/adapter_interface.rb +102 -0
  11. data/lib/persistence/adapter/mock/bucket.rb +9 -0
  12. data/lib/persistence/adapter/mock/bucket/bucket_interface.rb +260 -0
  13. data/lib/persistence/adapter/mock/bucket/index.rb +9 -0
  14. data/lib/persistence/adapter/mock/bucket/index/index_interface.rb +155 -0
  15. data/lib/persistence/adapter/mock/cursor.rb +9 -0
  16. data/lib/persistence/adapter/mock/cursor/cursor_interface.rb +238 -0
  17. data/lib/persistence/cursor.rb +11 -0
  18. data/lib/persistence/cursor/atomic.rb +110 -0
  19. data/lib/persistence/cursor/cursor_interface.rb +337 -0
  20. data/lib/persistence/exception/block_required.rb +7 -0
  21. data/lib/persistence/exception/conflicting_index_already_declared.rb +7 -0
  22. data/lib/persistence/exception/duplicate_violates_unique_index.rb +7 -0
  23. data/lib/persistence/exception/explicit_index_required.rb +7 -0
  24. data/lib/persistence/exception/indexing_block_failed_to_generate_keys.rb +7 -0
  25. data/lib/persistence/exception/indexing_object_requires_keys.rb +7 -0
  26. data/lib/persistence/exception/key_value_required.rb +7 -0
  27. data/lib/persistence/exception/no_port_enabled.rb +7 -0
  28. data/lib/persistence/object.rb +21 -0
  29. data/lib/persistence/object/autodetermine.rb +74 -0
  30. data/lib/persistence/object/class_instance.rb +1884 -0
  31. data/lib/persistence/object/complex.rb +17 -0
  32. data/lib/persistence/object/complex/array.rb +14 -0
  33. data/lib/persistence/object/complex/array/class_instance.rb +37 -0
  34. data/lib/persistence/object/complex/array/object_instance.rb +54 -0
  35. data/lib/persistence/object/complex/attributes.rb +1808 -0
  36. data/lib/persistence/object/complex/attributes/attributes_array.rb +32 -0
  37. data/lib/persistence/object/complex/attributes/attributes_hash.rb +187 -0
  38. data/lib/persistence/object/complex/attributes/default_atomic_non_atomic.rb +102 -0
  39. data/lib/persistence/object/complex/attributes/hash_to_port.rb +40 -0
  40. data/lib/persistence/object/complex/class_and_object_instance.rb +132 -0
  41. data/lib/persistence/object/complex/class_instance.rb +267 -0
  42. data/lib/persistence/object/complex/complex_object.rb +111 -0
  43. data/lib/persistence/object/complex/hash.rb +14 -0
  44. data/lib/persistence/object/complex/hash/class_instance.rb +40 -0
  45. data/lib/persistence/object/complex/hash/object_instance.rb +63 -0
  46. data/lib/persistence/object/complex/index/attribute_index.rb +10 -0
  47. data/lib/persistence/object/complex/index/attribute_index/attribute_index_interface.rb +43 -0
  48. data/lib/persistence/object/complex/object_instance.rb +469 -0
  49. data/lib/persistence/object/flat.rb +17 -0
  50. data/lib/persistence/object/flat/class_instance.rb +34 -0
  51. data/lib/persistence/object/flat/file.rb +14 -0
  52. data/lib/persistence/object/flat/file/class_instance.rb +122 -0
  53. data/lib/persistence/object/flat/file/contents.rb +7 -0
  54. data/lib/persistence/object/flat/file/file_persistence.rb +147 -0
  55. data/lib/persistence/object/flat/file/object_instance.rb +116 -0
  56. data/lib/persistence/object/flat/file/path.rb +9 -0
  57. data/lib/persistence/object/flat/object_instance.rb +24 -0
  58. data/lib/persistence/object/index.rb +479 -0
  59. data/lib/persistence/object/index/block_index.rb +10 -0
  60. data/lib/persistence/object/index/block_index/block_index_interface.rb +110 -0
  61. data/lib/persistence/object/index/explicit_index.rb +10 -0
  62. data/lib/persistence/object/index/explicit_index/explicit_index_interface.rb +57 -0
  63. data/lib/persistence/object/index_hash.rb +40 -0
  64. data/lib/persistence/object/object_instance.rb +322 -0
  65. data/lib/persistence/object/parse_persistence_args.rb +145 -0
  66. data/lib/persistence/port.rb +9 -0
  67. data/lib/persistence/port/bucket.rb +9 -0
  68. data/lib/persistence/port/bucket/bucket_index.rb +9 -0
  69. data/lib/persistence/port/bucket/bucket_interface.rb +685 -0
  70. data/lib/persistence/port/controller.rb +263 -0
  71. data/lib/persistence/port/port_interface.rb +417 -0
  72. data/lib/requires.rb +146 -0
  73. data/spec/Integration_spec.rb +53 -0
  74. data/spec/Persistence_spec.rb +175 -0
  75. data/spec/example_objects.rb +6 -0
  76. data/spec/example_objects/complex_object.rb +7 -0
  77. data/spec/example_objects/complex_object/array_object.rb +7 -0
  78. data/spec/example_objects/complex_object/hash_object.rb +7 -0
  79. data/spec/example_objects/flat_object.rb +7 -0
  80. data/spec/example_objects/flat_object/file_object.rb +7 -0
  81. data/spec/persistence/adapter/enable_disable_spec.rb +29 -0
  82. data/spec/persistence/adapter/mock/cursor_spec.rb +64 -0
  83. data/spec/persistence/adapter/mock_helpers.rb +27 -0
  84. data/spec/persistence/adapter/mock_helpers/bucket.rb +10 -0
  85. data/spec/persistence/adapter/mock_helpers/integration/dictionary_hash.rb +4 -0
  86. data/spec/persistence/adapter/mock_helpers/integration/note.rb +18 -0
  87. data/spec/persistence/adapter/mock_helpers/integration/notes_array.rb +4 -0
  88. data/spec/persistence/adapter/mock_helpers/integration/user.rb +44 -0
  89. data/spec/persistence/adapter/mock_helpers/integration/user/address.rb +18 -0
  90. data/spec/persistence/adapter/mock_helpers/integration/user/dictionary_entry.rb +12 -0
  91. data/spec/persistence/adapter/mock_helpers/integration/user/sub_account.rb +15 -0
  92. data/spec/persistence/adapter/mock_helpers/object.rb +87 -0
  93. data/spec/persistence/adapter/mock_helpers/port.rb +21 -0
  94. data/spec/persistence/adapter/mock_spec.rb +211 -0
  95. data/spec/persistence/adapter/primary_key/id_property_string_spec.rb +27 -0
  96. data/spec/persistence/adapter/primary_key/simple_spec.rb +19 -0
  97. data/spec/persistence/adapter/spec_abstract/adapter_spec.rb +223 -0
  98. data/spec/persistence/adapter/spec_abstract/cursor_spec.rb +116 -0
  99. data/spec/persistence/cursor/atomic_spec.rb +86 -0
  100. data/spec/persistence/cursor/object_and_class_instance_spec.rb +73 -0
  101. data/spec/persistence/cursor_spec.rb +128 -0
  102. data/spec/persistence/object/complex/attributes/persistence_hash/array_instance_spec.rb +51 -0
  103. data/spec/persistence/object/complex/attributes/persistence_hash/hash_instance_spec.rb +56 -0
  104. data/spec/persistence/object/complex/attributes_spec.rb +1717 -0
  105. data/spec/persistence/object/complex/complex_spec.rb +922 -0
  106. data/spec/persistence/object/complex/index/attribute_index_spec.rb +76 -0
  107. data/spec/persistence/object/flat/bignum_spec.rb +33 -0
  108. data/spec/persistence/object/flat/class_instance_spec.rb +30 -0
  109. data/spec/persistence/object/flat/class_spec.rb +38 -0
  110. data/spec/persistence/object/flat/complex_spec.rb +36 -0
  111. data/spec/persistence/object/flat/false_class_spec.rb +34 -0
  112. data/spec/persistence/object/flat/file/class_instance_spec.rb +54 -0
  113. data/spec/persistence/object/flat/file/object_instance_spec.rb +143 -0
  114. data/spec/persistence/object/flat/file_spec.rb +64 -0
  115. data/spec/persistence/object/flat/fixnum_spec.rb +32 -0
  116. data/spec/persistence/object/flat/float_spec.rb +32 -0
  117. data/spec/persistence/object/flat/indexing_spec.rb +38 -0
  118. data/spec/persistence/object/flat/rational_spec.rb +33 -0
  119. data/spec/persistence/object/flat/regexp_spec.rb +32 -0
  120. data/spec/persistence/object/flat/string_spec.rb +34 -0
  121. data/spec/persistence/object/flat/symbol_spec.rb +32 -0
  122. data/spec/persistence/object/flat/true_class_spec.rb +32 -0
  123. data/spec/persistence/object/indexes/block_index_spec.rb +119 -0
  124. data/spec/persistence/object/indexes/explicit_index_spec.rb +112 -0
  125. data/spec/persistence/object/parse_persistence_args_spec.rb +65 -0
  126. data/spec/persistence/object_spec.rb +310 -0
  127. data/spec/persistence/port/bucket/bucket_interface_spec.rb +146 -0
  128. data/spec/persistence/port/bucket/index/bucket_index_spec.rb +67 -0
  129. data/spec/persistence/port/bucket_spec.rb +20 -0
  130. data/spec/persistence/port/controller_spec.rb +60 -0
  131. data/spec/persistence/port/port_interface_spec.rb +105 -0
  132. metadata +178 -21
  133. data/.gitignore +0 -17
  134. data/Gemfile +0 -4
  135. data/LICENSE +0 -22
  136. data/Rakefile +0 -2
  137. data/lib/persistence/version.rb +0 -3
  138. data/persistence.gemspec +0 -17
@@ -0,0 +1,922 @@
1
+
2
+ require_relative '../../../../lib/persistence.rb'
3
+
4
+ describe ::Persistence::Object::Complex do
5
+
6
+ before :all do
7
+
8
+ ::Persistence.enable_port( :mock, ::Persistence::Adapter::Mock.new )
9
+
10
+ class ::Persistence::Object::Complex::UserObject
11
+ include ::Persistence::Object
12
+ attr_accessor :username, :firstname, :lastname
13
+ attr_index :username
14
+ end
15
+
16
+ class ::Persistence::Object::Complex::Address
17
+ include ::Persistence::Object
18
+ attr_accessor :number, :street, :city, :state, :zipcode
19
+ end
20
+
21
+ class ::Persistence::Object::Complex::HashContainerClass
22
+ include ::Persistence::Object
23
+ attr_accessor :some_hash, :storage_key
24
+ attr_index :storage_key
25
+ end
26
+
27
+ class ::Persistence::Object::Complex::ArrayContainerClass
28
+ include ::Persistence::Object
29
+ attr_accessor :array, :storage_key
30
+ attr_index :storage_key
31
+ end
32
+
33
+ end
34
+
35
+ after :all do
36
+
37
+ ::Persistence.disable_port( :mock )
38
+
39
+ end
40
+
41
+ it 'can persist complex objects' do
42
+ class ::Persistence::Object::Complex::UserMock
43
+ include ::Persistence::Object::Complex
44
+ attr_non_atomic_accessor :username, :firstname, :lastname, :address, :alternate_address
45
+ end
46
+ class ::Persistence::Object::Complex::AddressMock
47
+ include ::Persistence::Object::Complex
48
+ attr_non_atomic_accessor :number, :street, :city, :state, :zipcode
49
+ end
50
+
51
+ user = ::Persistence::Object::Complex::UserMock.new
52
+ user.username = 'user'
53
+ user.firstname = 'first'
54
+ user.lastname = 'last'
55
+
56
+ user.address = ::Persistence::Object::Complex::AddressMock.new
57
+ user.address.number = 42
58
+ user.address.street = 'Street'
59
+ user.address.city = 'Some City'
60
+ user.address.state = 'GA'
61
+ user.address.zipcode = '30003'
62
+
63
+ user.alternate_address = ::Persistence::Object::Complex::AddressMock.new
64
+ user.alternate_address.number = 37
65
+ user.alternate_address.street = 'Another Street'
66
+ user.alternate_address.city = 'Some Other City'
67
+ user.alternate_address.state = 'TX'
68
+ user.alternate_address.zipcode = '70004'
69
+ user.persist!
70
+
71
+ ::Persistence::Object::Complex::UserMock.persist( user.persistence_id ).should == user
72
+
73
+ user.alternate_address.number = 48
74
+
75
+ user.alternate_address.persist!
76
+
77
+ ::Persistence::Object::Complex::UserMock.persist( user.persistence_id ).should == user
78
+
79
+ end
80
+
81
+ ####################
82
+ # attr_flat #
83
+ # persists_flat? #
84
+ # attr_flat! #
85
+ ####################
86
+
87
+ it 'can force storing a attribute as a flat object' do
88
+ class ::Persistence::Object::Complex::AttrFlatMock
89
+
90
+ class ClassInstance
91
+
92
+ include ::Persistence::Object::Complex
93
+
94
+ persists_flat?( :some_attribute ).should == false
95
+ attr_flat :some_attribute
96
+ persists_flat?( :some_attribute ).should == true
97
+ non_atomic_attributes[ :some_other_attribute ] = :accessor
98
+ non_atomic_attributes[ :another_attribute ] = :accessor
99
+ attr_flat!
100
+ persists_flat?( :some_attribute ).should == true
101
+ persists_flat?( :some_other_attribute ).should == true
102
+ persists_flat?( :another_attribute ).should == true
103
+
104
+ end
105
+ end
106
+ end
107
+
108
+ ############
109
+ # cease! #
110
+ ############
111
+
112
+ it 'can delete an object by ID' do
113
+ module ::Persistence::Object::Complex::CeaseClassMock
114
+
115
+ class ClassInstance
116
+ include ::Persistence::Object::Complex
117
+ attr_non_atomic_accessor :some_value, :some_other_value
118
+ end
119
+
120
+ instance = ClassInstance.new
121
+ instance.some_value = :value
122
+ instance.some_other_value = :other_value
123
+ instance.persist!
124
+ copy = ClassInstance.persist( instance.persistence_id )
125
+ copy.should == instance
126
+ ClassInstance.cease!( instance.persistence_id )
127
+ ClassInstance.persist( instance.persistence_id ).should == nil
128
+
129
+ end
130
+ end
131
+
132
+ ################################
133
+ # attr_index #
134
+ # attr_index_with_duplicates #
135
+ ################################
136
+
137
+ it 'can create an index on a attribute' do
138
+ class ::Persistence::Object::Complex::AttrIndexMock
139
+
140
+ class ClassInstance
141
+
142
+ include ::Persistence::Object::Complex
143
+
144
+ attr_index :attribute_index
145
+ attr_index_with_duplicates :attribute_index_with_duplicates
146
+
147
+ has_attribute_index?( :attribute_index ).should == true
148
+ has_index?( :attribute_index ).should == true
149
+ has_attribute_index?( :attribute_index_with_duplicates ).should == true
150
+ has_index?( :attribute_index_with_duplicates ).should == true
151
+ index( :attribute_index ).is_a?( ::Persistence::Object::Index ).should == true
152
+ index( :attribute_index_with_duplicates ).is_a?( ::Persistence::Object::Index ).should == true
153
+
154
+ end
155
+
156
+ end
157
+ end
158
+
159
+ ###################################
160
+ # attr_delete_cascades #
161
+ # attr_delete_does_not_cascade #
162
+ # delete_cascades? #
163
+ # attr_delete_cascades! #
164
+ # attr_delete_does_not_cascade! #
165
+ ###################################
166
+
167
+ it 'can set an attribute to be deleted if self is deleted' do
168
+ module ::Persistence::Object::Complex::DeleteCascadesMock
169
+
170
+ class ObjectInstance
171
+ include ::Persistence::Object::Complex
172
+ attr_non_atomic_accessor :some_attribute, :cascading_attribute, :non_cascading_attribute, :complex_attribute
173
+ attr_delete_cascades :some_attribute
174
+ delete_cascades?( :some_attribute ).should == true
175
+ attr_delete_does_not_cascade :some_attribute
176
+ delete_cascades?( :some_attribute ).should == false
177
+ attr_delete_cascades!
178
+ delete_cascades?( :some_attribute ).should == true
179
+ attr_delete_does_not_cascade!
180
+ delete_cascades?( :some_attribute ).should == false
181
+ attr_delete_cascades :cascading_attribute
182
+ attr_delete_does_not_cascade :non_cascading_attribute
183
+ delete_cascades?( :cascading_attribute ).should == true
184
+ delete_cascades?( :non_cascading_attribute ).should == false
185
+ end
186
+ ObjectInstance.new.instance_eval do
187
+ delete_cascades?( :cascading_attribute ).should == true
188
+ delete_cascades?( :non_cascading_attribute ).should == false
189
+ object = ObjectInstance.new
190
+ object.persistence_bucket = persistence_bucket
191
+ persistence_bucket.put_object!( self )
192
+ persistence_bucket.put_attribute!( self, :complex_attribute, object )
193
+ # FIX - still have to figure out details of this
194
+ # delete_cascades?( :complex_attribute ).should == true
195
+ end
196
+
197
+ end
198
+ end
199
+
200
+ ########
201
+ # == #
202
+ ########
203
+
204
+ it 'can compare objects' do
205
+ module ::Persistence::Object::Complex::EqualsMock
206
+
207
+ class ObjectInstance
208
+ include ::Persistence::Object::Complex
209
+ attr_non_atomic_accessor :some_var, :some_other_var
210
+ end
211
+
212
+ # if we have the same ruby instance
213
+ instance = ObjectInstance.new
214
+ instance.persistence_id = 0
215
+ ( instance == instance ).should == true
216
+
217
+ # or if we have an id for both objects and the ids are not the same
218
+ other_instance = ObjectInstance.new
219
+ other_instance.persistence_id = 0
220
+ yet_other_instance = ObjectInstance.new
221
+ yet_other_instance.persistence_id = 1
222
+ ( instance == other_instance ).should == true
223
+ ( instance == yet_other_instance ).should == false
224
+
225
+ # or if the classes are not the same
226
+ ( instance == Object.new ).should == false
227
+
228
+ # otherwise if we have instance variables, compare
229
+ instance.instance_eval do
230
+ self.some_var = :some_value
231
+ self.persistence_id = nil
232
+ end
233
+ yet_other_instance.instance_eval do
234
+ self.some_var = :some_value
235
+ self.persistence_id = nil
236
+ end
237
+ ( instance == yet_other_instance ).should == true
238
+ yet_other_instance.instance_eval do
239
+ self.some_other_var = :some_other_value
240
+ end
241
+ ( instance == yet_other_instance ).should == false
242
+
243
+ end
244
+ end
245
+
246
+ ##############################
247
+ # persistence_hash_to_port #
248
+ ##############################
249
+
250
+ it "can create a persistence hash to correspond to persistence state" do
251
+ module ::Persistence::Object::Complex::PersistenceHashToPortMock
252
+
253
+ class ObjectInstance
254
+
255
+ include ::Persistence::Object::Complex
256
+
257
+ attr_atomic_accessor :flat_atomic_attribute
258
+ attr_atomic_accessor :complex_atomic_attribute
259
+ attr_non_atomic_accessor :flat_non_atomic_attribute
260
+ attr_non_atomic_accessor :complex_non_atomic_attribute
261
+ attr_accessor :flat_non_persistent_attribute
262
+ attr_accessor :complex_non_persistent_attribute
263
+ attr_flat :flat_attribute
264
+ attr_accessor :flat_non_persistent_attribute, :complex_non_persistent_attribute, :flat_attribute
265
+
266
+ def persist!
267
+ persistence_port.put_object!( self )
268
+ return self
269
+ end
270
+
271
+ end
272
+
273
+ instance = ObjectInstance.new
274
+
275
+ # flat object for attribute and for variable
276
+ instance.flat_atomic_attribute = 'flat atomic_attribute value'
277
+ complex_atomic_element = ObjectInstance.new
278
+ complex_atomic_element.flat_atomic_attribute = 'flat sub-atomic attribute'
279
+ instance.complex_atomic_attribute = complex_atomic_element
280
+
281
+ # complex object for attribute and for variable
282
+ instance.flat_non_atomic_attribute = 'flat non_atomic_attribute value'
283
+ complex_non_atomic_element = ObjectInstance.new
284
+ complex_non_atomic_element.flat_atomic_attribute = 'flat sub-atomic attribute'
285
+ instance.complex_non_atomic_attribute = complex_non_atomic_element
286
+
287
+ # non-persistent value
288
+ instance.flat_non_persistent_attribute = 'flat_non_persistent_attribute value'
289
+ instance.complex_non_persistent_attribute = 'complex_non_persistent_attribute value'
290
+
291
+ # flat complex object for attribute and for variable
292
+ instance.flat_attribute = 'flat_attribute value'
293
+
294
+ # get hash
295
+ hash_to_port = instance.persistence_hash_to_port
296
+
297
+ # make sure that flat atomic elements and non-atomic elements are included
298
+ hash_to_port[ :flat_atomic_attribute ].should == 'flat atomic_attribute value'
299
+ hash_to_port[ :flat_non_atomic_attribute ].should == 'flat non_atomic_attribute value'
300
+
301
+ # make sure that complex objects are stored by ID
302
+ hash_to_port[ :complex_atomic_attribute ].persistence_id.should == complex_atomic_element.persistence_id
303
+ hash_to_port[ :complex_non_atomic_attribute ].persistence_id.should == complex_non_atomic_element.persistence_id
304
+
305
+ end
306
+ end
307
+
308
+ ###################
309
+ # get_attribute #
310
+ ###################
311
+
312
+ it 'can serve as an adapter to a persistence bucket instance in an adapter instance' do
313
+ module ::Persistence::Object::Complex::GetAttributeMock
314
+
315
+ class ObjectInstance
316
+ include ::Persistence::Object::Complex
317
+ attr_non_atomic_accessor :simple_var, :complex_var
318
+ end
319
+ sub_object = ObjectInstance.new.instance_eval do
320
+ self.simple_var = :value
321
+ self
322
+ end
323
+ object = ObjectInstance.new.instance_eval do
324
+ self.simple_var = :some_value
325
+ self.complex_var = sub_object
326
+ self
327
+ end
328
+ bucket_instance = object.persistence_port.persistence_bucket( :some_bucket )
329
+ bucket_instance.put_object!( object )
330
+ object.persistence_id.should_not == nil
331
+ bucket_instance.get_attribute( object, :simple_var ).should == :some_value
332
+ bucket_instance.get_attribute( object, :complex_var ).persistence_hash_to_port.should == sub_object.persistence_hash_to_port
333
+ bucket_instance.delete_attribute!( object, :complex_var )
334
+ bucket_instance.get_attribute( object, :complex_var ).should == nil
335
+ bucket_instance.put_attribute!( object, :complex_var, sub_object )
336
+ bucket_instance.get_attribute( object, :complex_var ).persistence_hash_to_port.should == sub_object.persistence_hash_to_port
337
+
338
+ end
339
+ end
340
+
341
+ ####################################
342
+ # remove_atomic_attribute_values #
343
+ ####################################
344
+
345
+ it 'can remove any instance variables that are defined as atomic attributes' do
346
+ class ::Persistence::Object::Complex::PrivateMock
347
+ include ::Persistence::Object::Complex
348
+ attr_atomic_accessor :attribute1, :attribute2
349
+ end
350
+ ::Persistence::Object::Complex::PrivateMock.new.instance_eval do
351
+ self.attribute1 = :value1
352
+ self.attribute2 = :value2
353
+ remove_atomic_attribute_values
354
+ self.class::Controller.default_encapsulation.has_configuration_value?( self, :attribute1 ).should == false
355
+ self.class::Controller.default_encapsulation.has_configuration_value?( self, :attribute2 ).should == false
356
+ end
357
+ end
358
+
359
+ ########################
360
+ # is_complex_object? #
361
+ ########################
362
+
363
+ it 'can report whether an object should be treated as complex' do
364
+ class ::Persistence::Object::Complex::Mock
365
+ include ::Persistence::Object::Complex
366
+ attr_atomic_accessor :attribute1, :attribute2
367
+ end
368
+ ::Persistence::Object::Complex::Mock.new.instance_eval do
369
+ is_complex_object?( 2**64 ).should == false # Bignum
370
+ is_complex_object?( 2 ).should == false # Fixnum
371
+ is_complex_object?( Complex( 2, 3 ) ).should == false # Complex
372
+ is_complex_object?( Rational( 2, 3 ) ).should == false # Rational
373
+ is_complex_object?( true ).should == false # TrueClass
374
+ is_complex_object?( false ).should == false # FalseClass
375
+ is_complex_object?( 'some string' ).should == false # String
376
+ is_complex_object?( :some_symbol ).should == false # Symbol
377
+ is_complex_object?( /some_string/ ).should == false # Regexp
378
+ is_complex_object?( File.new( '.' ) ).should == false # File
379
+ is_complex_object?( ::Persistence::Object::Flat::File::Path.new( '/some/path' ) ).should == false # File::Path
380
+ is_complex_object?( ::Persistence::Object::Flat::File::Contents.new( 'some file contents' ) ).should == false # File::Contents
381
+ is_complex_object?( nil ).should == false # NilClass
382
+ is_complex_object?( Object.new ).should == true # Object
383
+ end
384
+ end
385
+
386
+ ###########################################################################################################
387
+ # public ################################################################################################
388
+ ###########################################################################################################
389
+
390
+ ###################
391
+ # get_attribute #
392
+ # set_attribute #
393
+ ###################
394
+
395
+ it 'can get a variable atomically if appropriate' do
396
+ class ::Persistence::Object::Complex::Mock
397
+ include ::Persistence::Object::Complex
398
+ attr_atomic_accessor :atomic_attribute
399
+ attr_non_atomic_accessor :non_atomic_attribute
400
+ end
401
+ # test without persistence id
402
+ ::Persistence::Object::Complex::Mock.new.instance_eval do
403
+ get_attribute( :atomic_attribute ).should == nil
404
+ set_attribute( :atomic_attribute, :some_value )
405
+ get_attribute( :atomic_attribute ).should == :some_value
406
+ end
407
+
408
+ # test with persistence id and non-atomic
409
+ ::Persistence::Object::Complex::Mock.new.instance_eval do
410
+ self.persistence_id = 0
411
+ get_attribute( :non_atomic_attribute ).should == nil
412
+ set_attribute( :non_atomic_attribute, :some_value )
413
+ get_attribute( :non_atomic_attribute ).should == :some_value
414
+ end
415
+
416
+ # test with persistence id and atomic
417
+ ::Persistence::Object::Complex::Mock.new.instance_eval do
418
+ atomic_attribute?( :atomic_attribute ).should == true
419
+ self.persistence_id = 1
420
+ get_attribute( :atomic_attribute ).should == nil
421
+ persistence_bucket.put_attribute!( self, :atomic_attribute, :some_value )
422
+ get_attribute( :atomic_attribute ).should == :some_value
423
+ end
424
+
425
+ # test with persistence id and atomic
426
+ ::Persistence::Object::Complex::Mock.new.instance_eval do
427
+ atomic_attribute?( :atomic_attribute ).should == true
428
+ self.persistence_id = 2
429
+ get_attribute( :atomic_attribute ).should == nil
430
+ instance = ::Persistence::Object::Complex::Mock.new
431
+ # we don't want our port value; we give it the wrong value to make sure
432
+ persistence_port.persistence_bucket( persistence_bucket.name ).put_attribute!( self, :atomic_attribute, instance )
433
+ get_attribute( :atomic_attribute ).should == instance
434
+ get_attribute( :non_atomic_attribute ).should == nil
435
+ set_attribute( :non_atomic_attribute, :some_other_value )
436
+ # we don't want our port value; we give it the wrong value to make sure
437
+ persistence_port.persistence_bucket( persistence_bucket.name ).put_attribute!( self, :non_atomic_attribute, :not_some_other_value )
438
+ get_attribute( :non_atomic_attribute ).should == :some_other_value
439
+ end
440
+
441
+ end
442
+
443
+ ###################
444
+ # set_attribute #
445
+ ###################
446
+
447
+ it 'can set a variable atomically if appropriate' do
448
+ class ::Persistence::Object::Complex::Mock
449
+ include ::Persistence::Object::Complex
450
+ attr_atomic_accessor :atomic_attribute
451
+ attr_non_atomic_accessor :non_atomic_attribute
452
+ end
453
+
454
+ # test without persistence id and non-atomic
455
+ ::Persistence::Object::Complex::Mock.new.instance_eval do
456
+ attr_non_atomic_accessor :some_var
457
+ get_attribute( :some_var ).should == nil
458
+ set_attribute( :some_var, :some_value )
459
+ get_attribute( :some_var ).should == :some_value
460
+ end
461
+
462
+ # test without persistence id and atomic
463
+ ::Persistence::Object::Complex::Mock.new.instance_eval do
464
+ attr_atomic_accessor :some_var
465
+ get_attribute( :some_var ).should == nil
466
+ set_attribute( :some_var, :some_value )
467
+ get_attribute( :some_var ).should == :some_value
468
+ end
469
+
470
+ # test with persistence id and non-atomic
471
+ ::Persistence::Object::Complex::Mock.new.instance_eval do
472
+ attr_non_atomic_accessor :some_var
473
+ self.persistence_id = 0
474
+ get_attribute( :some_var ).should == nil
475
+ set_attribute( :some_var, :some_value )
476
+ persistence_port.persistence_bucket( persistence_bucket.name ).get_attribute( self, :some_other_var ).should == nil
477
+ get_attribute( :some_var ).should == :some_value
478
+ end
479
+
480
+ # test with persistence id and atomic
481
+ ::Persistence::Object::Complex::Mock.new.instance_eval do
482
+ attr_atomic_accessor :some_var
483
+ self.persistence_id = 0
484
+ get_attribute( :some_var ).should == nil
485
+ set_attribute( :some_var, :some_value )
486
+ persistence_port.persistence_bucket( persistence_bucket.name ).get_attribute( self, :some_var ).should == :some_value
487
+ get_attribute( :some_var ).should == :some_value
488
+ end
489
+
490
+ end
491
+
492
+ #######################
493
+ # load_atomic_state #
494
+ #######################
495
+
496
+ it 'can load values for atomic state ' do
497
+ class ::Persistence::Object::Complex::PrivateMock
498
+ include ::Persistence::Object::Complex
499
+ attr_atomic_accessor :attribute1, :attribute2
500
+ end
501
+ ::Persistence::Object::Complex::PrivateMock.new.instance_eval do
502
+ self.attribute1 = :value1
503
+ self.attribute2 = :value2
504
+ load_atomic_state
505
+ @attribute1.should == :value1
506
+ @attribute2.should == :value2
507
+ end
508
+ end
509
+
510
+ it "can persist an object to and from a default bucket with an arbitrary key method" do
511
+ module ::Persistence::Object::Complex::ArbitraryKeyMethodMock
512
+
513
+ class UserObject < ::Persistence::Object::Complex::UserObject
514
+ end
515
+
516
+ user = UserObject.new
517
+ user.username = 'user'
518
+ user.firstname = 'first'
519
+ user.lastname = 'last'
520
+ user.persist!
521
+ UserObject.persist( :username => 'user' ).should == user
522
+
523
+ end
524
+ end
525
+
526
+ it "can persist an object to and from a default bucket with an arbitrary key variable" do
527
+ module ::Persistence::Object::Complex::ArbitraryKeyVariableMock
528
+
529
+ class UserObject < ::Persistence::Object::Complex::UserObject
530
+ end
531
+
532
+ user = UserObject.new
533
+ user.username = 'user'
534
+ user.firstname = 'first'
535
+ user.lastname = 'last'
536
+ user.persist!
537
+ UserObject.persist( :username => 'user' ).should == user
538
+
539
+ end
540
+ end
541
+
542
+ it "can persist an object with other objects as members" do
543
+ module ::Persistence::Object::Complex::ArbitraryNestedObjectMock
544
+
545
+ class UserObject < ::Persistence::Object::Complex::UserObject
546
+ attr_accessor :username, :firstname, :lastname, :address, :alternate_address
547
+ attr_index :username
548
+ end
549
+
550
+ class Address < ::Persistence::Object::Complex::Address
551
+ attr_accessor :number, :street, :city, :state, :zipcode
552
+ end
553
+
554
+ user = UserObject.new
555
+ user.username = 'user'
556
+ user.firstname = 'first'
557
+ user.lastname = 'last'
558
+
559
+ user.address = Address.new
560
+ user.address.number = 42
561
+ user.address.street = 'Street'
562
+ user.address.city = 'Some City'
563
+ user.address.state = 'GA'
564
+ user.address.zipcode = '30003'
565
+
566
+ user.alternate_address = Address.new
567
+ user.alternate_address.number = 37
568
+ user.alternate_address.street = 'Another Street'
569
+ user.alternate_address.city = 'Some Other City'
570
+ user.alternate_address.state = 'TX'
571
+ user.alternate_address.zipcode = '70004'
572
+ user.persist!
573
+
574
+ # here we should be looking for:
575
+ # * username => 'user' => looks for 'user' with bucket (should find it and replace it)
576
+ # * address => should get ID from existing user if user exists => needs to check if existing user address is same ID
577
+ # * alternate_ddress => should also get ID from existing user if user exists => needs to check if existing alternate address is same ID
578
+
579
+ UserObject.persist( :username => 'user' ).should == user
580
+
581
+ user.alternate_address.number = 48
582
+
583
+ user.alternate_address.persist!
584
+
585
+ UserObject.persist( :username => 'user' ).should == user
586
+
587
+ end
588
+ end
589
+
590
+ it "can persist an object with other objects as members that have atomic properties" do
591
+ module ::Persistence::Object::Complex::NestedAtomicObjectsMock
592
+
593
+ class UserObject < ::Persistence::Object::Complex::UserObject
594
+ attr_accessor :username, :firstname, :lastname, :address, :alternate_address
595
+ attr_index :username
596
+ end
597
+
598
+ class Address < ::Persistence::Object::Complex::Address
599
+ attr_accessor :number, :street, :city, :state, :zipcode
600
+ attr_atomic_accessor :number
601
+ attrs_atomic!
602
+ end
603
+
604
+ Address.atomic_attribute?( :number ).should == true
605
+
606
+ user = UserObject.new
607
+ user.username = 'user'
608
+ user.firstname = 'first'
609
+ user.lastname = 'last'
610
+
611
+ user.address = Address.new
612
+ user.address.number = 42
613
+ user.address.street = 'Street'
614
+ user.address.city = 'Some City'
615
+ user.address.state = 'GA'
616
+ user.address.zipcode = '30003'
617
+
618
+ user.alternate_address = Address.new
619
+ user.alternate_address.number = 37
620
+ user.alternate_address.street = 'Another Street'
621
+ user.alternate_address.city = 'Some Other City'
622
+ user.alternate_address.state = 'TX'
623
+ user.alternate_address.zipcode = '70004'
624
+ user.persist!
625
+
626
+ UserObject.persist( :username => 'user' ).should == user
627
+
628
+ user.alternate_address.number = 48
629
+
630
+ UserObject.persist( :username => 'user' ).should == user
631
+
632
+ end
633
+ end
634
+
635
+ it "can persist an object with hash members" do
636
+ module ::Persistence::Object::Complex::NestedHashesMock
637
+
638
+ class UserObject < ::Persistence::Object::Complex::UserObject
639
+ end
640
+
641
+ class HashContainerClass < ::Persistence::Object::Complex::HashContainerClass
642
+ end
643
+
644
+ class HashMock < ::Hash
645
+ end
646
+
647
+ hash_container = HashContainerClass.new
648
+ hash_container.storage_key = :hash_container
649
+ hash_container.some_hash = HashMock.new
650
+ hash_container.some_hash[ :hash_key ] = :hash_data
651
+
652
+ hash_container.persist!
653
+ HashContainerClass.persist( :storage_key => :hash_container ).should == hash_container
654
+
655
+ end
656
+ end
657
+
658
+ it "can persist an object with array members" do
659
+ module ::Persistence::Object::Complex::NestedArraysMock
660
+
661
+ class UserObject < ::Persistence::Object::Complex::UserObject
662
+ end
663
+
664
+ class ArrayContainerClass < ::Persistence::Object::Complex::ArrayContainerClass
665
+ end
666
+
667
+ class ArrayMock < ::Array
668
+ end
669
+
670
+ storage_key = :array_container
671
+ array_data = :array_data
672
+ array_container = ArrayContainerClass.new
673
+ array_container.storage_key = storage_key
674
+ array_container.array = ArrayMock.new
675
+ array_container.array.push( array_data )
676
+
677
+ array_container.persist!
678
+ ArrayContainerClass.persist( :storage_key => storage_key ).should == array_container
679
+
680
+ end
681
+ end
682
+
683
+ ##############
684
+ # persist! #
685
+ # persist #
686
+ ##############
687
+
688
+ it "can persist an object to and from a default bucket with an arbitrary key method" do
689
+ module ::Persistence::Object::Complex::PersistArbitraryKeyMethodMock
690
+
691
+ class UserObject < ::Persistence::Object::Complex::UserObject
692
+ end
693
+
694
+ user = UserObject.new
695
+ user.username = 'user'
696
+ user.firstname = 'first'
697
+ user.lastname = 'last'
698
+ user.persist!
699
+ persisted_user = UserObject.persist( user.persistence_id )
700
+ persisted_user.should == user
701
+ persisted_user_two = UserObject.new
702
+ persisted_user_two.persistence_id = persisted_user.persistence_id
703
+ persisted_user_two.persist
704
+ persisted_user_two.should == persisted_user
705
+ end
706
+
707
+ end
708
+
709
+ it "can persist an object to and from a default bucket with an arbitrary key variable" do
710
+ module ::Persistence::Object::Complex::PersistArbitraryKeyVariableMock
711
+
712
+ class UserObject < ::Persistence::Object::Complex::UserObject
713
+ end
714
+
715
+ user = UserObject.new
716
+ user.username = 'user'
717
+ user.firstname = 'first'
718
+ user.lastname = 'last'
719
+ user.persist!
720
+ UserObject.persist( user.persistence_id ).should == user
721
+ persisted_user_two = UserObject.new
722
+ persisted_user_two.persistence_id = user.persistence_id
723
+ persisted_user_two.persist
724
+ persisted_user_two.should == user
725
+
726
+ end
727
+ end
728
+
729
+ it "can persist an object with other objects as members" do
730
+ module ::Persistence::Object::Complex::PersistNestedObjectsMock
731
+
732
+ class UserObject < ::Persistence::Object::Complex::UserObject
733
+ attr_non_atomic_accessor :username, :firstname, :lastname, :address, :alternate_address
734
+ end
735
+
736
+ class Address < ::Persistence::Object::Complex::Address
737
+ attr_non_atomic_accessor :number, :street, :city, :state, :zipcode
738
+ end
739
+
740
+ user = UserObject.new
741
+ user.username = 'user'
742
+ user.firstname = 'first'
743
+ user.lastname = 'last'
744
+
745
+ user.address = Address.new
746
+ user.address.number = 42
747
+ user.address.street = 'Street'
748
+ user.address.city = 'Some City'
749
+ user.address.state = 'GA'
750
+ user.address.zipcode = '30003'
751
+
752
+ user.alternate_address = Address.new
753
+ user.alternate_address.number = 37
754
+ user.alternate_address.street = 'Another Street'
755
+ user.alternate_address.city = 'Some Other City'
756
+ user.alternate_address.state = 'TX'
757
+ user.alternate_address.zipcode = '70004'
758
+ user.persist!
759
+
760
+ # here we should be looking for:
761
+ # * username => 'user' => looks for 'user' with bucket (should find it and replace it)
762
+ # * address => should get ID from existing user if user exists => needs to check if existing user address is same ID
763
+ # * alternate_ddress => should also get ID from existing user if user exists => needs to check if existing alternate address is same ID
764
+
765
+ UserObject.persist( user.persistence_id ).should == user
766
+
767
+ user.alternate_address.number = 48
768
+
769
+ user.alternate_address.persist!
770
+
771
+ UserObject.persist( user.persistence_id ).should == user
772
+
773
+ end
774
+ end
775
+
776
+ it "can persist an object with other objects as members that have atomic properties" do
777
+ module ::Persistence::Object::Complex::PersistAtomicMock
778
+
779
+ class UserObject < ::Persistence::Object::Complex::UserObject
780
+ attr_non_atomic_accessor :username, :firstname, :lastname, :address, :alternate_address
781
+ end
782
+
783
+ class Address < ::Persistence::Object::Complex::Address
784
+ attr_non_atomic_accessor :number, :street, :city, :state, :zipcode
785
+ attr_atomic_accessor :number
786
+ attrs_atomic!
787
+ end
788
+
789
+ Address.atomic_attribute?( :number ).should == true
790
+
791
+ user = UserObject.new
792
+ user.username = 'user'
793
+ user.firstname = 'first'
794
+ user.lastname = 'last'
795
+
796
+ user.address = Address.new
797
+ user.address.number = 42
798
+ user.address.street = 'Street'
799
+ user.address.city = 'Some City'
800
+ user.address.state = 'GA'
801
+ user.address.zipcode = '30003'
802
+
803
+ user.alternate_address = Address.new
804
+ user.alternate_address.number = 37
805
+ user.alternate_address.street = 'Another Street'
806
+ user.alternate_address.city = 'Some Other City'
807
+ user.alternate_address.state = 'TX'
808
+ user.alternate_address.zipcode = '70004'
809
+ user.persist!
810
+
811
+ UserObject.persist( user.persistence_id ).should == user
812
+
813
+ user.alternate_address.number = 48
814
+
815
+ UserObject.persist( user.persistence_id ).should == user
816
+
817
+ end
818
+ end
819
+
820
+ it "can persist an object with hash members" do
821
+ module ::Persistence::Object::Complex::PersistNestedHashMembersMock
822
+
823
+ class HashContainerClass < ::Persistence::Object::Complex::HashContainerClass
824
+ attr_non_atomic_accessor :some_hash
825
+ end
826
+
827
+ class HashMock < ::Hash
828
+ include ::Persistence::Object::Complex::Hash
829
+ end
830
+
831
+ hash_container = HashContainerClass.new
832
+ hash_container.some_hash = HashMock.new
833
+ hash_container.some_hash[ :hash_key ] = :hash_data
834
+ hash_container.persist!
835
+ HashContainerClass.persist( hash_container.persistence_id ).should == hash_container
836
+
837
+ end
838
+ end
839
+
840
+ it "can persist an object with array members" do
841
+ module ::Persistence::Object::Complex::PersistNestedArrayMembersMock
842
+
843
+ class UserObject < ::Persistence::Object::Complex::UserObject
844
+ end
845
+
846
+ class ArrayContainerClass < ::Persistence::Object::Complex::ArrayContainerClass
847
+ attr_non_atomic_accessor :some_hash
848
+ end
849
+
850
+ class ArrayMock < ::Array
851
+ end
852
+
853
+ storage_key = :array_container
854
+ array_data = :array_data
855
+ array_container = ArrayContainerClass.new
856
+ array_container.storage_key = storage_key
857
+ array_container.array = ArrayMock.new
858
+ array_container.array.push( array_data )
859
+
860
+ array_container.persist!
861
+ ArrayContainerClass.persist( array_container.persistence_id ).should == array_container
862
+
863
+ end
864
+ end
865
+
866
+ ############
867
+ # cease! #
868
+ ############
869
+
870
+ it 'can delete an object' do
871
+ module ::Persistence::Object::Complex::CeaseObjectMock
872
+
873
+ class UserObject < ::Persistence::Object::Complex::UserObject
874
+ end
875
+
876
+ class MockObject
877
+ include ::Persistence
878
+ attr_non_atomic_accessor :some_value, :some_other_value
879
+ end
880
+ instance = MockObject.new
881
+ instance.some_value = :value
882
+ instance.some_other_value = :other_value
883
+ instance.persist!
884
+ copy = MockObject.persist( instance.persistence_id )
885
+ copy.should == instance
886
+ instance.cease!
887
+ MockObject.persist( instance.persistence_id ).should == nil
888
+
889
+ end
890
+ end
891
+
892
+ ######################
893
+ # persist! #
894
+ # index_attributes #
895
+ # persist #
896
+ ######################
897
+
898
+ it 'indexes attributes during persist' do
899
+ module ::Persistence::Object::Complex::PersistAndIndexAttributesMock
900
+
901
+ class UserObject < ::Persistence::Object::Complex::UserObject
902
+ end
903
+
904
+ class MockObject
905
+ include ::Persistence
906
+ attr_non_atomic_accessor :attribute_index
907
+ attr_index :attribute_index
908
+ end
909
+ instance = MockObject.new
910
+ instance.attribute_index = :some_value
911
+ # should call index_attributes
912
+ instance.persist!
913
+ instance_copy = MockObject.persist( :attribute_index, :some_value )
914
+ instance_copy.should == instance
915
+ instance_copy_two = MockObject.new
916
+ instance_copy_two.persist( :attribute_index, :some_value )
917
+ instance_copy_two.should == instance
918
+
919
+ end
920
+ end
921
+
922
+ end